前几天统计一个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. select CustName,count(1) c from WorkOrder where Creat ...

  2. MySQL 中 key, primary key ,unique key,index的区别

    一.key与primary key区别 CREATE TABLE wh_logrecord ( logrecord_id int(11) NOT NULL auto_increment, user_n ...

  3. 如何检查mysql中建立的索引是否生效的检测方法及相关参数说明

    所使用的mysql函数explain语法:explain < table_name >例如: explain select * from t3 where id=3952602;expla ...

  4. 详解 MySQL 中的 explain

    来源:persister 链接:http://www.blogjava.net/persister/archive/2008/10/27/236813.html 在 explain的帮助下,您就知道什 ...

  5. mysql中key 、primary key 、unique key 与index区别

    一.key与primary key区别 CREATE TABLE wh_logrecord ( logrecord_id ) NOT NULL auto_increment, ) default NU ...

  6. Mysql中Key与Index的区别

    mysql的key和index多少有点令人迷惑,这实际上考察对数据库体系结构的了解的. 1 key 是数据库的物理结构,它包含两层意义,一是约束(偏重于约束和规范数据库的结构完整性),二是索引(辅助查 ...

  7. 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这四者的区别 ...

  8. MySQL中KEY、PRIMARY KEY、UNIQUE KEY、INDEX 的区别

    参考:MySQL中KEY.PRIMARY KEY.UNIQUE KEY.INDEX 的区别 对于题目中提出的问题,可以拆分来一步步解决.在 MySQL 中 KEY 和 INDEX 是同义.那这个问题就 ...

  9. MysqL中的Show Index From Table_Name命令说明

    我们在分析SQL性能的时候,会使用到show index from table_name命令,会返回出下面的列 | Table | Non_unique | Key_name | Seq_in_ind ...

随机推荐

  1. Mongodb集群【三】

    Mongodb常用三种集群 1 主从(Master/Slave) 不推荐,但是mongodb依然保留有.一主多从,不支持链式结构.简单主从,没有裁仲者不能自动恢复. 2 副本集(Relica Set) ...

  2. IOS10.3上传照片只能拍照不能选择解决办法

    升级IOS10.3正式版以后可能会出现上传文件的控件只能拍照而不能选择现有图片的问题. 正好被我们碰到了,于是找了找解决思路,发现如下解决思路: 原代码为: <input type=" ...

  3. vagrant快速搭建LNMP环境并且打包带走留着以后用

    不多说废话,全文文字,照着输就没问题 vagrant下载 可以到VirtualBox的官网进行下载:  https://www.virtualbox.org/wiki/Downloads vagran ...

  4. 数据结构-堆(应用篇)之堆排序法-C和C++的实现

    堆排序 关于堆的内容我们已经在上一节中了解了,本节中将给出一个堆的应用-堆排序. 关于堆的概念可以看上一节,入口:http://www.cnblogs.com/HongYi-Liang/p/78536 ...

  5. Linux audio驱动模型

    linux驱动 alsa模型: Linux ALSA声卡驱动之一:ALSA架构简介 Linux ALSA声卡驱动之二:声卡的创建 Linux ALSA声卡驱动之三:PCM设备的创建 Linux ALS ...

  6. JavaScript基础知识(概念、常量和变量)

    1.JavaScript概念 JavaScript是脚本语言; 编写之后,可以直接运行(缺失了编译的过程) 2.JavaScript发展 LiveScript    =>    JavaScri ...

  7. Elastic Stack之kibana入门

    为了解决公司的项目在集群环境下查找日志不便的问题,我在做过简单调研后,选用Elastic公司的Elastic Stack产品作为我们的日志收集,存储,分析工具. Elastic Stack是ELK(E ...

  8. Maven工程搭建spring boot+spring mvc+JPA

    添加Spring boot支持,引入相关包: 1.maven工程,少不了pom.xml,spring boot的引入可参考官网: <parent> <groupId>org.s ...

  9. 使用python写天气预告

    先去YY天气注册一个账号,然后就能用API了 http://www.yytianqi.com/ # encoding=utf-8import urllib.requestimport jsonimpo ...

  10. [bzoj3287] Mato的刷屏计划

    第一眼以为是傻逼斜率优化>_< f[i]表示按i次最多可输出字符数..f[i]=max{ f[i-1]+1,(i-j-1)*f[j] },j<i-2 结果n在100+的时候就喜闻乐见 ...