MYSQL的全表扫描,主键索引(聚集索引、第一索引),非主键索引(非聚集索引、第二索引),覆盖索引四种不同查询的分析...

文章出处:http://inter12.iteye.com/blog/1430144

MYSQL的全表扫描,主键索引(聚集索引、第一索引),非主键索引(非聚集索引、第二索引),覆盖索引四种不同查询的分析

 

1.前置条件:

本次是基于小数据量,且数据块在一个页中的最理想情况进行分析,可能无具体的实际意义,但是可以借鉴到各种复杂条件下,因为原理是相同的,知小见大,见微知著!

 

打开语句分析并确认是否已经打开

 

Java代码  收藏代码
  1. mysql> set profiling=1;     
  2. Query OK, 0 rows affected (0.00 sec)  
  3.   
  4. mysql> select @@profiling;  
  5. +-------------+  
  6. | @@profiling |  
  7. +-------------+  
  8. |           1 |  
  9. +-------------+  
  10. 1 row in set (0.01 sec)  

 

2.数据准备:

2.1全表扫描数据

 

Java代码  收藏代码
  1. create table person4all(id int not null  auto_increment, name varchar(30) not null, gender varchar(10) not null ,primary key(id));  
  2. insert into person4all(name,gender) values("zhaoming","male");  
  3. insert into person4all(name,gender) values("wenwen","female");  

 

2.2根据主键查看数据

 

Java代码  收藏代码
  1. create table person4pri(id int not null  auto_increment, name varchar(30) not null, gender varchar(10) not null ,primary key(id));  
  2. insert into person4pri(name,gender) values("zhaoming","male");  
  3. insert into person4pri(name,gender) values("wenwen","female");  

 

2.3根据非聚集索引查数据

 

Java代码  收藏代码
  1. create table person4index(id int not null  auto_increment, name varchar(30) not null, gender varchar(10) not null ,primary key(id) , index(gender));  
  2. insert into person4index(name,gender) values("zhaoming","male");  
  3. insert into person4index(name,gender) values("wenwen","female");  

 

2.4根据覆盖索引查数据

 

Java代码  收藏代码
  1. create table person4cindex(id int not null  auto_increment, name varchar(30) not null, gender varchar(10) not null ,primary key(id) , index(name,gender));  
  2. insert into person4cindex(name,gender) values("zhaoming","male");  
  3. insert into person4cindex(name,gender) values("wenwen","female");  

 

主要从以下几个方面分析:查询消耗的时间,走的执行计划等方面。

 

3.开工测试:

第一步:全表扫描

 

Java代码  收藏代码
  1. mysql> select * from person4all ;  
  2. +----+----------+--------+  
  3. | id | name     | gender |  
  4. +----+----------+--------+  
  5. |  1 | zhaoming | male   |  
  6. |  2 | wenwen   | female |  
  7. +----+----------+--------+  
  8. 2 rows in set (0.00 sec)  

 

查看其执行计划:

 

Java代码  收藏代码
  1. mysql> explain select * from person4all;  
  2. +----+-------------+------------+------+---------------+------+---------+------+------+-------+  
  3. | id | select_type | table      | type | possible_keys | key  | key_len | ref  | rows | Extra |  
  4. +----+-------------+------------+------+---------------+------+---------+------+------+-------+  
  5. |  1 | SIMPLE      | person4all | ALL  | NULL          | NULL | NULL    | NULL |    2 |       |  
  6. +----+-------------+------------+------+---------------+------+---------+------+------+-------+  
  7. 1 row in set (0.01 sec)  

 

我们可以很清晰的看到走的是全表扫描,而没有走索引!

 

查询消耗的时间:

 

Java代码  收藏代码
  1. mysql> show profiles;  
  2. +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------+  
  3. | Query_ID | Duration   | Query                                                                                                                             |  
  4. |       54 | 0.00177300 | select * from person4all                                                                                                          |  
  5. |       55 | 0.00069200 | explain select * from person4all                                                                                                  |  
  6. +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------+  

 

