前几天统计一个sql,是一个人提交了多少工单,顺便做了相关sql优化。数据大概2000多w。

select  CustName,count(1) c from WorkOrder  where CreateDate>'2016-5-1' and CreateDate<'2017-1-1'
group by CustName having c>100
order by c desc;

  为了实验最少受其他因素干扰,将生产库的200多w数据导出来,用测试服务器进行测试。

  导出来的数据是一个堆表,没有主键,没有索引。

mysql> show index from WorkOrder;   查询index方法1
Empty set (0.00 sec) mysql> show keys from WorkOrder; 查询index方法2
Empty set (0.00 sec)

 1.堆表的情况

 这时候就在这时候,用执行计划分析下语句。

 
mysql>  explain select  CustName,count(1) c from WorkOrder
where CreateDate>'2016-5-1' and CreateDate<'2017-1-1' group by CustName having c>100 order by c desc;
+----+-------------+-----------+------+---------------+------+---------+------+---------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+------+---------+------+---------+----------------------------------------------+
| 1 | SIMPLE | WorkOrder | ALL | NULL | NULL | NULL | NULL | 2528727 | Using where; Using temporary; Using filesort |
+----+-------------+-----------+------+---------------+------+---------+------+---------+----------------------------------------------+
1 row in set
 

  select_type的值为SIMPLE,表示简单的select查询,不使用union或子查询。

  type的值为ALL,表示要对表进行表扫描。

  possible_keys 表示能使用哪个索引找到行记录。

  key 表示Mysql决定使用的索引(键)。

key_len 表示Mysql决定使用索引的长度。

  ref  表示使用哪个列和key一起从表中选择行。

  rows 表示Mysql认为它执行查询时必须检查的行数。

  extra 表示查询的详情信息,用到where,临时表,排序。

  

  执行下该语句三次,发现执行了16.30 sec、16.34 sec、16.24 sec。

 2.有索引的情况

  建了四个索引,分别以custname,CreateDate建两个单列索引,另外两个是联合索引,只是最左边列不一样。

alter table WorkOrder add index ix_name(custname)
alter table WorkOrder add index ix_date(CreateDate)
alter table WorkOrder add index ix_namedate(custname,CreateDate)
alter table WorkOrder add index ix_datename(CreateDate,custname)
 
mysql> show keys from WorkOrder;
+-----------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| WorkOrder | 1 | ix_name | 1 | CustName | A | 1264363 | NULL | NULL | YES | BTREE | | |
| WorkOrder | 1 | ix_date | 1 | CreateDate | A | 2528727 | NULL | NULL | | BTREE | | |
| WorkOrder | 1 | ix_namedate | 1 | CustName | A | 1264363 | NULL | NULL | YES | BTREE | | |
| WorkOrder | 1 | ix_namedate | 2 | CreateDate | A | 2528727 | NULL | NULL | | BTREE | | |
| WorkOrder | 1 | ix_datename | 1 | CreateDate | A | 2528727 | NULL | NULL | | BTREE | | |
| WorkOrder | 1 | ix_datename | 2 | CustName | A | 2528727 | NULL | NULL | YES | BTREE | | |
+-----------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
6 rows in set (0.00 sec)
 

  之后,用执行计划分析下sql查询语句。

 
mysql> explain select  CustName,count(1) c from WorkOrder
where CreateDate>'2016-5-1' and CreateDate<'2017-1-1' group by CustName having c>100 order by c desc;
+----+-------------+-----------+-------+-----------------------------------------+-------------+---------+------+--------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+-----------------------------------------+-------------+---------+------+--------+-----------------------------------------------------------+
| 1 | SIMPLE | WorkOrder | range | ix_name,ix_date,ix_namedate,ix_datename | ix_datename | 4 | NULL | 824372 | Using where; Using index; Using temporary; Using filesort |
+----+-------------+-----------+-------+-----------------------------------------+-------------+---------+------+--------+-----------------------------------------------------------+
1 row in set (0.01 sec)
 

  从执行计划可以看出,Mysql从四个索引中选取了ix_datename这个索引,type为range表示索引范围扫描。rows的数量值是没堆表的1/3。

  执行语句三次,时间是 8.64 sec、8.61sec、8.55 sec。

我建了三个索引,那么我想用下另外三个索引怎么办?

  这里可以用force index(),这个指令可以指定本次查询强制使用哪个索引,因为Mysql优化器的选择并不是最优的索引。

 
mysql> explain select  CustName,count(1) c from WorkOrder force index(ix_namedate) 
where CreateDate>'2016-5-1' and CreateDate<'2017-1-1' group by CustName having c>100 order by c desc;
+----+-------------+-----------+-------+---------------------------------+-------------+---------+------+---------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------------------------+-------------+---------+------+---------+-----------------------------------------------------------+
| 1 | SIMPLE | WorkOrder | index | ix_name,ix_namedate,ix_datename | ix_namedate | 307 | NULL | 2528727 | Using where; Using index; Using temporary; Using filesort |
+----+-------------+-----------+-------+---------------------------------+-------------+---------+------+---------+-----------------------------------------------------------+
 

    选用另一个联合索引 ix_namedate,这次type变为index,可以这样理解,根据索引的顺序进行全表扫描,比ALL效率要高些,rows的值和堆表的值差不多。

    执行语句三次,时间是 7.84 sec、7.92 sec、7.84 sec。

 
