新闻动态
新闻动态
NEWS INFORMATION

导致MySQL做全表扫描的几种情况

发布日期:2022-02-14 19:47 | 文章来源:gibhub

这两天看到了两种可能会导致全表扫描的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处理。

实时开通

自选配置、实时开通

免备案

全球线路精选!

全天候客户服务

7x24全年不间断在线

专属顾问服务

1对1客户咨询顾问

在线
客服

在线客服:7*24小时在线

客服
热线

400-630-3752
7*24小时客服服务热线

关注
微信

关注官方微信
顶部