MySQL的四种不同查询的分析
1.前置条件:
本次是基于小数据量,且数据块在一个页中的最理想情况进行分析,可能无具体的实际意义,但是可以借鉴到各种复杂条件下,因为原理是相同的,知小见大,见微知著!
打开语句分析并确认是否已经打开
- mysql> set profiling=1;
- Query OK, 0 rows affected (0.00 sec)
- mysql> select @@profiling;
- +-------------+
- | @@profiling |
- +-------------+
- | 1 |
- +-------------+
- 1 row in set (0.01 sec)
2.数据准备:
2.1全表扫描数据
- create table person4all(id int not null auto_increment, name varchar(30) not null, gender varchar(10) not null ,primary key(id));
- insert into person4all(name,gender) values("zhaoming","male");
- insert into person4all(name,gender) values("wenwen","female");
2.2根据主键查看数据
- create table person4pri(id int not null auto_increment, name varchar(30) not null, gender varchar(10) not null ,primary key(id));
- insert into person4pri(name,gender) values("zhaoming","male");
- insert into person4pri(name,gender) values("wenwen","female");
2.3根据非聚集索引查数据
- create table person4index(id int not null auto_increment, name varchar(30) not null, gender varchar(10) not null ,primary key(id) , index(gender));
- insert into person4index(name,gender) values("zhaoming","male");
- insert into person4index(name,gender) values("wenwen","female");
2.4根据覆盖索引查数据
- 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));
- insert into person4cindex(name,gender) values("zhaoming","male");
- insert into person4cindex(name,gender) values("wenwen","female");
主要从以下几个方面分析:查询消耗的时间,走的执行计划等方面。
3.开工测试:
第一步:全表扫描
- mysql> select * from person4all ;
- +----+----------+--------+
- | id | name | gender |
- +----+----------+--------+
- | 1 | zhaoming | male |
- | 2 | wenwen | female |
- +----+----------+--------+
- 2 rows in set (0.00 sec)
查看其执行计划:
- mysql> explain select * from person4all;
- +----+-------------+------------+------+---------------+------+---------+------+------+-------+
- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
- +----+-------------+------------+------+---------------+------+---------+------+------+-------+
- | 1 | SIMPLE | person4all | ALL | NULL | NULL | NULL | NULL | 2 | |
- +----+-------------+------------+------+---------------+------+---------+------+------+-------+
- 1 row in set (0.01 sec)
我们可以很清晰的看到走的是全表扫描,而没有走索引!
查询消耗的时间:
- mysql> show profiles;
- +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------+
- | Query_ID | Duration | Query |
- | 54 | 0.00177300 | select * from person4all |
- | 55 | 0.00069200 | explain select * from person4all |
- +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------+
全表扫描总共话了0.0017730秒
各个阶段消耗的时间是:
- mysql> show profile for query 54;
- +--------------------------------+----------+
- | Status | Duration |
- +--------------------------------+----------+
- | starting | 0.000065 |
- | checking query cache for query | 0.000073 |
- | Opening tables | 0.000037 |
- | System lock | 0.000024 |
- | Table lock | 0.000053 |
- | init | 0.000044 |
- | optimizing | 0.000022 |
- | statistics | 0.000032 |
- | preparing | 0.000030 |
- | executing | 0.000020 |
- | Sending data | 0.001074 |
- | end | 0.000091 |
- | query end | 0.000020 |
- | freeing items | 0.000103 |
- | storing result in query cache | 0.000046 |
- | logging slow query | 0.000019 |
- | cleaning up | 0.000020 |
- +--------------------------------+----------+
- 17 rows in set (0.00 sec)
第一次不走缓存的话,需要检查是否存在缓存中,打开表,初始化等操作,最大的开销在于返回数据。
第二步:根据主键查询数据。
- mysql> select name ,gender from person4pri where id in (1,2);
- +----------+--------+
- | name | gender |
- +----------+--------+
- | zhaoming | male |
- | wenwen | female |
- +----------+--------+
- 2 rows in set (0.01 sec)
查看其执行计划:
- mysql> explain select name ,gender from person4pri where id in (1,2);
- +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
- +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
- | 1 | SIMPLE | person4pri | range | PRIMARY | PRIMARY | 4 | NULL | 2 | Using where |
- +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
- 1 row in set (0.00 sec)
从执行计划中我们可以看出,走的是范围索引。
再看其执行消耗的时间:
- mysql> show profiles;
- +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------+
- | Query_ID | Duration | Query |
- +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------+
- | 63 | 0.00135700 | select name ,gender from person4pri where id in (1,2) |
- | 64 | 0.00079200 | explain select name ,gender from person4pri where id in (1,2) |
- +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------+
- 15 rows in set (0.01 sec)
这次查询消耗时间为0.00079200。
查看各个阶段消耗的时间:
- mysql> show profile for query 63;
- +--------------------------------+----------+
- | Status | Duration |
- +--------------------------------+----------+
- | starting | 0.000067 |
- | checking query cache for query | 0.000146 |
- | Opening tables | 0.000342 |
- | System lock | 0.000027 |
- | Table lock | 0.000115 |
- | init | 0.000056 |
- | optimizing | 0.000032 |
- | statistics | 0.000069 |
- | preparing | 0.000039 |
- | executing | 0.000022 |
- | Sending data | 0.000100 |
- | end | 0.000075 |
- | query end | 0.000022 |
- | freeing items | 0.000158 |
- | storing result in query cache | 0.000045 |
- | logging slow query | 0.000019 |
- | cleaning up | 0.000023 |
- +--------------------------------+----------+
- 17 rows in set (0.00 sec)
看出最大的消耗也是在Sending data,第一次也是需要一些初始化操作。
第三步:根据非聚集索引查询
- mysql> select name ,gender from person4index where gender in ("male","female");
- +----------+--------+
- | name | gender |
- +----------+--------+
- | wenwen | female |
- | zhaoming | male |
- +----------+--------+
- 2 rows in set (0.00 sec)
查看器执行计划:
- mysql> explain select name ,gender from person4index where gender in ("male","female");
- +----+-------------+--------------+-------+---------------+--------+---------+------+------+-------------+
- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
- +----+-------------+--------------+-------+---------------+--------+---------+------+------+-------------+
- | 1 | SIMPLE | person4index | range | gender | gender | 12 | NULL | 2 | Using where |
- +----+-------------+--------------+-------+---------------+--------+---------+------+------+-------------+
- 1 row in set (0.00 sec)
可以看出,走的也是范围索引。同主键查询,那么就看其消耗时间了
- mysql> show profiles;
- +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------+
- | Query_ID | Duration | Query |
- +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------+
- | 68 | 0.00106600 | select name ,gender from person4index where gender in ("male","female") |
- | 69 | 0.00092500 | explain select name ,gender from person4index where gender in ("male","female") |
- +----------+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------+
- 15 rows in set (0.00 sec)
这个非主键索引消耗的时间为:0.00106600,可以看出略大于组件索引消耗的时间。
看其具体消耗的阶段:
- mysql> show profile for query 68 ;
- +--------------------------------+----------+
- | Status | Duration |
- +--------------------------------+----------+
- | starting | 0.000059 |
- | checking query cache for query | 0.000111 |
- | Opening tables | 0.000085 |
- | System lock | 0.000023 |
- | Table lock | 0.000067 |
- | init | 0.000183 |
- | optimizing | 0.000031 |
- | statistics | 0.000139 |
- | preparing | 0.000035 |
- | executing | 0.000020 |
- | Sending data | 0.000148 |
- | end | 0.000024 |
- | query end | 0.000019 |
- | freeing items | 0.000043 |
- | storing result in query cache | 0.000042 |
- | logging slow query | 0.000017 |
- | cleaning up | 0.000020 |
- +--------------------------------+----------+
- 17 rows in set (0.00 sec)
看几个关键词的点;init,statistics,Sending data 这几个关键点上的消耗向比较主键的查询要大很多,特别是Sending data。因为若是走的非聚集索引,那么就需要回表进行再进行一次查询,多消耗一次IO。
第四部:根据覆盖索引查询数据
- mysql> select gender ,name from person4cindex where gender in ("male","female");
- +--------+----------+
- | gender | name |
- +--------+----------+
- | female | wenwen |
- | male | zhaoming |
- +--------+----------+
- 2 rows in set (0.01 sec)
这里需要注意的是,我的字段查询顺序变了,是gender,name而不在是前面的name,gender,这样是为了走覆盖索引。具体看效果吧
还是先看执行计划:
- mysql> explain select gender ,name from person4cindex where gender in ("male","female");
- +----+-------------+---------------+-------+---------------+------+---------+------+------+--------------------------+
- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
- +----+-------------+---------------+-------+---------------+------+---------+------+------+--------------------------+
- | 1 | SIMPLE | person4cindex | index | NULL | name | 44 | NULL | 2 | Using where; Using index |
- +----+-------------+---------------+-------+---------------+------+---------+------+------+--------------------------+
- 1 row in set (0.00 sec)
最后栏Extra中表示走的就是覆盖索引。
看消耗的时间吧:
- mysql> show profiles;
- +----------+------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
- | Query_ID | Duration | Query |
- +----------+------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
- | 83 | 0.00115400 | select gender ,name from person4cindex where gender in ("male","female") |
- | 84 | 0.00074000 | explain select gender ,name from person4cindex where gender in ("male","female") |
- +----------+------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
我们看到消耗的时间是0.00115400,看这个数字好像挺高的,那么都花在什么地方了呢?
看下具体的消耗情况:
- mysql> show profile for query 83 ;
- +--------------------------------+----------+
- | Status | Duration |
- +--------------------------------+----------+
- | starting | 0.000083 |
- | checking query cache for query | 0.000113 |
- | Opening tables | 0.000039 |
- | System lock | 0.000026 |
- | Table lock | 0.000075 |
- | init | 0.000128 |
- | optimizing | 0.000193 |
- | statistics | 0.000056 |
- | preparing | 0.000038 |
- | executing | 0.000021 |
- | Sending data | 0.000121 |
- | end | 0.000042 |
- | query end | 0.000021 |
- | freeing items | 0.000112 |
- | storing result in query cache | 0.000043 |
- | logging slow query | 0.000021 |
- | cleaning up | 0.000022 |
- +--------------------------------+----------+
- 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;
MySQL的四种不同查询的分析的更多相关文章
- MYSQL的全表扫描,主键索引(聚集索引、第一索引),非主键索引(非聚集索引、第二索引),覆盖索引四种不同查询的分析
文章出处:http://inter12.iteye.com/blog/1430144 MYSQL的全表扫描,主键索引(聚集索引.第一索引),非主键索引(非聚集索引.第二索引),覆盖索引四种不同查询的分 ...
- MySQL 通用查询日志和慢查询日志分析
MySQL中的日志包括:错误日志.二进制日志.通用查询日志.慢查询日志等等.这里主要介绍下比较常用的两个功能:通用查询日志和慢查询日志. 1)通用查询日志:记录建立的客户端连接和执行的语句.2)慢查询 ...
- 关于MySQL 通用查询日志和慢查询日志分析
MySQL中的日志包括:错误日志.二进制日志.通用查询日志.慢查询日志等等.这里主要介绍下比较常用的两个功能:通用查询日志和慢查询日志. 1)通用查询日志:记录建立的客户端连接和执行的语句. 2)慢查 ...
- 关于MySQL 通用查询日志和慢查询日志分析(转)
MySQL中的日志包括:错误日志.二进制日志.通用查询日志.慢查询日志等等.这里主要介绍下比较常用的两个功能:通用查询日志和慢查询日志. 1)通用查询日志:记录建立的客户端连接和执行的语句. 2)慢查 ...
- Mysql Binlog三种格式介绍及分析【转】
一.Mysql Binlog格式介绍 Mysql binlog日志有三种格式,分别为Statement,MiXED,以及ROW! 1.Statement:每一条会修改数据的sql都会记录在 ...
- MySQL有四种BLOB类型
先说明一下Blob的类型,直接从网上摘抄了!!!1.MySQL有四种BLOB类型: ·tinyblob:仅255个字符 ·blob:最大限制到65K字节 ·mediumblob:限制到16M字节 ·l ...
- MySQL中四种常用存储引擎的介绍
MySQL常用的四种引擎的介绍 (1):MyISAM存储引擎: 不支持事务.也不支持外键,优势是访问速度快,对事务完整性没有 要求或者以select,insert为主的应用基本上可以用这个引擎来创建表 ...
- Mysql常见四种索引的使用
提到MySQL优化,索引优化是必不可少的.其中一种优化方式 --索引优化,添加合适的索引能够让项目的并发能力和抗压能力得到明显的提升. 我们知道项目性能的瓶颈主要是在"查(select)&q ...
- 160624、Spark读取数据库(Mysql)的四种方式讲解
目前Spark支持四种方式从数据库中读取数据,这里以Mysql为例进行介绍. 一.不指定查询条件 这个方式链接MySql的函数原型是: 1 def jdbc(url: String, table: S ...
随机推荐
- 报表UI测试点
1.功能完整性:是否实现了产品需求功能 2.数据准确性:UI显示数据,是否与后端传过来的数据一致 3.页面兼容性:浏览器兼容.布局 4.分页查询 5.数据格式一致性:小数精确位.百分比保留位数等 6. ...
- 使用spring validation完成数据后端校验
前言 数据的校验是交互式网站一个不可或缺的功能,前端的js校验可以涵盖大部分的校验职责,如用户名唯一性,生日格式,邮箱格式校验等等常用的校验.但是为了避免用户绕过浏览器,使用http工具直接向后端请求 ...
- 行为模式--代理Proxy模式(Java)
代理(AOP切面的雏形): 题记:顾名思义就是将某件事,某个东西的使用权进行为让授权转移.代理相当于中介(不同于中介者模式),在原本操作的类之间添加了一个桥梁.但代理不能去修改原有目标.比如:一个人要 ...
- 为什么java实体类需要重写toString方法
如果没重写toString的情况: Object 类的 toString 方法 返回一个字符串,该字符串由类名(对象是该类的一个实例).at 标记符“@”和此对象哈希码的无符号十六进制表示组成.换句话 ...
- Python基本模块介绍:sys、platform
sys模块 常用函数 sys.argv 命令行参数,实现从程序外部向程序传递参数. sys.path 模块搜索路径. sys.platform 获取当前系统平台. sys.version 获取pyth ...
- jQuery图片延迟加载插件:jquery.lazyload
----------------------------------------------------------------------------------------------- clas ...
- Android辅助开发工具说明
1.aapt(Android Asset Packaging Tool):用于建立zip包(zip.jar.apk),也可用于将资源编译到二进制的assets:2.adb(Android Debug ...
- 3Ds Max 2014
原文地址:https://blog.csdn.net/u011518678/article/details/50764835 1.3Ds Max 2014 的安装和激活 激活地址: https://j ...
- jQuery文档就绪事件
[jQuery文档就绪事件] 为了防止文档在完全加载(就绪)之前运行 jQuery 代码.如果在文档没有完全加载之前就运行函数,操作可能失败. $(document).ready(function() ...
- CSS Media Query
[CSS Media Query] CSS Media Queries are a feature in CSS3 which allows you to specify when certain C ...