MySQL的EXPLAIN指令使用例解
2016-01-25 20:31
393 查看
数库库一共5个表(tab1,tab2等等),表结构如下:
看第一个例子:
查看上面EXPLAIN指令的输出结果,一共有两行,前后顺序也是MySQL扫描表的先后顺序(1)。共有两种扫描类型“range”、“eq_ref”,说明MySQL先使用tab5表的主键索引来过滤条件(<=500000),然后再利用参照tab4的主键索引来找到关联表的记录。
再来看一个例子:
和前面的EXPLAIN语句相比,把查询的范围扩大了一倍。再看扫描类型,变化为“ALL”,“eq_ref”,这说明MySQL再扫描tab5时不使用主键索引了,直接扫描全表,然后拿记录来过滤条件(<=1000000),然后再利用参照tab4的主键索引来找到关联表的记录。为什么不使用tab5的主键索引了呢?想必是MySQL判定在索引(二叉树)中查找一个范围所用的时间比扫描全表还慢,所以选择扫描全表(2)。
下面用“强制使用索引”来验证下上面的想法:
结果和设想的一致,索引的较大范围判定还是比较耗时的。
看下一条EXPLAIN语句:
如前面的相比,我指定查询条件tab4的一条(id = 200000)记录,此时MySQL的扫描顺序发生的变化,先扫描tab4,再扫描tab5,扫描类型也变为“const”,“ALL”。也就是说MySQL先根据tab4的索引找到id等于200000的记录,然后再对tab5表进行全表扫描,逐条比较是否满足关联条件和id小于等2000000的条件。来看下这个查询语句需要的时间:
如果,我对tab5表中的tab4_id字段做一个索引,会不会让上面语句查询速度有很大的提高呢?试一下,再看查询速度:
速度果然有很大提高,已经不超过10毫秒了。再执行下EXPLAIN语句:
此时的扫描类型已经变为“const”,“ref”,也就是说MySQL先根据tab4的索引找到id等于200000的记录,然后再参照tab4的id,利用tab5表中的对应索引划定一个范围,在这个范围中再比较其是否满足条件(<=2000000)。也提示我们关联字段要不要建索引,视关联表在查询时的使用条件而定(3)。
mysql> desc tab1; -- 共有400行记录 +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | col1 | varchar(15) | YES | | NULL | | | col2 | datetime | YES | MUL | NULL | | +-------+-------------+------+-----+---------+----------------+ 3 rows in set (0.01 sec) mysql> desc tab2; -- 共有4000行记录 +---------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | col1 | varchar(15) | YES | | NULL | | | col2 | datetime | YES | MUL | NULL | | | tab1_id | int(11) | YES | | NULL | | +---------+-------------+------+-----+---------+----------------+ 4 rows in set (0.01 sec) -- tab3,tab4,tab5结构类似于tab2,分别有40000、400000,4000000行记录;
看第一个例子:
mysql> EXPLAIN -> SELECT COUNT(*) -> FROM tab5 JOIN tab4 ON tab4.id = tab5.tab4_id -> WHERE tab5.id <= 500000; +----+-------------+-------+--------+---------------+---------+---------+-------------------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------+---------+---------+-------------------+--------+-------------+ | 1 | SIMPLE | tab5 | range | PRIMARY | PRIMARY | 4 | NULL | 504980 | Using where | | 1 | SIMPLE | tab4 | eq_ref | PRIMARY | PRIMARY | 4 | test.tab5.tab4_id | 1 | Using index | +----+-------------+-------+--------+---------------+---------+---------+-------------------+--------+-------------+ 2 rows in set (0.00 sec)
查看上面EXPLAIN指令的输出结果,一共有两行,前后顺序也是MySQL扫描表的先后顺序(1)。共有两种扫描类型“range”、“eq_ref”,说明MySQL先使用tab5表的主键索引来过滤条件(<=500000),然后再利用参照tab4的主键索引来找到关联表的记录。
再来看一个例子:
mysql> EXPLAIN -> SELECT COUNT(*) -> FROM tab5 JOIN tab4 ON tab4.id = tab5.tab4_id -> WHERE tab5.id <= 1000000; +----+-------------+-------+--------+---------------+---------+---------+-------------------+---------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------+---------+---------+-------------------+---------+-------------+ | 1 | SIMPLE | tab5 | ALL | PRIMARY | NULL | NULL | NULL | 4000000 | Using where | | 1 | SIMPLE | tab4 | eq_ref | PRIMARY | PRIMARY | 4 | test.tab5.tab4_id | 1 | Using index | +----+-------------+-------+--------+---------------+---------+---------+-------------------+---------+-------------+ 2 rows in set (0.00 sec)
和前面的EXPLAIN语句相比,把查询的范围扩大了一倍。再看扫描类型,变化为“ALL”,“eq_ref”,这说明MySQL再扫描tab5时不使用主键索引了,直接扫描全表,然后拿记录来过滤条件(<=1000000),然后再利用参照tab4的主键索引来找到关联表的记录。为什么不使用tab5的主键索引了呢?想必是MySQL判定在索引(二叉树)中查找一个范围所用的时间比扫描全表还慢,所以选择扫描全表(2)。
下面用“强制使用索引”来验证下上面的想法:
mysql> SELECT COUNT(*) FROM tab5 JOIN tab4 ON tab4.id = tab5.tab4_id WHERE tab5.id <= 1000000; 1 row in set (1.73 sec) mysql> SELECT COUNT(*) FROM tab5 FORCE INDEX (PRIMARY) JOIN tab4 ON tab4.id = tab5.tab4_id WHERE tab5.id <= 1000000; 1 row in set (4.02 sec)
结果和设想的一致,索引的较大范围判定还是比较耗时的。
看下一条EXPLAIN语句:
mysql> EXPLAIN -> SELECT COUNT(*) -> FROM tab5 JOIN tab4 ON tab4.id = tab5.tab4_id -> WHERE tab5.id <= 2000000 AND tab4.id = 200000; +----+-------------+-------+-------+---------------+---------+---------+-------+---------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+-------+---------+-------------+ | 1 | SIMPLE | tab4 | const | PRIMARY | PRIMARY | 4 | const | 1 | Using index | | 1 | SIMPLE | tab5 | ALL | PRIMARY | NULL | NULL | NULL | 4000000 | Using where | +----+-------------+-------+-------+---------------+---------+---------+-------+---------+-------------+ 2 rows in set (0.00 sec)
如前面的相比,我指定查询条件tab4的一条(id = 200000)记录,此时MySQL的扫描顺序发生的变化,先扫描tab4,再扫描tab5,扫描类型也变为“const”,“ALL”。也就是说MySQL先根据tab4的索引找到id等于200000的记录,然后再对tab5表进行全表扫描,逐条比较是否满足关联条件和id小于等2000000的条件。来看下这个查询语句需要的时间:
mysql> SELECT COUNT(*) FROM tab5 JOIN tab4 ON tab4.id = tab5.tab4_id WHERE tab5.id <= 2000000 AND tab4.id = 200000; 1 row in set (0.52 sec)
如果,我对tab5表中的tab4_id字段做一个索引,会不会让上面语句查询速度有很大的提高呢?试一下,再看查询速度:
-- 原来tab5表tab4_id字段没有索引,这条语句是在加上索引后执行的 mysql> SELECT COUNT(*) FROM tab5 JOIN tab4 ON tab4.id = tab5.tab4_id WHERE tab5.id <= 2000000 AND tab4.id = 200000; 1 row in set (0.00 sec)
速度果然有很大提高,已经不超过10毫秒了。再执行下EXPLAIN语句:
mysql> EXPLAIN -> SELECT COUNT(*) -> FROM tab5 JOIN tab4 ON tab4.id = tab5.tab4_id -> WHERE tab5.id <= 2000000 AND tab4.id = 200000; +----+-------------+-------+-------+---------------------+-------------+---------+-------+------+------------- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra +----+-------------+-------+-------+---------------------+-------------+---------+-------+------+------------- | 1 | SIMPLE | tab4 | const | PRIMARY | PRIMARY | 4 | const | 1 | Using index | 1 | SIMPLE | tab5 | ref | PRIMARY,idx_tab4_id | idx_tab4_id | 5 | const | 10 | Using where +----+-------------+-------+- 3ff0 ------+---------------------+-------------+---------+-------+------+------------- 2 rows in set (0.00 sec)
此时的扫描类型已经变为“const”,“ref”,也就是说MySQL先根据tab4的索引找到id等于200000的记录,然后再参照tab4的id,利用tab5表中的对应索引划定一个范围,在这个范围中再比较其是否满足条件(<=2000000)。也提示我们关联字段要不要建索引,视关联表在查询时的使用条件而定(3)。
相关文章推荐
- 19个MySQL性能优化主要要点
- MySQL识别下列转义字符:
- MySQL user表简介
- mysql root给其它用户授权问题
- MySQL 存储过程 常用语法
- mysql学习笔记
- MySQL索引使用方法和性能优化
- mysql锁3.常见问题
- MySQL支持的数据类型
- MySQL 获得当前日期时间(以及时间的转换)
- mysql的in选择结果过,按照in里面的排序排序
- Mysql中创建根据第二个自增的id
- MySQL某一时间点数据与一小时前、一天前、一月前数据对比
- ubantu操作指令 访问Mysql
- MYSQL的分区字段必须包含主键-介绍以及解决方法
- mysql 索引( mysql index )
- 使用mysql profiling功能剖析单条查询
- mysql解决自动断开8小时未曾用过的链接
- [MySQL]Software caused connection abort: recv failed 问题分析与解决
- PostgreSQL与MySQL优势比较