首页/数据/SQL 速查/EXPLAIN 中的表访问顺序
性能与执行计划72 条

EXPLAIN 中的表访问顺序

多表连接时 EXPLAIN 按访问顺序逐行列出:同 id 的行属于同一查询块,自上而下就是连接发生顺序。

SQL 速查数据更新于 2026-10-13

计划里的表访问顺序

多表连接的经典计划输出是一张文字表格,每个表占一行,行的先后顺序就是优化器决定的访问顺序:排在前面的先被读取并产出连接键,排在后面的按索引逐行查找。判断顺序不能看 SQL 里 FROM 的书写次序,优化器会按代价重排。另外要注意编号列:编号相同的行属于同一个查询块,编号不同则分属不同的子查询或集合运算分支,跨编号谈顺序没有意义。

基本信息

适用平台MySQL 8.0 / PostgreSQL 12 及以上
顺序判定同一查询块内,行序即访问顺序,自上而下
编号含义查询块标识,子查询与集合运算会引入新编号
关注字段访问类型、用到的索引、估算行数、额外信息
新版变化MySQL 8.0.18 起另有树形格式的分析输出,信息更细

典型使用场景

  • 确认哪张表被当作驱动表,是否符合数据分布预期
  • 排查连接慢:看被驱动表的访问方式是否退化成全表扫描
  • 验证索引是否被使用,以及用的是不是预期的那个索引
  • 对比改写前后的计划差异,评估改写是否真的有效
  • 归档慢查询证据,供后续复盘与容量评估使用

读计划的顺序

读计划的顺序
EXPLAIN
SELECT u.name, o.total
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE u.city = 'shanghai' AND o.status = 'paid';
-- 输出中 users 行在上、orders 行在下:
--   先访问 users(驱动侧),再按连接键查 orders
-- 反向顺序也常出现:优化器认为 orders 过滤后更小就会调换

-- 需要更细的执行信息时用分析模式(会真实执行语句)
EXPLAIN ANALYZE
SELECT u.name, o.total
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE u.city = 'shanghai' AND o.status = 'paid';

-- 干预顺序的手段(MySQL 可指定强制连接顺序,PostgreSQL 可调整连接重排上限)

关键列读法

列含义异常信号
编号列查询块编号跨编号比较顺序得出的结论通常是错的
表名列本次访问的对象出现衍生表或临时表说明存在物化步骤
访问类型单行、索引、范围、全表出现全表扫描且行数大时要重点看
索引列实际选用的索引显示未用索引说明条件无法利用现有索引
估算行数预计扫描行数与真实行数差一两个数量级说明统计信息失真
额外信息排序、临时表、下推等提示出现临时表与排序说明中间结果较大
驱动表的选择不是越小的表越好,而是「过滤之后产出行数最少」的一侧更适合当驱动。判断依据是过滤后的估算行数,而不是表的原始大小。
分析模式会真实执行语句,涉及写操作时务必先改写成等价的查询,或在事务里执行后回滚,不要在生产环境直接跑。

易错点

  • 按 SQL 书写顺序推断执行顺序:优化器会重排连接顺序,必须以计划输出为准
  • 把不同编号的行混在一起读,得出「先访问某表」的错误结论,跨查询块的行没有先后关系
  • 只看访问类型不看估算行数,漏掉「走了索引但扫描行数巨大」的隐性问题
  • 在生产直接运行分析模式跑更新语句,语句真实执行造成数据变更
  • 计划看着没问题就认为线上也如此:参数与数据分布不同会让计划完全不同,要用生产参数复现

数据来源与参考

  • MySQL 8.0 Reference Manual §8.8.2 EXPLAIN Output Format
  • PostgreSQL Documentation §14.1 Using EXPLAIN
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