SQL WHERE 条件组合优化实战案例

6次阅读

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

SQL WHERE 条件组合优化实战案例

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(尤其当时间范围太大时,可能全表扫描)
  • 检查方式:用 EXPLAINkeyrows,确认是否命中复合索引的最左前缀

复合索引字段顺序必须和 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) = 2024WHERE 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 或补全业务语义
text=ZqhQzanResources