您的位置:首页 > 数据库 > > 正文

mysql出现锁表的原因(导致MySQL做全表扫描的几种情况)

更多 时间:2021-10-16 00:54:39 类别:数据库 浏览量:2035

mysql出现锁表的原因

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

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

情况1:

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

举例如下:

首先我们创建一个表

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  •  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是主键。

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

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 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    |
  • +----+------+-------+
  • rows in set (0.00 sec)
  • 这个时候,我们使用explain语句来查看两条sql的执行情况,分别是:

  • ?
  • 1
  • 2
  • 3
  • explain select * from test where score ='10';
  •  
  • explain select * from test where score =10;
  • 结果如下:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 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条数据:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 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   |
  • +-------+
  • rows in set (0.00 sec)
  •     当我们使用反向查找的时候,不会使用到索引,来看下面两条sql:

  • ?
  • 1
  • 2
  • 3
  • explain select * from test1 where score='111';
  •  
  • explain select * from test1 where score!='111';
  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 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值条件可能导致全表扫描。

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

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • create table `test4` (
  •   `id` int(11) default null,
  •   `namevarchar(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 |
  • +------+------+
  • rows in set (0.00 sec)
  •    其中表test4包含两个字段,id字段是一个索引,而name字段是varchar类型,我们来看下面三个语句的扫描行数:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 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;
  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 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 全表扫描的资料请关注开心学习网其它相关文章!

    原文链接:https://mp.weixin.qq.com/s/5G1xGrxb6ii_gpcWE1hC6A

    标签:mysql 扫描 全表
    您可能感兴趣