导致MySQL做全表扫描的几种情况
这两天看到了两种可能会导致全表扫描的sql,这里给大家看一下,希望可以避免踩坑:
情况1:
强制类型转换的情况下,不会使用索引,会走全表扫描。
举例如下:
首先我们创建一个表
CREATETABLE`test`( `id`int(11)NOTNULLAUTO_INCREMENT, `age`int(11)DEFAULTNULL, `score`varchar(20)NOTNULLDEFAULT'', PRIMARYKEY(`id`), KEY`idx_score`(`score`) )ENGINE=InnoDBAUTO_INCREMENT=12DEFAULTCHARSET=utf8
我们可以看到,这个表有三个字段,其中两个int类型,一个varchar类型。varchar类型的字段score是一个索引,而id是主键。
然后我们给这个表里面插入一些数据,插入数据之后的表如下:
mysql:yeyztest 21:43:12>>select*fromtest; +----+------+-------+ |id|age|score| +----+------+-------+ |1|1|5| |2|2|10| |5|5|25| |8|8|40| |9|2|45| |10|5|50| |11|8|55| +----+------+-------+ 7rowsinset(0.00sec)
这个时候,我们使用explain语句来查看两条sql的执行情况,分别是:
explain select * from test where score ='10'; explain select * from test where score =10;
结果如下:
mysql:yeyztest21:42:29>>explainselect*fromtestwherescore='10'; +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+ |id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra| +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+ |1|SIMPLE|test|NULL|ref|idx_score|idx_score|62|const|1|100.00|NULL| +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+ 1rowinset,1warning(0.00sec) mysql:yeyztest21:43:06>>explainselect*fromtestwherescore=10; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ |id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra| +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ |1|SIMPLE|test|NULL|ALL|idx_score|NULL|NULL|NULL|7|14.29|Usingwhere| +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1rowinset,3warnings(0.00sec)
可以看到,如果我们使用的是varchar类型的值,那么结果中扫描的行数rows就是1,而当我们使用的是整数值10的时候,扫描行数变为了7,证明,如果出现了强制类型转换,则会导致索引失效。
情况2:
反向查询不能使用索引,会导致全表扫描。
创建一个表test1,它的主键是score,然后插入6条数据:
CREATETABLE`test1`( `score`varchar(20) not null default '' , PRIMARYKEY(`score`) )ENGINE=InnoDBDEFAULTCHARSET=utf8 mysql:yeyztest22:09:37>>select*fromtest1; +-------+ |score| +-------+ |111| |222| |333| |444| |555| |666| +-------+ 6rowsinset(0.00sec)
当我们使用反向查找的时候,不会使用到索引,来看下面两条sql:
explain select * from test1 where score='111'; explain select * from test1 where score!='111';
mysql:yeyztest22:13:01>>explainselect*fromtest1wherescore='111'; +----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ |id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra| +----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ |1|SIMPLE|test1|NULL|const|PRIMARY|PRIMARY|62|const|1|100.00|Usingindex| +----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ 1rowinset,1warning(0.00sec) mysql:yeyztest22:13:08>>explainselect*fromtest1wherescore!='111'; +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+ |id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra| +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+ |1|SIMPLE|test1|NULL|index|PRIMARY|PRIMARY|62|NULL|6|100.00|Usingwhere;Usingindex| +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+ 1rowinset,1warning(0.00sec)
可以看到,使用!=作为条件的时候,扫描的行数是表的总记录行数。因此如果想要使用索引,我们就不能使用反向匹配规则。
情况3:
某些or值条件可能导致全表扫描。
首先我们创建一个表,并插入几条数据:
CREATETABLE`test4`( `id`int(11)DEFAULTNULL, `name`varchar(20)DEFAULTNULL, KEY`idx_id`(`id`) )ENGINE=InnoDBDEFAULTCHARSET=utf8 1rowinset(0.00sec) mysql--dba_admin@127.0.0.1:yeyztest22:23:44>>select*fromtest4; +------+------+ |id|name| +------+------+ |1|aaa| |2|bbb| |3|ccc| |4|yeyz| |NULL|yeyz| +------+------+ 5rowsinset(0.00sec)
其中表test4包含两个字段,id字段是一个索引,而name字段是varchar类型,我们来看下面三个语句的扫描行数:
explain select * from test4 where id=1; explain select * from test4 where id is null; explain select * from test4 where id=1 or id is null;
mysql:yeyztest22:24:12>>explainselect*fromtest4whereidisnull; +----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-----------------------+ |id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra| +----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-----------------------+ |1|SIMPLE|test4|NULL|ref|idx_id|idx_id|5|const|1|100.00|Usingindexcondition| +----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-----------------------+ 1rowinset,1warning(0.00sec) mysql:yeyztest22:24:17>>explainselect*fromtest4whereid=1; +----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+ |id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra| +----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+ |1|SIMPLE|test4|NULL|ref|idx_id|idx_id|5|const|1|100.00|NULL| +----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+ 1rowinset,1warning(0.00sec) mysql:yeyztest22:24:28>>explainselect*fromtest4whereid=1oridisnull; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ |id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra| +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ |1|SIMPLE|test4|NULL|ALL|idx_id|NULL|NULL|NULL|5|40.00|Usingwhere| +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1rowinset,1warning(0.00sec)
可以看到单独使用id=1和id is null,都只会扫描一行记录,而使用or将二者连接起来就会导致扫描全表而不使用索引。
简单总结一下:
1.强制类型转换的情况下,不会使用索引,会走全表扫描
2.反向查询不能使用索引,会导致全表扫描。
3.某些or值条件可能导致全表扫描。
以上就是导致MySQL做全表扫描的几种情况的详细内容,更多关于MySQL 全表扫描的资料请关注本站其它相关文章!
版权声明:本站文章来源标注为YINGSOO的内容版权均为本站所有,欢迎引用、转载,请保持原文完整并注明来源及原文链接。禁止复制或仿造本网站,禁止在非www.yingsoo.com所属的服务器上建立镜像,否则将依法追究法律责任。本站部分内容来源于网友推荐、互联网收集整理而来,仅供学习参考,不代表本站立场,如有内容涉嫌侵权,请联系alex-e#qq.com处理。