mysql无固定代价公式,需通过explain的type、rows、key、extra等字段反推优化逻辑;驱动表选择、索引对齐、统计信息更新是影响join成本的关键因素。

MySQL 不对外暴露代价评估的完整数学公式,它的成本模型是内部实现、动态估算且随版本演进调整的;你无法用一个固定公式算出“这个 JOIN 代价是 1234”,但可以通过 EXPLAIN 输出的关键字段反推优化器的判断逻辑。
看懂 EXPLAIN 中的 cost 相关字段
MySQL 8.0+ 在 EXPLAIN FORMAT=TREE 或 EXPLAIN ANALYZE 中会显示估算成本(cost),但更稳定、通用的是传统 EXPLAIN 的几列:
-
type:连接类型,从system→const→eq_ref→ref→range→index→ALL,越靠后扫描行数越多、成本越高 -
rows:优化器预估需要扫描的行数(不是结果行数),该值乘以每行平均 IO 开销是成本主因 -
key和key_len:是否命中索引、用了索引的前几字节,没索引或索引失效(如类型不匹配、函数包裹)会导致type=ALL和rows暴涨 -
Extra中出现Using filesort或Using temporary是高成本信号,意味着额外排序或内存/磁盘临时表
驱动表选择直接影响总 cost
MySQL 使用嵌套循环连接(Nested Loop Join),外层表(驱动表)决定内层表被探测的次数。总代价 ≈ 驱动表扫描行数 × 内层表单次探测平均开销。所以:
- 优先让过滤性最强的表做驱动表(比如加了
WHERE order_time > '2026-05-01'的orders表) - 避免用大表驱动小表:若
users有 1000 万行、orders有 50 万行,LEFT JOIN orders ON users.id = orders.user_id可能比反过来慢几个数量级 -
STRAIGHT_JOIN可强制连接顺序,但仅在你确认优化器选错时使用,否则可能掩盖真实问题
JOIN 条件字段的索引与类型必须严格对齐
即使写了 ON a.id = b.user_id,只要存在以下任一情况,优化器就大概率放弃走索引、退化为全表扫描:
- 两字段类型不一致(如
a.id是BIGINT,b.user_id是INT) - 其中一列上有函数或表达式(如
ON DATE(o.created_at) = '2026-06-01') - 字符集或排序规则不同(如
utf8mb4_0900_as_csvsutf8mb4_general_ci) - 关联字段未单独建索引,或复合索引未满足最左前缀(例如
INDEX(status, user_id)无法加速ON user_id = ?)
别信“理论上应该快”,先看 EXPLAIN 的 rows 和 type
很多开发者按业务直觉写 JOIN 顺序,比如“用户是主实体,当然放左边”,但优化器只认数据分布和索引。真正卡住性能的,往往不是语法多复杂,而是某张表看似只查几十行,EXPLAIN 却显示 rows=2800000 —— 这说明它根本没走索引,或者统计信息过期。
执行 ANALYZE TABLE table_name 更新统计信息,再看 EXPLAIN,有时比重写 SQL 更快见效。代价评估不是玄学,但它藏在 rows 里,不在你的 SELECT 语句里。