全表扫描总共话了0.0017730秒

 

各个阶段消耗的时间是:

 

Java代码  收藏代码
  1. mysql> show profile for query 54;  
  2. +--------------------------------+----------+  
  3. | Status                         | Duration |  
  4. +--------------------------------+----------+  
  5. | starting                       | 0.000065 |  
  6. | checking query cache for query | 0.000073 |  
  7. | Opening tables                 | 0.000037 |  
  8. | System lock                    | 0.000024 |  
  9. | Table lock                     | 0.000053 |  
  10. | init                           | 0.000044 |  
  11. | optimizing                     | 0.000022 |  
  12. | statistics                     | 0.000032 |  
  13. | preparing                      | 0.000030 |  
  14. | executing                      | 0.000020 |  
  15. | Sending data                   | 0.001074 |  
  16. | end                            | 0.000091 |  
  17. | query end                      | 0.000020 |  
  18. | freeing items                  | 0.000103 |  
  19. | storing result in query cache  | 0.000046 |  
  20. | logging slow query             | 0.000019 |  
  21. | cleaning up                    | 0.000020 |  
  22. +--------------------------------+----------+  
  23. 17 rows in set (0.00 sec)  

 

第一次不走缓存的话,需要检查是否存在缓存中,打开表,初始化等操作,最大的开销在于返回数据。

 

第二步:根据主键查询数据。

 

Java代码  收藏代码
  1. mysql> select name ,gender from person4pri where id in (1,2);  
  2. +----------+--------+  
  3. | name     | gender |  
  4. +----------+--------+  
  5. | zhaoming | male   |  
  6. | wenwen   | female |  
  7. +----------+--------+  
  8. 2 rows in set (0.01 sec)  

 

查看其执行计划:

 

Java代码  收藏代码
  1. mysql> explain select name ,gender from person4pri where id in (1,2);  
  2. +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+  
  3. | id | select_type | table      | type  | possible_keys | key     | key_len | ref  | rows | Extra       |  
  4. +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+  
  5. |  1 | SIMPLE      | person4pri | range | PRIMARY       | PRIMARY | 4       | NULL |    2 | Using where |  
  6. +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+  
  7. 1 row in set (0.00 sec)  

 

从执行计划中我们可以看出,走的是范围索引。

 

再看其执行消耗的时间:

 

Java代码  收藏代码
  1. mysql> show profiles;  
  2. +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------+  
  3. | Query_ID | Duration   | Query                                                                                                                             |  
  4. +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------+  
  5. |       63 | 0.00135700 | select name ,gender from person4pri where id in (1,2)                                                                             |  
  6. |       64 | 0.00079200 | explain select name ,gender from person4pri where id in (1,2)                                                                     |  
  7. +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------+  
  8. 15 rows in set (0.01 sec)  

 

这次查询消耗时间为0.00079200。

 

查看各个阶段消耗的时间:

 

Java代码  收藏代码
  1. mysql> show profile for query 63;  
  2. +--------------------------------+----------+  
  3. | Status                         | Duration |  
  4. +--------------------------------+----------+  
  5. | starting                       | 0.000067 |  
  6. | checking query cache for query | 0.000146 |  
  7. | Opening tables                 | 0.000342 |  
  8. | System lock                    | 0.000027 |  
  9. | Table lock                     | 0.000115 |  
  10. | init                           | 0.000056 |  
  11. | optimizing                     | 0.000032 |  
  12. | statistics                     | 0.000069 |  
  13. | preparing                      | 0.000039 |  
  14. | executing                      | 0.000022 |  
  15. | Sending data                   | 0.000100 |  
  16. | end                            | 0.000075 |  
  17. | query end                      | 0.000022 |  
  18. | freeing items                  | 0.000158 |  
  19. | storing result in query cache  | 0.000045 |  
  20. | logging slow query             | 0.000019 |  
  21. | cleaning up                    | 0.000023 |  
  22. +--------------------------------+----------+  
  23. 17 rows in set (0.00 sec)  

 

