170602-MySQL索引失效情况

MySQL索引失效情况

explain命令解释

1
2
3
4
5
6
7
mysql> explain select * from u_user where name like '王%' ;
+----+-------------+--------+-------+---------------+----------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+-------+---------------+----------+---------+------+------+-----------------------+
| 1 | SIMPLE | u_user | range | idx_name | idx_name | 152 | NULL | 17 | Using index condition |
+----+-------------+--------+-------+---------------+----------+---------+------+------+-----------------------+
1 row in set (0.02 sec)

以下通过explain显示出mysql执行的字段内容:

id: SELECT 查询的标识符. 每个 SELECT 都会自动分配一个唯一的标识符.

select_type: SELECT 查询的类型.

table: 查询的是哪个表

partitions: 匹配的分区

type: join 类型

possible_keys: 此次查询中可能选用的索引

key: 此次查询中确切使用到的索引.

ref: 哪个字段或常数与 key 一起被使用

rows: 显示此查询一共扫描了多少行. 这个是一个估计值.

filtered: 表示此查询条件所过滤的数据的百分比

extra: 额外的信息

索引失效情况

  1. like 以%开头,索引无效;当like前缀没有%,后缀有%时,索引有效

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    mysql> explain select * from u_user where name like '%王' ;
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | 1 | SIMPLE | u_user | ALL | NULL | NULL | NULL | NULL | 4613 | Using where |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    1 row in set (0.00 sec)

    mysql> explain select * from u_user where name like '王%' ;
    +----+-------------+--------+-------+---------------+----------+---------+------+------+-----------------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+-------+---------------+----------+---------+------+------+-----------------------+
    | 1 | SIMPLE | u_user | range | idx_name | idx_name | 152 | NULL | 17 | Using index condition |
    +----+-------------+--------+-------+---------------+----------+---------+------+------+-----------------------+
    1 row in set (0.01 sec)
  2. or语句前后没有同时使用索引。当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    mysql> explain select * from u_user where name ='王五' or user_id='1111'  ;
    +----+-------------+--------+-------------+------------------+------------------+---------+------+------+--------------------------------------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+-------------+------------------+------------------+---------+------+------+--------------------------------------------+
    | 1 | SIMPLE | u_user | index_merge | user_id,idx_name | idx_name,user_id | 152,92 | NULL | 2 | Using union(idx_name,user_id); Using where |
    +----+-------------+--------+-------------+------------------+------------------+---------+------+------+--------------------------------------------+
    1 row in set (0.08 sec)

    mysql> explain select * from u_user where name ='王五' or level_cd='11' ;
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | 1 | SIMPLE | u_user | ALL | idx_name | NULL | NULL | NULL | 4613 | Using where |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    1 row in set (0.01 sec)
  3. 组合索引,不是使用第一列索引,索引失效

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    mysql> explain select * from u_user where email ='yubo@163.com';
    +----+-------------+--------+------+-------------------+-------------------+---------+-------+------+-----------------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+------+-------------------+-------------------+---------+-------+------+-----------------------+
    | 1 | SIMPLE | u_user | ref | idx_email_mobile | idx_email_mobile | 93 | const | 1 | Using index condition |
    +----+-------------+--------+------+-------------------+-------------------+---------+-------+------+-----------------------+
    1 row in set (0.00 sec)

    mysql> explain select * from u_user where tel ='17797173884';
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | 1 | SIMPLE | u_user | ALL | NULL | NULL | NULL | NULL | 4613 | Using where |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    1 row in set (0.02 sec)
  4. 数据类型出现隐式转化。如varchar不加单引号的话可能会自动转换为int型,使索引无效,产生全表扫描

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    mysql> explain select * from u_user where name='17';
    +----+-------------+--------+------+---------------+----------+---------+-------+------+-----------------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+------+---------------+----------+---------+-------+------+-----------------------+
    | 1 | SIMPLE | u_user | ref | idx_name | idx_name | 152 | const | 1 | Using index condition |
    +----+-------------+--------+------+---------------+----------+---------+-------+------+-----------------------+
    1 row in set (0.01 sec)

    mysql> explain select * from u_user where name=17;
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | 1 | SIMPLE | u_user | ALL | idx_name | NULL | NULL | NULL | 4613 | Using where |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    1 row in set (0.00 sec)
  5. 在索引列上使用 IS NULL 或 IS NOT NULL操作。索引是不索引空值的,所以这样的操作不能使用索引,可以用其他的办法处理,例如:数字类型,判断大于0,字符串类型设置一个默认值,判断是否等于默认值即可。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    mysql> explain select * from u_user where email is  null;
    +----+-------------+--------+------+---------------+-----------+---------+-------+------+-----------------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+------+---------------+-----------+---------+-------+------+-----------------------+
    | 1 | SIMPLE | u_user | ref | idx_email | idx_email | 93 | const | 116 | Using index condition |
    +----+-------------+--------+------+---------------+-----------+---------+-------+------+-----------------------+
    1 row in set (0.01 sec)

    mysql> explain select * from u_user where email is not null;
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | 1 | SIMPLE | u_user | ALL | idx_email | NULL | NULL | NULL | 4613 | Using where |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    1 row in set (0.03 sec)
  6. 在索引字段上使用not,<>,!=。不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。 优化方法: key<>0 改为 key>0 or key<0

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    mysql> explain select * from u_user where age !=20;
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | 1 | SIMPLE | u_user | ALL | idx_age | NULL | NULL | NULL | 4613 | Using where |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    1 row in set (0.09 sec)

    mysql> explain select * from u_user where age <20;
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | 1 | SIMPLE | u_user | ALL | idx_age | NULL | NULL | NULL | 4613 | Using where |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    1 row in set (0.06 sec)

    mysql> explain select * from u_user where age >20;
    +----+-------------+--------+-------+---------------+---------+---------+------+------+-----------------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+-------+---------------+---------+---------+------+------+-----------------------+
    | 1 | SIMPLE | u_user | range | idx_age | idx_age | 5 | NULL | 4 | Using index condition |
    +----+-------------+--------+-------+---------------+---------+---------+------+------+-----------------------+
    1 row in set (0.02 sec)
  7. 对索引字段进行计算操作、字段上使用函数

    1
    2
    3
    4
    5
    6
    7
    mysql> explain select name from u_user  where left(email,1) ='a';
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    | 1 | SIMPLE | u_user | ALL | NULL | NULL | NULL | NULL | 4613 | Using where |
    +----+-------------+--------+------+---------------+------+---------+------+------+-------------+
    1 row in set (0.03 sec)
  8. 当全表扫描速度比索引速度快时,mysql会使用全表扫描,此时索引失效

索引失效分析工具

索引失效分析工具:

可以使用explain命令加在要分析的sql语句前面,在执行结果中查看key这一列的值,如果为NULL,说明没有使用索引。

参考资料

Mysql索引查询失效的情况

#
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×