• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    导致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 全表扫描的资料请关注脚本之家其它相关文章!

    您可能感兴趣的文章:
    • 大幅提升MySQL中InnoDB的全表扫描速度的方法
    • MySQL查询优化:LIMIT 1避免全表扫描提高查询效率
    • Mysql如何避免全表扫描的方法
    上一篇:MySQL中关于null值的一个小问题
    下一篇:详解MySQL8.0原子DDL语法
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

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