关闭 prefer_ordering_index 不一定能避免 Using filesort,但大概率可以,关键看 WHERE 过滤性是否远高于 ORDER BY 字段选择性;实操需用 EXPLAIN FORMAT=JSON 对比 sort_cost 与 table_scan_cost,并确认 filtered >30%。

prefer_ordering_index 关闭能避免 Using filesort 吗
不一定,但大概率可以。关键看 WHERE 条件的过滤性是否远高于 ORDER BY 字段的选择性。比如 status='shipped' 过滤掉 80% 行,而 create_time 是时间戳、分布密集,优化器默认开启 prefer_ordering_index=on 就会倾向走 idx_create_time 索引,结果扫描大量无关行再回表+排序,Extra 显示 Using filesort。关闭后,优化器把排序成本权重从 ×1.5 降到 ×0.5,更愿意选 idx_status 先筛数据,哪怕后续要排序——因为排序 100 行比扫描 10 万行再回表便宜得多。
实操建议:
- 用
EXPLAIN FORMAT=JSON对比开关前后query_block下的sort_cost和table_scan_cost变化 - 确认
filtered值是否显著高于 10%(比如 >30%),这是关闭该参数的强信号 - 注意:仅对含 WHERE + ORDER BY 的查询生效;纯 ORDER BY 或纯 WHERE 不触发此权衡
optimizer_switch 里哪些成本相关开关值得动
MySQL 8.0 的 optimizer_switch 是个逗号分隔字符串,真正影响成本估算的开关不多,乱开反而容易破坏默认平衡。重点关注这三个:
-
prefer_ordering_index=off:如上所述,解决“排序索引 vs 过滤索引”误判 -
condition_fanout_filter=on(默认开):让优化器在估算多条件 AND 时,考虑条件间相关性,避免把status='shipped' AND user_id IN (1,2,3)的行数简单相乘 -
use_index_extensions=on(默认开):允许优化器使用二级索引扩展(即隐式包含主键),这对覆盖扫描和排序有实际影响,关了可能让Using index消失
别碰 index_merge、derived_merge 这类逻辑重写开关——它们不调成本,只改语义,风险高且与执行计划稳定性无关。
直方图比调参数更能救回错选索引吗
是的,而且更安全。参数调整是全局或会话级的“粗调”,直方图是针对单列的“精调”。当某列(比如 status)值分布严重倾斜(95% 是 'pending',其余 5% 均匀分布在 10 个状态),统计信息里的 cardinality 会严重失真,导致 filtered 估算错误(比如把 status='shipped' 估成 50%,实际只有 0.5%)。这时关 prefer_ordering_index 可能没用——优化器压根没意识到这个条件有多高效。
实操建议:
- 对 WHERE 中高频、分布歪的列建直方图:
ANALYZE TABLE orders UPDATE HISTOGRAM ON status WITH 64 BUCKETS; - 直方图不影响 DML 性能,只增少量元数据存储;但必须配合
ANALYZE TABLE才生效,不是建完就立刻起效 - 验证方式:查
INFORMATION_SCHEMA.COLUMN_STATISTICS看histogram字段非空,再跑EXPLAIN看filtered是否贴近真实比例
成本模型参数修改后必须 ANALYZE TABLE 吗
不必须,但强烈建议。参数只改优化器“怎么算”,统计信息决定“算什么”。比如你刚把 prefer_ordering_index 关了,但 orders 表上周批量更新了 20% 订单状态,innodb_stats_auto_recalc 默认异步触发,可能还没跑完;此时优化器拿着过期的行数、基数去算新成本,结果还是错的。一个 ANALYZE TABLE orders 能强制重采样,让 rows 和 filtered 回到现实。
注意点:
-
ANALYZE TABLE是轻量操作,InnoDB 默认只采样 20 页,一般秒级完成 - 生产环境避开高峰期执行;若表极大,可设
innodb_stats_persistent_sample_pages=100提高采样精度(代价是ANALYZE时间略长) - 直方图也依赖
ANALYZE TABLE ... UPDATE HISTOGRAM,不能靠自动重算
最易被忽略的是:成本模型参数和统计信息是两层东西。调了参数却忘了更新统计,等于给计算器换了公式,但还用着去年的账本——数字再漂亮,也算不准当下这笔账。


















