开放问答
WHERE 走 idx_trace_id、ORDER BY 想走 (trace_id, ts) 复合索引,优化器偏要 filesort,怎么判
该问题的正文、回答与评论。
提问者 陈清和-122 · 状态 open
MySQL优化器复合索引filesortFORCE INDEX
背景:MySQL 8.0.32 / InnoDB,一张约 1.8 亿的链路追踪明细表 trace_detail,字段:id (bigint 自增 PK)、trace_id (varchar(32))、span_name (varchar(64))、ts (datetime(3))、duration (int)、status (tinyint)。现有索引:idx_trace_id (trace_id)、idx_trace_ts (trace_id, ts)。
现象:业务侧按 trace_id 拉最近 N 条 span 的查询长这样——
SELECT id, span_name, ts, duration FROM trace_detail WHERE trace_id = 'abc-...' ORDER BY ts DESC LIMIT 50
EXPLAIN 显示 key = idx_trace_id、type = ref、rows ≈ 40,Extra = Using filesort。单次耗时 8~30ms,本身不算慢,但这条 SQL 是网关侧高频调用,峰值 800 QPS,慢日志里它排第一。
已尝试与结果:
ANALYZE TABLE trace_detail后再 EXPLAIN,优化器依旧选 idx_trace_id + filesort;- 改成
FORCE INDEX (idx_trace_ts),单次耗时降到 2~4ms,P99 也明显下来,但不敢长期裸用——担心后续 trace_id 基数变化或新增 WHERE 条件后强制索引反而劣化; - 考虑过直接删掉 idx_trace_id 只留复合索引,但表里还有另一条 SQL 只用 trace_id 不带 ORDER BY,删单列索引怕影响那条路径;
- 没有上覆盖索引(span_name/duration 都是变长列,加进去维护成本怕吃不消)。
期望的回答形态:
- 给一个判断标准:什么情况下优化器选「WHERE 索引 + filesort」、什么情况下选「(trace_id, ts) 复合索引、免排序」是更优的?关键变量是 trace_id 的基数、单次命中行数、表规模里的哪一个?
FORCE INDEX长期挂在 SQL 里到底有没有代价?团队里有没有踩过「强制索引在数据分布漂移后变慢」的真实案例?- 如果让我二选一:保留 idx_trace_id + FORCE INDEX,还是删掉 idx_trace_id 只留复合索引,你会怎么选?依据是什么?
- 顺带一句:如果这条 SQL 的 WHERE 后续会扩展成
WHERE trace_id = ? AND status = ?,复合索引列顺序应该怎么摆?
我贴 EXPLAIN 全量结果和 SHOW INDEX 输出在评论区,方便大家直接对号入座。
已采纳
回答者
回答正文
评论
暂无评论。