看出最大的消耗也是在Sending data,第一次也是需要一些初始化操作。

 

第三步:根据非聚集索引查询

 

Java代码  收藏代码
  1. mysql> select name ,gender from person4index where gender in ("male","female");  
  2. +----------+--------+  
  3. | name     | gender |  
  4. +----------+--------+  
  5. | wenwen   | female |  
  6. | zhaoming | male   |  
  7. +----------+--------+  
  8. 2 rows in set (0.00 sec)  

查看器执行计划:

 

Java代码  收藏代码
  1. mysql> explain select name ,gender from person4index where gender in ("male","female");  
  2. +----+-------------+--------------+-------+---------------+--------+---------+------+------+-------------+  
  3. | id | select_type | table        | type  | possible_keys | key    | key_len | ref  | rows | Extra       |  
  4. +----+-------------+--------------+-------+---------------+--------+---------+------+------+-------------+  
  5. |  1 | SIMPLE      | person4index | range | gender        | gender | 12      | NULL |    2 | Using where |  
  6. +----+-------------+--------------+-------+---------------+--------+---------+------+------+-------------+  
  7. 1 row in set (0.00 sec)  

 

可以看出,走的也是范围索引。同主键查询,那么就看其消耗时间了

 

Java代码  收藏代码
  1. mysql> show profiles;  
  2. +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------+  
  3. | Query_ID | Duration   | Query                                                                                                                                               |  
  4. +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------+  
  5. |       68 | 0.00106600 | select name ,gender from person4index where gender in ("male","female")                                                                             |  
  6. |       69 | 0.00092500 | explain select name ,gender from person4index where gender in ("male","female")                                                                     |  
  7. +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------+  
  8. 15 rows in set (0.00 sec)  

 

这个非主键索引消耗的时间为:0.00106600,可以看出略大于组件索引消耗的时间。

 

看其具体消耗的阶段:

 

Java代码  收藏代码
  1. mysql> show profile for query 68 ;  
  2. +--------------------------------+----------+  
  3. | Status                         | Duration |  
  4. +--------------------------------+----------+  
  5. | starting                       | 0.000059 |  
  6. | checking query cache for query | 0.000111 |  
  7. | Opening tables                 | 0.000085 |  
  8. | System lock                    | 0.000023 |  
  9. | Table lock                     | 0.000067 |  
  10. | init                           | 0.000183 |  
  11. | optimizing                     | 0.000031 |  
  12. | statistics                     | 0.000139 |  
  13. | preparing                      | 0.000035 |  
  14. | executing                      | 0.000020 |  
  15. | Sending data                   | 0.000148 |  
  16. | end                            | 0.000024 |  
  17. | query end                      | 0.000019 |  
  18. | freeing items                  | 0.000043 |  
  19. | storing result in query cache  | 0.000042 |  
  20. | logging slow query             | 0.000017 |  
  21. | cleaning up                    | 0.000020 |  
  22. +--------------------------------+----------+  
  23. 17 rows in set (0.00 sec)  

 

看几个关键词的点;init,statistics,Sending data 这几个关键点上的消耗向比较主键的查询要大很多,特别是Sending data。因为若是走的非聚集索引,那么就需要回表进行再进行一次查询,多消耗一次IO。

 

第四部:根据覆盖索引查询数据

 

Java代码  收藏代码
  1. mysql> select gender ,name from person4cindex where gender in ("male","female");  
  2. +--------+----------+  
  3. | gender | name     |  
  4. +--------+----------+  
  5. | female | wenwen   |  
  6. | male   | zhaoming |  
  7. +--------+----------+  
  8. 2 rows in set (0.01 sec)  

 

