思考
最左匹配
join字符集
函数
null @定义字段 not null default ""
or @union all
like
字段区分度不大
+++++
!=
not in @between
varchar类型数字型,查询不是字符串查询
MySQL 索引失效的常见场景
MySQL 索引失效会导致查询性能急剧下降,以下是索引失效的主要场景及其原理分析:
1. 违反最左前缀原则
场景:复合索引未从最左列开始使用
sql
-- 复合索引为 (a, b, c) WHERE b = 1 AND c = 2 -- 索引失效 WHERE a = 1 AND c = 2 -- 只用到a列索引
原理:复合索引按照从左到右的顺序建立B+树结构
2. 对索引列进行计算或函数操作
场景:对索引字段进行运算或函数处理
sql
-- 索引列:create_time WHERE YEAR(create_time) = 2023 -- 索引失效 WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31' -- 有效 -- 索引列:age WHERE age + 1 > 20 -- 索引失效 WHERE age > 19 -- 有效
3. 使用不等于(!= 或 <>)
场景:使用不等于条件
sql
-- 索引列:status WHERE status != 1 -- 索引失效
例外:覆盖索引时可能仍会使用索引
4. 使用 IS NULL 或 IS NOT NULL
场景:判断NULL值
sql
-- 索引列:name WHERE name IS NULL -- 可能失效(取决于数据分布)
优化:设置默认值替代NULL
5. 使用LIKE以通配符开头
场景:模糊查询
sql
-- 索引列:title WHERE title LIKE '%关键字%' -- 索引失效 WHERE title LIKE '关键字%' -- 可以使用索引
6. 隐式类型转换
场景:字段类型与条件值类型不一致
sql
-- 索引列:mobile(varchar) WHERE mobile = 13800138000 -- 索引失效(数字转字符串) WHERE mobile = '13800138000' -- 有效
7. 使用OR条件不当
场景:OR连接非索引列
sql
-- 索引列:a WHERE a = 1 OR b = 2 -- 索引失效(如果b无索引)
优化:改用UNION ALL
sql
SELECT * FROM table WHERE a = 1 UNION ALL SELECT * FROM table WHERE b = 2
8. 索引列使用NOT IN
场景:否定条件查询
sql
-- 索引列:id WHERE id NOT IN (1, 2, 3) -- 索引失效
替代方案:
sql
WHERE id < 1 OR id > 3 -- 可能使用索引
9. 数据分布不均匀
场景:索引列值区分度低
sql
-- 索引列:gender(只有'M','F'两种值) WHERE gender = 'M' -- 可能放弃索引(全表扫描更快)
解决方案:建立复合索引提高区分度
10. 使用ORDER BY不当
场景:排序字段与索引顺序不一致
sql
-- 索引(a, b) ORDER BY b, a -- 索引失效
11. JOIN条件字符集不匹配
场景:关联字段字符集不同
sql
-- table1.utf8_col JOIN table2.latin1_col -- 索引失效
12. 索引列使用表达式
场景:索引列参与表达式
sql
-- 索引列:price WHERE price * 0.8 > 100 -- 索引失效 WHERE price > 100 / 0.8 -- 有效
检测索引是否失效的方法
EXPLAIN分析:
sql
EXPLAIN SELECT * FROM table WHERE ...
查看
type
列:ref
/range
:使用索引ALL
:全表扫描
开启优化器跟踪:
sql
SET optimizer_trace="enabled=on"; SELECT * FROM table WHERE ...; SELECT * FROM information_schema.optimizer_trace;