mysql> explain select  CustName,count(1) c from WorkOrder force index(ix_name)
where CreateDate>'2016-5-1' and CreateDate<'2017-1-1' group by CustName having c>100 order by c desc;
+----+-------------+-----------+-------+---------------------------------+---------+---------+------+---------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------------------------+---------+---------+------+---------+----------------------------------------------+
| 1 | SIMPLE | WorkOrder | index | ix_name,ix_namedate,ix_datename | ix_name | 303 | NULL | 2528727 | Using where; Using temporary; Using filesort |
+----+-------------+-----------+-------+---------------------------------+---------+---------+------+---------+----------------------------------------------+
1 row in set
 

  

  选用另一个联合索引 ix_name,这次type是index,可以这样理解,根据索引的顺序进行全表扫描,比ALL效率要高些,rows的值和堆表的值差不多。

    执行语句三次,时间是 1 min 28.17 sec、1 min 27.64 sec、1 min 27.58 sec。

 
mysql> explain select  CustName,count(1) c from WorkOrder force index(ix_date)
where CreateDate>'2016-5-1' and CreateDate<'2017-1-1' group by CustName having c>100 order by c desc;
+----+-------------+-----------+-------+-----------------------------------------+---------+---------+------+--------+-------------------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+-----------------------------------------+---------+---------+------+--------+-------------------------------------------------------------------+
| 1 | SIMPLE | WorkOrder | range | ix_name,ix_date,ix_namedate,ix_datename | ix_date | 4 | NULL | 921062 | Using index condition; Using MRR; Using temporary; Using filesort |
+----+-------------+-----------+-------+-----------------------------------------+---------+---------+------+--------+-------------------------------------------------------------------+
 

  选用另一个联合索引 ix_date,这次type是range,表示索引范围扫描,rows的值是堆表的1/3多些 。

    执行语句三次,时间是 9.55 sec、9.52 sec、9.39 sec。

假如我不想用索引了怎么办?

  可以使用ignore index(),这个指令可以强制Mysql在查询时,不使用某索引。

  

 
mysql> explain select  CustName,count(1) c from WorkOrder  ignore index(ix_date)
where CreateDate>'2016-5-1' and CreateDate<'2017-1-1' group by CustName having c>100 order by c desc;
+----+-------------+-----------+-------+---------------------------------+-------------+---------+------+--------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------------------------+-------------+---------+------+--------+-----------------------------------------------------------+
| 1 | SIMPLE | WorkOrder | range | ix_name,ix_namedate,ix_datename | ix_datename | 4 | NULL | 824372 | Using where; Using index; Using temporary; Using filesort |
+----+-------------+-----------+-------+---------------------------------+-------------+---------+------+--------+-----------------------------------------------------------+ mysql> explain select CustName,count(1) c from WorkOrder ignore index(ix_date,ix_name,ix_namedate,ix_datename)
where CreateDate>'2016-5-1' and CreateDate<'2017-1-1' group by CustName having c>100 order by c desc;
+----+-------------+-----------+------+---------------------------------+------+---------+------+---------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------------------------+------+---------+------+---------+----------------------------------------------+
| 1 | SIMPLE | WorkOrder | ALL | ix_name,ix_namedate,ix_datename | NULL | NULL | NULL | 2528727 | Using where; Using temporary; Using filesort |
+----+-------------+-----------+------+---------------------------------+------+---------+------+---------+----------------------------------------------+
 

  上面第一个强制不使用ix_date索引,那么就Mysql就从剩下的三个索引中,选取他认为是最优的索引。第二个时将四个索引都不使用,那么Mysql就进行全表扫描了。

  总结:

      1.Mysql的语句优化,没有绝对的正确,explain也只是给出个大致的方向,例如 key_len值小的,rows小的按理说,时间应该最短,效率最高。但是,实验中时间最少的却不是那个值最小的。

       2. 优化还需根据实际数据情况,例如,假如我where选取的时间范围变化,或者说CustName的分布有些变化,可能跟刚才的实验,又会产生一定偏差。

       3. 同样我还实验了,当给表加上主键时,整体的查询时间会缩短些。

------------------附相关index命令--------------

 
删除主键

ALTER TABLE WorkOrder MODIFY id int(11); --1.先删除auto_increment
ALTER TABLE  WorkOrder  DROP PRIMARY KEY;  --2.再删除主键

ALTER TABLE WorkOrder DROP index ix_datename;--删除索引
 

参考:mysql如何添加主键约束和唯一性约束,删除主键和唯一性约束

   mysql强制使用索引与不使用索引

   利用 force index优化sql语句性能

     mysql 存在索引但不能使用索引的典型场景

     mysql explain用法和结果的含义

     MySQL 优化之 index merge(索引合并)

     MySQL单列索引和组合索引(联合索引)的区别详解