这里需要注意的是,我的字段查询顺序变了,是gender,name而不在是前面的name,gender,这样是为了走覆盖索引。具体看效果吧

 

还是先看执行计划:

 

Java代码  收藏代码
  1. mysql> explain select gender ,name from person4cindex where gender in ("male","female");  
  2. +----+-------------+---------------+-------+---------------+------+---------+------+------+--------------------------+  
  3. | id | select_type | table         | type  | possible_keys | key  | key_len | ref  | rows | Extra                    |  
  4. +----+-------------+---------------+-------+---------------+------+---------+------+------+--------------------------+  
  5. |  1 | SIMPLE      | person4cindex | index | NULL          | name | 44      | NULL |    2 | Using where; Using index |  
  6. +----+-------------+---------------+-------+---------------+------+---------+------+------+--------------------------+  
  7. 1 row in set (0.00 sec)  

 

最后栏Extra中表示走的就是覆盖索引。

 

看消耗的时间吧:

 

Java代码  收藏代码
  1. mysql> show profiles;  
  2. +----------+------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+  
  3. | Query_ID | Duration   | Query                                                                                                                                                            |  
  4. +----------+------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+  
  5. |       83 | 0.00115400 | select gender ,name from person4cindex where gender in ("male","female")                                                                                         |  
  6. |       84 | 0.00074000 | explain select gender ,name from person4cindex where gender in ("male","female")                                                                                 |  
  7. +----------+------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+  

 

我们看到消耗的时间是0.00115400,看这个数字好像挺高的,那么都花在什么地方了呢?

 

看下具体的消耗情况:

 

Sql代码  收藏代码
  1. mysql> show profile for query 83 ;  
  2. +--------------------------------+----------+  
  3. | Status                         | Duration |  
  4. +--------------------------------+----------+  
  5. | starting                       | 0.000083 |  
  6. | checking query cache for query | 0.000113 |  
  7. | Opening tables                 | 0.000039 |  
  8. | System lock                    | 0.000026 |  
  9. | Table lock                     | 0.000075 |  
  10. | init                           | 0.000128 |  
  11. | optimizing                     | 0.000193 |  
  12. | statistics                     | 0.000056 |  
  13. | preparing                      | 0.000038 |  
  14. | executing                      | 0.000021 |  
  15. | Sending data                   | 0.000121 |  
  16. | end                            | 0.000042 |  
  17. | query end                      | 0.000021 |  
  18. | freeing items                  | 0.000112 |  
  19. | storing result in query cache  | 0.000043 |  
  20. | logging slow query             | 0.000021 |  
  21. | cleaning up                    | 0.000022 |  
  22. +--------------------------------+----------+  
  23. 17 rows in set (0.00 sec)  

 

很惊奇吧,在初始化和优化上消耗了这么多时间,取数据基恩差不多。

 

总结:

    有了上面这些数据,那么我们整理下吧。未存在缓存下的数据。

 

看这个表,全表扫描最慢,我们可以理解,同时主键查询比覆盖所有扫描慢也还能接受,但是为什么主键扫描会比非主键扫描慢?而且非主键查询需要消耗的1次查询的io+一次回表的查询IO,理论上是要比主键扫描慢,而出来的数据缺不是如此。那么就仔细看下是个查询方式在各个主要阶段消耗的时间吧。

查询是否存在缓存,打开表及锁表这些操作时间是差不多,我们不会计入。具体还是看init,optimizing等环节消耗的时间。

 

 

1.从这个表中,我们看到非主键索引和覆盖索引在准备时间上需要开销很多的时间,预估这两种查询方式都需要进行回表操作,所以花在准备上更多时间。

2.第二项optimizing上,可以清晰知道,覆盖索引话在优化上大量的时间,这样在二级索引上就无需回表。

3. Sendingdata,全表扫描慢就慢在这一项上,因为是加载所有的数据页,所以花费在这块上时间较大,其他三者都差不多。

