sql where条件应先写等值条件再写范围条件,且顺序须与复合索引最左前缀严格匹配;避免字段计算、隐式转换及高比例null判断,否则导致索引失效或全表扫描。

SQL WHERE 条件组合写得不合理,轻则拖慢查询,重则让数据库直接卡死。优化核心不是堆索引,而是让条件顺序和索引结构真正匹配执行计划。
WHERE 中等值条件优先,放最前面
数据库优化器通常优先用等值条件(=、IN、IS NULL)定位数据范围,再用范围条件(>、)过滤。如果把 create_time > '2024-01-01' 放最前,而 status = 1 放后面,即使 status 字段有索引,也可能被跳过。
- ✅ 推荐写法:
WHERE status = 1 AND type IN ('A','B') AND create_time > '2024-01-01' - ❌ 风险写法:
WHERE create_time > '2024-01-01' AND status = 1(尤其当时间范围太大时,可能全表扫描) - 检查方式:用
EXPLAIN看key和rows,确认是否命中复合索引的最左前缀
复合索引字段顺序必须和 WHERE 等值条件严格对齐
比如表上有索引 INDEX idx_status_type_ct (status, type, create_time),那只有 WHERE 含 status = ? 才能触发该索引;若只写 type = ? 或 create_time > ?,这个索引基本无效。
- 等值条件字段要连续且靠左:支持
status=1 AND type='A',也支持status=1单独使用 - 范围条件只能放在等值之后:如
status=1 AND type='A' AND create_time > '2024-01-01'可用全部三列;但status=1 AND create_time > '2024-01-01'只能用到 status 列 - IN 是特殊情况:可视为多个等值,仍算“等值条件”,但元素过多(如 IN(1000个值))会退化,建议拆分或改用临时表
避免在 WHERE 字段上做计算或函数操作
WHERE YEAR(create_time) = 2024 或 WHERE UPPER(name) = 'ABC' 会让索引完全失效——数据库无法用索引树直接比对结果,只能全表扫描后逐行计算。
- ✅ 改成范围写法:
create_time >= '2024-01-01' AND create_time - ✅ 函数操作可前置:如需大小写不敏感匹配,建函数索引(MySQL 8.0+)或加生成列索引,而不是 WHERE 里调 UPPER()
- 注意隐式类型转换:
WHERE mobile = 13812345678(mobile 是 VARCHAR)会触发全表扫描,应写成字符串'13812345678'
NULL 判断要谨慎,尽量用默认值替代
WHERE deleted_at IS NULL 看似合理,但如果该字段 NULL 值占比极高(比如 95%),索引区分度极低,优化器很可能弃用索引走全表扫描。
- 更高效做法:业务层约定未删除为
deleted_at = '1970-01-01',删除时设为真实时间,WHERE 改为deleted_at = '1970-01-01',配合索引效果显著 - 真要用 IS NULL:确保该字段在索引中靠前,且 NULL 值比例不高;或搭配其他高区分度等值条件共同使用
- 避免混合写法:
WHERE status = 1 OR status IS NULL极难优化,尽量拆成 UNION 或补全业务语义









