MySQL索引失效情况
explain命令解释
1 | mysql> explain select * from u_user where name like '王%' ; |
以下通过explain显示出mysql执行的字段内容:
id: SELECT 查询的标识符. 每个 SELECT 都会自动分配一个唯一的标识符.
select_type: SELECT 查询的类型.
table: 查询的是哪个表
partitions: 匹配的分区
type: join 类型
possible_keys: 此次查询中可能选用的索引
key: 此次查询中确切使用到的索引.
ref: 哪个字段或常数与 key 一起被使用
rows: 显示此查询一共扫描了多少行. 这个是一个估计值.
filtered: 表示此查询条件所过滤的数据的百分比
extra: 额外的信息
索引失效情况
like 以%开头,索引无效;当like前缀没有%,后缀有%时,索引有效
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15mysql> 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)or语句前后没有同时使用索引。当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15mysql> 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)组合索引,不是使用第一列索引,索引失效
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15mysql> 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)数据类型出现隐式转化。如varchar不加单引号的话可能会自动转换为int型,使索引无效,产生全表扫描
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15mysql> 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)在索引列上使用 IS NULL 或 IS NOT NULL操作。索引是不索引空值的,所以这样的操作不能使用索引,可以用其他的办法处理,例如:数字类型,判断大于0,字符串类型设置一个默认值,判断是否等于默认值即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15mysql> 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)在索引字段上使用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
23mysql> 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)对索引字段进行计算操作、字段上使用函数
1
2
3
4
5
6
7mysql> 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)当全表扫描速度比索引速度快时,mysql会使用全表扫描,此时索引失效
索引失效分析工具
索引失效分析工具:
可以使用explain命令加在要分析的sql语句前面,在执行结果中查看key这一列的值,如果为NULL,说明没有使用索引。