没使用索引
mysql> EXPLAIN select * from employees where first_name="Sahrah";
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| 1 | SIMPLE | employees | NULL | ALL | NULL | NULL | NULL | NULL | 299290 | 10.00 | Using where |
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+-------------+
1 row in set, 1 warning (0.01 sec)
使用索引
mysql> create index index_test on employees(first_name);
mysql> EXPLAIN select * from employees where first_name="Sahrah";
+----+-------------+-----------+------------+------+---------------+------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+------+---------------+------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | employees | NULL | ref | index_test | index_test | 58 | const | 217 | 100.00 | NULL |
+----+-------------+-----------+------------+------+---------------+------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
很直观的可以看出没使用索引前扫描约299290行数据,使用了之后只扫描217条数据,filtered表示扫描结果有百分之几符合where条件
小贴士:
索引不能生效的场景:
1.当字段成为函数参数时候
SELECT * FROM employees WHERE UPPER(first_name) = 'SAHRAH';
2.当模糊匹配为%开头时
SELECT * FROM employees WHERE first_name LIKE '%ah';
3.复合索引的左前缀原则,当创建复合索引(first_name, last_name),但是使用语句如下所示时不会触发索引优势
SELECT * FROM employees WHERE last_name = 'Smith';
正确的应该是
SELECT * FROM employees WHERE first_name = 'Sahrah';
或者
SELECT * FROM employees WHERE first_name="Sahrah" AND last_name = 'Smith';
4.低选择性或者返回数据量过大
SELECT * FROM employees WHERE gender = 'M';
假设 gender 列只有两个值(如 'M' 和 'F'),而且 'M' 的数据占比很高,在这种情况下,即使 gender 上有索引,优化器可能会认为全表扫描更高效,因为索引过滤的效果不明显
5.OR条件中部分无索引,假设 first_name 有索引,而 last_name 没有,MySQL 使用OR条件的时候无法通过索引合并高效地执行查询,而最终选择全表扫描
SELECT * FROM employees WHERE first_name="Sahrah" OR last_name = 'Smith';
6.数据类型不匹配
SELECT * FROM employees WHERE CAST(employee_id AS CHAR) = '123';
即使 employee_id 是一个有索引的整数列,通过 CAST() 将其转换为字符类型后,原有的索引顺序就失去了作用,优化器因此不能利用该索引
7.表达式运算
SELECT * FROM employees WHERE salary + bonus > 5000;
即使 salary 或 bonus 分别有索引,这个由运算生成的值不能直接对应到索引结构,因此索引不会被用于该条件的过滤