php分页全表扫描,导致MySQL做全表扫描的几种情况

这两天看到了两种可能会导致全表扫描的sql,这里给大家看一下,希望可以避免踩坑:

情况1:

强制类型转换的情况下,不会使用索引,会走全表扫描。

举例如下:

首先我们创建一个表

CREATE TABLE `test` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`age` int(11) DEFAULT NULL,

`score` varchar(20) NOT NULL DEFAULT '',

PRIMARY KEY (`id`),

KEY `idx_score` (`score`)

) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8

我们可以看到,这个表有三个字段,其中两个int类型,一个varchar类型。varchar类型的字段score是一个索引,而id是主键。

然后我们给这个表里面插入一些数据,插入数据之后的表如下:

mysql:yeyztest 21:43:12>>select * from test;

+----+------+-------+

| id | age  | score |

+----+------+-------+

|  1 |    1 | 5     |

|  2 |    2 | 10    |

|  5 |    5 | 25    |

|  8 |    8 | 40    |

|  9 |    2 | 45    |

| 10 |    5 | 50    |

| 11 |    8 | 55    |

+----+------+-------+

7 rows in set (0.00 sec)

这个时候,我们使用explain语句来查看两条sql的执行情况,分别是:

explain select * from test where score ='10';

explain select * from test where score =10;

结果如下:

mysql:yeyztest 21:42:29>>explain select * from test where score ='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  |

+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+

1 row in set, 1 warning (0.00 sec)

mysql:yeyztest 21:43:06>>explain select * from test where score =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 | Using where |

+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

1 row in set, 3 warnings (0.00 sec)

可以看到,如果我们使用的是varchar类型的值,那么结果中扫描的行数rows就是1,而当我们使用的是整数值10的时候,扫描行数变为了7,证明,如果出现了强制类型转换,则会导致索引失效。

情况2:

反向查询不能使用索引,会导致全表扫描。

创建一个表test1,它的主键是score,然后插入6条数据:

CREATE TABLE `test1` (

`score` varchar(20) not null default '' ,

PRIMARY KEY (`score`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8

mysql:yeyztest 22:09:37>>select * from test1;

+-------+

| score |

+-------+

| 111   |

| 222   |

| 333   |

| 444   |

| 555   |

| 666   |

+-------+

6 rows in set (0.00 sec)

当我们使用反向查找的时候,不会使用到索引,来看下面两条sql:

explain select * from test1 where score='111';

explain select * from test1 where score!='111';

mysql:yeyztest 22:13:01>>explain select * from test1 where score='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 | Using index |

+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+

1 row in set, 1 warning (0.00 sec)

mysql:yeyztest 22:13:08>>explain select * from test1 where score!='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 | Using where; Using index |

+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+

1 row in set, 1 warning (0.00 sec)

可以看到,使用!=作为条件的时候,扫描的行数是表的总记录行数。因此如果想要使用索引,我们就不能使用反向匹配规则。

情况3:

某些or值条件可能导致全表扫描。

首先我们创建一个表,并插入几条数据:

CREATE TABLE `test4` (

`id` int(11) DEFAULT NULL,

`name` varchar(20) DEFAULT NULL,

KEY `idx_id` (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8

1 row in set (0.00 sec)

mysql--dba_admin@127.0.0.1:yeyztest 22:23:44>>select * from test4;

+------+------+

| id   | name |

+------+------+

|    1 | aaa  |

|    2 | bbb  |

|    3 | ccc  |

|    4 | yeyz |

| NULL | yeyz |

+------+------+

5 rows in set (0.00 sec)

其中表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:yeyztest 22:24:12>>explain select * from test4 where id is null;

+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-----------------------+

| 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 | Using index condition |

+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-----------------------+

1 row in set, 1 warning (0.00 sec)

mysql:yeyztest 22:24:17>>explain select * from test4 where id=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  |

+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+

1 row in set, 1 warning (0.00 sec)

mysql:yeyztest 22:24:28>>explain select * from test4 where id=1 or id is null;

+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

| 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 | Using where |

+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

1 row in set, 1 warning (0.00 sec)

可以看到单独使用id=1和id is null,都只会扫描一行记录,而使用or将二者连接起来就会导致扫描全表而不使用索引。

简单总结一下:

1.强制类型转换的情况下,不会使用索引,会走全表扫描

2.反向查询不能使用索引,会导致全表扫描。

3.某些or值条件可能导致全表扫描。

以上就是导致MySQL做全表扫描的几种情况的详细内容,更多关于MySQL 全表扫描的资料请关注脚本之家其它相关文章!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值