已采纳
回答正文
回复
讨论正文
该问题的正文与回答。
背景:MySQL 8.0.36,InnoDB,一张约 5000 万行的日志表 access_log,主键 id,二级索引 idx_path (path),idx_path_status (path, status),idx_time (create_time)。日常查询是 SELECT id, path FROM access_log WHERE path = ? AND status = ? LIMIT 20,之前走 idx_path_status 覆盖索引,P99 约 3ms。
现象:
ANALYZE TABLE access_log,information_schema.TABLES 里 TABLE_ROWS 从 5000 万刷到 1000 万,但 EXPLAIN 结果不变,还是选 idx_path;WHERE path = ? AND status = ? AND create_time > '2025-09-01' 的查询,优化器又切回 idx_path_status,说明它"知道"这个索引存在,但在只有 path+status 两个条件时就是不肯选。已尝试:
ANALYZE TABLE access_log(刷新统计信息后 EXPLAIN 不变);SET optimizer_switch='index_merge=off' 排除 index merge 干扰,无变化;FORCE INDEX (idx_path_status) 验证,确实能走对索引,P99 回到 4ms,证明是优化器选错而非索引本身有问题;information_schema.INNODB_TABLE_STATS,n_diff_p000/p001/p010/p100/p111 的值在 ANALYZE 前后有变化,但变化幅度看起来不足以让优化器"换心";想请教:
/*+ INDEX(...) */)、或者调整 innodb_stats_persistent_sample_pages 到某个阈值后一定能纠正?想避免在业务代码里到处塞 FORCE INDEX。ALTER TABLE ... ENGINE=InnoDB 重建、还是直接改查询写法?有没有人踩过类似的坑并给出了稳定方案?