Mysql force index和ignore index 使用实例的更多相关文章

  1. Mysql中的force index和ignore index

    前几天统计一个sql,是一个人提交了多少工单,顺便做了相关sql优化.数据大概2000多w. ) c order by c desc; 为了实验最少受其他因素干扰,将生产库的200多w数据导出来,用测 ...

  2. MySQL force Index 强制索引概述

    以下的文章主要介绍的是MySQL force Index  强制索引,以及其他的强制操作,其优先操作的具体操作步骤如下:我们以MySQL中常用的hint来进行详细的解析,如果你是经常使用Oracle的 ...

  3. 【转】mysql force Index 强制索引

    其他强制操作,优先操作如下: mysql常用的hint 对于经常使用oracle的朋友可能知道,oracle的hint功能种类很多,对于优化sql语句提供了很多方法.同样,在mysql里,也有类似的h ...

  4. mysql force index() 强制索引的使用

    mysql force index() 强制索引的使用 之前跑了一个SQL,由于其中一个表的数据量比较大,而在条件中有破坏索引或使用了很多其他索引,就会使得sql跑的非常慢... 那我们怎么解决呢? ...

  5. mysql index hint 在index不存在时的处理

    关于index_hint 在mysql查询语句中可以通过指定index_hint来告诉优化器如何使用索引,详细可以参考这里 index_hint: USE {INDEX|KEY} [FOR {JOIN ...

  6. MySQL中的索引提示Index Hint

    MySQL数据库支持索引提示(INDEX HINT)显式的高速优化器使用了哪个索引.以下是可能需要用到INDEX HINT的情况 a)MySQL数据库的优化器错误的选择了某个索引,导致SQL运行很慢. ...

  7. 1229【MySQL】性能优化之 Index Condition Pushdown

    转自http://blog.itpub.net/22664653/viewspace-1210844/  [MySQL]性能优化之 Index Condition Pushdown2014-07-06 ...

  8. MySQL 执行计划中Extra(Using where,Using index,Using index condition,Using index,Using where)的浅析

      关于如何理解MySQL执行计划中Extra列的Using where.Using Index.Using index condition,Using index,Using where这四者的区别 ...

  9. 在MYSQL中运用全文索引(FULLTEXT index)

    在MYSQL中使用全文索引(FULLTEXT index) MYSQL的一个很有用的特性是使用全文索引(FULLTEXT index)查找文本的能力.目前只有使用MyISAM类型表的时候有效(MyIS ...

随机推荐

  1. sql select 1 和 exists

    SELECT * FROM LACOMMISION WHERE MANAGECOM LIKE'8694%' AND STATE='1' AND EXISTS(SELECT 1 FROM laagent ...

  2. Moonraker靶机

    仅供个人娱乐 靶机搭建与下载 Monraker靶机ip: 192.168.181.135 kali攻击者ip : 192.168.181.128 说明:获取目标主机的root权限并读取目录中的flag ...

  3. 租了一台华为云耀云服务器,却直接被封公网ip,而且是官方的bug导致!

    小弟在博客园也有十多个年头了,因为离开了.net圈子,所以很少发文,今天可算是被华为云气疯了.写下这篇文章,大家也要注意自查一下,避免无端端被封公网ip. 因为小弟创业公司业务发展,需要一个公网做宣传 ...

  4. 安卓安装https证书

    前置条件 1 手机要设置密码 然后安装charles 证书 2 赋予 adb shell root权限(安装magisk就行) adb shell # 连接手机进入shell模式 su root # ...

  5. netty系列之:中国加油

    目录 简介 场景规划 启动Server 启动客户端 消息处理 消息处理中的陷阱 总结 简介 之前的系列文章中我们学到了netty的基本结构和工作原理,各位小伙伴一定按捺不住心中的喜悦,想要开始手写代码 ...

  6. 靶机Cyberry

    工具 hydra.crunch.dirbuster 涉及到的点 Port knocking(端口试探) Brainfuck编码 ftp爆破 ssh爆破 openssl enc加密 命令执行漏洞 Lin ...

  7. i春秋CTF-web-upload

    ------------恢复内容开始------------ 记一道文件上传的题目. 题目告诉我们随意上传,第一想到的当然给他上传一个木马文件然后蚁剑拿shell,上传之后可以在源码里查看我们上传的文 ...

  8. 多次面试被拒,‘宅家苦修’30天,终获美团offer(含字节跳动/阿里/腾讯等大厂面试题整理)

    背景:双非渣本. 今年由于疫情,上半年一直在家里.2月份本来无忧无虑,呆在家里不给国家添乱的时候,发现身边的同学找到了大厂的offer.心里开始有点慌张.本来想在3月份如果能回到学校,就开始考研之路, ...

  9. JavaGUI三种布局管理器FlowLayout,BorderLayout,GridLayout的使用

    三种布局管理器 流式布局FlowLayout package GUI; import java.awt.*; import java.awt.event.WindowAdapter; import j ...

  10. POI解析excel,将批量数据写入文件或数据库

    .personSunflowerP { background: rgba(51, 153, 0, 0.66); border-bottom: 1px solid rgba(0, 102, 0, 1); ...