MySQL EXPLAIN 执行计划分析:能否查看 JOIN 关联顺序

你们知道 EXPLAIN 是否能看出 MySQL 的 JOIN 关联顺序? 结论是:完全可以 ,而且 EXPLAIN 是查看、分析 MySQL JOIN 关联顺序的核心、最常用手段,没有之一。


一、核心结论:EXPLAIN 中 JOIN 关联顺序的核心规则

✅ 规则1:EXPLAIN 结果的行展示顺序 = MySQL 实际执行的 JOIN 关联顺序

EXPLAIN 执行后会返回一个结果集(多行数据),MySQL 是「从下往上」执行 JOIN 关联的,这个顺序是绝对的核心,记住这个口诀:

EXPLAIN 结果越靠后的行 ,是 MySQL 执行 JOIN 时先访问的表(驱动表);

EXPLAIN 结果越靠前的行 ,是 MySQL 执行 JOIN 时后访问的表(被驱动表)。

✅ 规则2:驱动表 & 被驱动表的定义(理解关联顺序的前提)

  • 驱动表 (driving table) :JOIN 关联时先被加载、先被扫描的表,MySQL 会用驱动表的每条数据,去匹配另一张表的数据;
  • 被驱动表 (driven table) :JOIN 关联时后被加载、被匹配的表,也叫「匹配表」;
  • 驱动表的选择,是 MySQL 优化器的核心逻辑之一,小表(数据量少、过滤后结果集小)优先作为驱动表,这是最优的 JOIN 执行策略。

二、最直观案例:一眼看懂 JOIN 关联顺序

案例表准备

有两张常见业务表,做 JOIN 查询:

sql 复制代码
-- 订单表(数据量较大,假设10万条)
CREATE TABLE `order` (
  id INT PRIMARY KEY,
  user_id INT,
  order_no VARCHAR(32),
  KEY idx_user_id (user_id)
);
-- 用户表(数据量较小,假设1万条)
CREATE TABLE `user` (
  id INT PRIMARY KEY,
  name VARCHAR(32),
  age INT
);

执行 JOIN 查询+EXPLAIN

sql 复制代码
EXPLAIN SELECT o.*, u.name FROM `order` o LEFT JOIN `user` u ON o.user_id = u.id;

EXPLAIN 结果(核心关注 table 列)

假设 EXPLAIN 返回 2行结果table 列展示如下:

id select_type table type ...
1 SIMPLE o ALL ...
1 SIMPLE u ref ...

关联顺序解读

EXPLAIN 结果里,行1是表 o(order)、行2是表 u(user),根据「从下往上执行」的规则:

✅ MySQL 实际执行顺序:先查 user 表(驱动表) → 再查 order 表(被驱动表)

补充:哪怕你写的是 order LEFT JOIN user,MySQL 优化器会自动调整顺序,因为 user 是小表,做驱动表效率更高!


三、EXPLAIN 中判断 JOIN 的两个核心关键字段(必看)

EXPLAIN 的结果有很多列,判断是否是 JOIN 查询、以及 JOIN 关联的匹配方式,只需要重点看 2 个关键字段,缺一不可:

✅ 字段1:type 列 - 关联匹配的「访问类型」

type 列代表 MySQL 对表的访问/匹配方式只要是 JOIN 查询,被驱动表的 type 字段一定会出现 ref / eq_ref 这两个值之一,这是 JOIN 的「身份标识」。

  • eq_ref:最优的 JOIN 匹配,一对一匹配(比如关联主键/唯一索引),性能极高;
  • ref:非常好的 JOIN 匹配,多对一匹配(比如关联普通索引),性能也很好;

补充:如果 JOIN 的被驱动表 typeALL,说明是「笛卡尔积匹配/全表扫描匹配」,是性能极差的 JOIN,必须优化(加索引)。

✅ 字段2:possible_keys/key 列 - JOIN 用的索引

  • possible_keys:MySQL 认为可以用来做 JOIN 关联的索引(候选索引);
  • key:MySQL 最终实际选用的 JOIN 关联索引(核心字段);

关键优化点:如果 JOIN 查询的 key 列是 NULL,说明 MySQL 没有用到任何索引做关联,就是上面说的「全表扫描 JOIN」,一定要给 JOIN 的关联字段(如 o.user_id/u.id)加索引。


四、多表 JOIN 场景:3表/多表的关联顺序怎么看?

如果是 3 张及以上表的 JOIN,规则完全不变,还是遵循:

EXPLAIN 结果 从下往上 执行,后行 = 先行执行(驱动表),前行 = 后执行(被驱动表)

案例:3表 JOIN

sql 复制代码
EXPLAIN SELECT o.*, u.name, g.goods_name 
FROM `order` o 
LEFT JOIN `user` u ON o.user_id = u.id
LEFT JOIN `goods` g ON o.goods_id = g.id;

