use index 和 force index 在 mysql 5.7+ 中仅为优化器建议而非强制指令,可能被忽略或反向生效;统计信息陈旧时易导致低效执行计划,应先 analyze table 更新统计信息并结合 explain format=json 验证。

MySQL 的 USE INDEX 或 FORCE INDEX 被优化器忽略或反向生效
MySQL 5.7+ 中,USE INDEX 和 FORCE INDEX 并非强制指令,而只是“建议”。当优化器判断该索引会导致更差的执行计划(比如回表代价远高于全表扫描),它可能仍选择走主键或跳过提示。尤其在统计信息陈旧、行数预估严重偏差时,FORCE INDEX 可能锁死一个低效路径。
常见现象:EXPLAIN 显示 key 是你指定的索引,但 rows 高得离谱,且实际执行耗时比不用提示还长。
- 先用
ANALYZE TABLE table_name;更新统计信息,再测试提示是否真有必要 - 对比
EXPLAIN FORMAT=JSON输出中的considered_execution_plans字段,确认优化器是否真的评估过该索引路径 - 避免对小表(
PostgreSQL 的 SET enable_seqscan = off 强制走索引引发大量随机 I/O
PostgreSQL 没有 SQL 级 Hint 语法(除非用 pg_hint_plan 扩展),但有人会用 SET enable_seqscan = off 全局禁用顺序扫描来“逼”查询走索引。这非常危险:当索引覆盖范围大、数据物理分布稀疏时,数据库需反复寻道读取分散的磁盘页,随机 I/O 延迟远高于顺序扫描连续块。
典型场景:按时间范围查日志表,索引存在但数据跨几十个 GB 文件碎片存储;enable_seqscan = off 后 QPS 断崖下跌,iostat -x 1 显示 %util 接近 100 且 await 极高。
- 永远优先用
EXPLAIN (ANALYZE, BUFFERS)观察实际 I/O 模式(Buffers: shared hit=xxx read=yyy) - 若
read数量远大于hit,说明缓存未命中严重,强制索引大概率是错的 - 改用分区表 + 时间字段分区裁剪,比硬塞索引更有效
Hint 导致优化器放弃更优连接顺序或物化策略
在多表 JOIN 场景下,给某张表加 USE INDEX 可能破坏优化器原本规划的驱动表顺序。例如原计划用小表驱动大表(small_table 为驱动,large_table 上走索引),但提示强制 large_table 用某个低效索引后,优化器被迫将它提前作为驱动表,导致嵌套循环次数暴增。
另一个隐蔽问题:MySQL 对子查询的物化(materialization)仅在 SELECT 中启用,UPDATE/DELETE 不支持。若你在 UPDATE 的子查询部分加了索引提示,反而可能阻止优化器将子查询结果物化为临时表,退化为依赖型子查询(DEPENDENT SUBQUERY),每行外层都重新执行一次子查询。
- 对 UPDATE/DELETE,优先重写为 JOIN 形式,而非依赖子查询 + Hint
- 用
EXPLAIN检查子查询类型:出现DEPENDENT SUBQUERY就说明物化失败 - JOIN 重写示例:
UPDATE t1 JOIN t2 ON t1.id = t2.t1_id SET t1.status = 'done' WHERE t2.flag = 1
索引提示掩盖了真正的问题:过滤性差或回表成本高
最常被忽略的一点:加 Hint 后变慢,往往不是 Hint 本身的问题,而是它暴露了底层索引设计缺陷。比如你在 WHERE status = 'pending' 上建了单列索引,但该值占比 80%,优化器本来就不该用它——你强行 FORCE INDEX,等于让数据库用 B+ 树逐条捞出 80% 的主键再回表,比直接扫主键聚簇索引还多一次树查找和大量随机读。
另一个典型:联合索引 (a, b, c),你写 WHERE b = ? AND c = ? 并加 USE INDEX(a,b,c),但因不满足最左前缀,实际只能走全索引扫描(type: index),而非高效查找(type: ref)。
- 用
EXPLAIN的key_len判断联合索引实际用了几列(例如key_len=4表示只用了第一列 int) - 检查
rows和filtered:若filtered长期低于 10%,说明索引过滤性极差,应考虑删掉或重构 - 对高基数低过滤性的字段(如
gender,status),优先考虑位图索引(PG)或跳过索引(MySQL 8.0+),而非 B+ 树
EXPLAIN 里的 rows、key_len、filtered 和实际执行时的 I/O 模式。