4. 非主键查询话在freeingitems上时间最少,那么可以看出它在读取数据块的时候最少。

5.相比较主键查询和非主键查询,非主键查询在Init,statistics都远高于主键查询,只是在freeingitems开销时间比主键查询少。因为这里测试数据比较少,但是我们可以预见在大数据量的查询上,不走缓存的话,那么主键查询的速度是要快于非主键查询的,本次数据不过是太小体现不出差距而已。

6.在大多数情况下,全表扫描还是要慢于索引扫描的。

 

 

tips:

过程中的辅助命令:

1.清楚缓存

reset query cache ;

flush tables;

 

2.查看表的索引:

show index from tablename;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/262024.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

控件(View)之TextSwitcher, Gallery, ImageSwitcher, GridView, ListView, ExpandableList【转】

在 Android 中使用各种控件(View) TextSwitcher - 文字转换器控件(改变文字时增加一些动画效果)Gallery - 缩略图浏览器控件ImageSwitcher - 图片转换器控件(改变图片时增加一些动画效果)GridView - 网格控件ListView - 列表控件E…

linux下php反编译apk,php反编译

Host IP:运行APP的Host侧IP地址。 Compile Path:推理场景为ATC的执行路径,训练场景为脚本执行路径。用于存储算子编译中间生成的输出件和pbtxt,一般为“kernel_meta”文件的父路径(例如:~/model_convert)。 图1 参数配…

13 对话一 【96】

13 对话一 【96】 This line is taking forever! It sure is. But lunch hour is the busiest time of day. That’s true. Especially at the end of the month. Mm-hmm. You know, you look really familiar. Don’t I know you from somewhere? I’m not sure. I think we…

程序员狂想曲

【前序】博客园首页对博文的规定有:原创精品、排版整齐、有足够的篇幅、与程序员相关、能够让读者从中学到知识的基本要求。我心想,除非不同时空,否则这绝对是我原创的;段落分明排版自然问题不大;一千三百来字的文章远…

python异常处理的语法格式_Python异常处理