EXPLAIN 结果(table列):3行

行1 → table: o

行2 → table: g

行3 → table: u

实际执行顺序

第一步 :先访问 u 表(最下行,驱动表1)

第二步 :用 u 表的数据关联访问 g 表(中间行,被驱动表1、驱动表2)

第三步 :用 u+g 关联的结果,关联访问 o 表(最上行,被驱动表2)

总结:不管多少表 JOIN,只需要把 EXPLAIN 的结果行倒序看,就是完整的执行顺序!


五、MySQL 会不会「自己调整 JOIN 关联顺序」?

✅ 重要结论:会的!而且是常态!

你在 SQL 语句中书写的 JOIN 表顺序不等于 MySQL 实际执行的 JOIN 顺序!

核心原因:MySQL 有「JOIN 优化器(关联顺序优化)」

MySQL 的优化器会基于「成本估算」,自动调整 JOIN 的关联顺序,核心原则是:

优先选择「小表/过滤后结果集最小的表」作为驱动表

因为驱动表越小,需要循环匹配的次数越少,JOIN 的整体执行效率越高。

比如你写的是 大表 JOIN 小表,MySQL 优化器会自动调整为 小表 JOIN 大表,这也是为什么我们不用刻意纠结 SQL 中 JOIN 的书写顺序的原因。


六、如何强制 MySQL 按照「我写的顺序」执行 JOIN?

如果某些特殊场景下,你确定自己写的 JOIN 顺序比 MySQL 优化器选的更优,想要禁用优化器的关联顺序调整,强制按 SQL 书写顺序执行 JOIN,有 2 种可靠方法:

✅ 方法1:使用 STRAIGHT_JOIN 关键字(推荐,轻量)

STRAIGHT_JOINJOIN 的「强制顺序版」,功能和 JOIN 完全一致,唯一区别是:强制 MySQL 按照 SQL 中书写的表顺序执行 JOIN,不做任何调整

语法:把 SQL 中的 JOIN 替换成 STRAIGHT_JOIN 即可。

sql 复制代码
-- 强制:先查 order 表 → 再查 user 表,完全按书写顺序执行
EXPLAIN SELECT o.*, u.name FROM `order` o STRAIGHT_JOIN `user` u ON o.user_id = u.id;

✅ 方法2:关闭优化器的关联顺序优化(不推荐,全局生效)

通过设置 MySQL 会话参数关闭优化器,会影响所有查询,谨慎使用:

sql 复制代码
-- 关闭关联顺序优化
SET optimizer_switch='join_cache_bka=off';
-- 执行你的 JOIN 查询
EXPLAIN SELECT o.*, u.name FROM `order` o JOIN `user` u ON o.user_id = u.id;
-- 用完建议恢复默认
SET optimizer_switch='join_cache_bka=on';

✨ 全文核心知识点总结(必记)

  1. EXPLAIN 可以精准查看 MySQL JOIN 的关联顺序,是核心分析工具;
  2. JOIN 关联顺序核心规则:EXPLAIN 结果 从下往上执行,后行是驱动表(先执行),前行是被驱动表(后执行);
  3. 判断 JOIN 的 2 个核心字段:type 列(必为 ref/eq_ref)+ key 列(非 NULL 代表用到关联索引);
  4. 多表 JOIN 规则不变,倒序看 EXPLAIN 结果就是执行顺序;
  5. MySQL 会自动调整 JOIN 顺序(小表优先做驱动表),无需手动调整书写顺序;
  6. 强制按书写顺序执行:用 STRAIGHT_JOIN 替换 JOIN 即可。
相关推荐
TianXinCoord2 小时前
SpringBoot+MyBatis Plus+PostgreSQL整合常用数据类型(json、array)操作
后端
micromicrofat2 小时前
【MongoDB】WSL2访问宿主机的MongoDB
数据库·mongodb
两拆2 小时前
Redhat7.9安装部署Oracle 19C
数据库·oracle
TDengine (老段)2 小时前
TDengine 企业用户建表规模有多大?
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
程序员爱钓鱼3 小时前
用Python开发“跳一跳”小游戏——从零到可玩
后端·python·面试
程序员爱钓鱼3 小时前
Python 源码打包成.whl文件的完整指南
后端·python·面试
IT_陈寒3 小时前
Vite 3.0 实战:5个优化技巧让你的开发效率提升50%
前端·人工智能·后端
、BeYourself3 小时前
Spring AI ChatClient 响应处理
后端·ai·springai
FIT2CLOUD飞致云3 小时前
操作教程丨通过1Panel轻松安装和管理MySQL开源数据库
linux·运维·服务器·mysql·开源·1panel