标准答案
- 避免在索引列外层套函数,例如 DATE(created_at);应改为明确的时间范围条件。
- 字段类型与参数类型要一致,字符串与数字、不同字符集或日期格式的隐式转换可能改变比较方向并放弃索引。
- LIKE "%keyword" 缺少固定前缀,普通 B+ 树无法有效缩小范围;全文检索需求应使用合适的搜索索引。
- 对列做算术、OR 组合或非 SARGable 表达式时,要检查能否改写为可检索范围或拆分查询。
- 索引没有被选择也可能是选择性太差、统计信息错误或返回行过多,不能只归咎于 SQL 语法。
题目解析
所谓“索引失效”并不总是完全不用索引,更常见是索引不能把扫描范围缩小到足够小,优化器选择全表扫反而更便宜。排查时应看实际访问行数、过滤比例和执行计划,而不是只看有没有出现 key 名称。
改写 SQL 的目标是保留列的原始可排序性。例如查某一天的数据,应把日期转换到常量一侧,使用 [当天开始, 次日开始) 的范围,而不是逐行对 created_at 求日期。
常见误区
- 把所有未命中索引的问题都用 FORCE INDEX 压过去,掩盖数据分布或查询设计问题。
- 为了避免函数条件在应用层拉回全量数据再过滤,造成更大的网络和内存开销。