Python异常处理 一. 异常的概念 程序在运行时,如果 Python 解释器 遇到 到一个错误,会停止程序的执行,并且提示一些错误信息,这就是 异常。 程序停止执行并且提示错误信息 这个动作,我们通常称之为:抛出(ra…

Cheatsheet: 2010 04.26 ~ 04.30

Web Telling robots about your crawl-able Ajax apps Scrollin’ Scrollin’ Scrollin’ to the NextPoint The Big List of JavaScript, CSS, and HTML Development Tools, Libraries, Projects, and Books Database MongoDB vs. SQL Server 2008 Performance Showdown Raven…

linux防ddos 软件下载,linux下防DDOS工具

DDoS deflate是一款免费的用来防御和减轻DDoS攻击的脚本。它通过netstat监测跟踪创建大量网络连接的IP地址,在检测到某个结点超过预设的限 制时,该程序会通过APF或IPTABLES禁止或阻挡这些IP.DDoS deflate官方网站:http://deflate.medialayer.…

${oid?c}的使用

编辑器加载中... ${oid?c} 写在js里会报错,其实根本就不用转换,但是如果在非javascript里就要转换 ,因为会出现逗号问题 还有个问题要注意下: var orderId document.getElementsByName("orderId"); 获取的orderId如果…

从零开始山寨Caffe·零:必先利其器

工作环境 巧妇有了米炊 众所周知,Caffe是在Linux下写的,所以长久以来,大家都认为跑Caffe,先装Linux。 niuzhiheng大神发起了caffe-windows项目(解决了一些编译、API相异问题) 以及willyd大神发起的caffe-wi…

python单例_Python - 单例模式(Singleton)

单例模式(Singleton) 本文地址: http://blog.csdn.net/caroline_wendy/article/details/23374575 单例模式 , 类的实例从始至终, 只 被创建一次 , 这些类可以用来管理一些资源; 需要 继承Object类 , 才可以使用类的方法 super() , 只实例化一次; 参见Python文档: Note super() …

Linux抓eth0网卡包的命令,Linux系统使用tcpdump命令抓包

前提条件:1. 一台安装有Linux的机器….这个是必要的;2. Tcpdump程序;3. 以下所有均是root用户登录操作,且命令不支持直接复制到Linux控制台,请手工输入!4.工具以及教程文档下载地址 点我操作步骤&#xff1a…

SilverLight非托管代码的初始化进度条方法

SilverLight非托管代码的初始化进度条方法 <script type"text/javascript"> 错误处理函数 function onSilverlightError(sender, args) ... //下载进度函数 function onSourceDownloadProgressChanged(sender, eventArgs) { sender.findN…

超全的学习资料——Oracle 从入门到精通

Oracle 从入门到精通 目录 一、SQL...................................................................................................................................................8 1.1、基本概念&#xff1a;..................................................…

common-collections中Java反序列化漏洞导致的RCE原理分析

2019独角兽企业重金招聘Python工程师标准>>> common-collections中Java反序列化漏洞导致的RCE原理分析 隐形人真忙 2015/11/11 22:40 0x00 背景 这几天在zone看到了有人提及了有关于common-collections包的RCE漏洞&#xff0c;并且http://zone.wooyun.org/content/…

linux nfs 配置_centos7 NFS 配置

NFS是什么最近项目上有这么个需求&#xff0c;客户端上传文件的时候&#xff0c;想把文件上传到另外一台服务器。本来想用ftp的&#xff0c;觉得太麻烦&#xff0c;就各种查资料&#xff0c;请教别人&#xff0c;后来发现&#xff0c;NFS这个东东真不错。NFS(网络文件系统)服务…

linux命令 waf,常用waf命令

常用waf命令一、配置及编译&#xff1a;$ ./waf configure [option]$ ./waf帮助&#xff1a; $ ./waf --help配置调试&#xff0c;优化调试&#xff1a;$ ./waf -d configure: debug,optimized改变flag: $ CXXFLAGS"-O3" ./waf configure或者&#xff1a; $CXXg-…

Windows Server 2003 导入Java生成的证书,保证iis对CAS的访问

开始 -- 运行-- mmc 打开了一个控制台程序 菜单 --> 文件 --> 添加/删除管理单元 (Ctrl M) 打开界面: 点击 "添加" 按钮,打开界面后选择 "证书",继续点此界面的添加,完成添加证书管理的操作 中间需要选择账户,我就选择的是 我的用户账户, 也可…

shell命令tree

在Windwows下很喜欢tree命令&#xff0c;在CenntOS下也有这条命令&#xff0c;在网上找到了源代码和一段简单的脚本&#xff0c; 完整的tree源代码可以在这里下载&#xff1a; ftp://mama.indstate.edu/linux/tree/ 简易的tree脚本如下&#xff1a; #!/bin/sh ################…

ulimit

ulimit用于shell启动进程所占用的资源. ulimit [-acdfHlmnpsStvw] [size] -H 设置硬资源限制.-S 设置软资源限制.-a 显示当前所有的资源限制.-c size:设置core文件的最大值.单位:blocks-d size:设置数据段的最大值.单位:kbytes-f size:设置创建文件的最大值.单位:blocks-l size…

命令点亮硬盘灯_macOS下移动硬盘无法挂载且硬盘灯一直闪烁的解决方法

致力于成为您终身的苹果管家点击上方蓝字 关注我们小编近日遇到一个诡异的问题&#xff0c;小编的移动硬盘不定期的会自动断开&#xff0c;提示未正常拔出&#xff0c;实际上一直没有动过连接线&#xff0c;然后硬盘一直处于未加载的状态&#xff0c;硬盘灯也一直闪烁不停。通…