首页/数据/数据库速查/连表顺序与驱动表选择
性能与调优57 条

连表顺序与驱动表选择

优化器按成本选驱动表:小结果集先驱动、被驱动表走索引是理想形;驱动表选错(统计失真)时可用 STRAIGHT_JOIN 临时纠偏并分析根因。

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

驱动表是怎么选的

多表连接时优化器按成本模型挑驱动表,理想形态是小结果集做驱动表、被驱动表通过索引做等值查找。当统计信息失真或写法特殊时,优化器可能选大表驱动并对被驱动表做全表扫描,执行计划因此急剧恶化。此时可以短期用 STRAIGHT_JOIN 纠偏,但根因通常是被驱动表缺索引或统计陈旧。

基本信息

适用MySQL 5.7 / 8.0,重点关注 JOIN 查询
判断入口EXPLAIN 输出顺序、type、rows、Extra 列
纠偏手段STRAIGHT_JOIN、optimizer hint(JOIN_ORDER 等)
根因治理补索引、更新统计信息、改写过滤条件

观察与纠偏

观察与纠偏
-- 观察顺序:EXPLAIN 里先出现的表为驱动表
EXPLAIN SELECT o.id FROM appdb.users u JOIN appdb.orders o ON o.user_id = u.id WHERE u.city='Hangzhou'\G
-- 检查被驱动表的访问类型:目标应为 ref 或 eq_ref,而非 ALL
EXPLAIN FORMAT=JSON SELECT o.id FROM appdb.users u JOIN appdb.orders o ON o.user_id = u.id WHERE u.city='Hangzhou'\G
-- 临时强制顺序(谨慎使用,仅用于验证假设)
SELECT STRAIGHT_JOIN o.id FROM appdb.orders o JOIN appdb.users u ON o.user_id = u.id WHERE u.city='Hangzhou';
ANALYZE TABLE appdb.orders;   # 统计信息陈旧时先更新再重新评估计划

计划质量判断

观察项理想情况异常表现
输出顺序过滤后行数少的表在前大表做驱动表,后续步骤反复扫描
被驱动表 typeref 或 eq_refALL 全表扫描,成本随行数放大
rows 估算与实际数量接近估算严重偏小,导致选错顺序
ExtraUsing index / Index lookupUsing join buffer、Using temporary 说明无法走索引
join buffer 使用越少越好大量 BNL 连接,内存换时间的信号

典型使用场景

  • 慢 JOIN 排查:确认驱动表是否选错,被驱动表是否走得动索引
  • 新增索引后验证计划是否按预期改变
  • 历史数据分布变化导致计划退化,先更新统计再评估
  • 分页查询在大偏移量下变慢,检查连接与排序的组合
  • 上线前评审:把连接顺序与访问类型纳入 SQL 审查清单
连接顺序是优化器基于成本的结果而不是原因:被驱动表缺索引才是根本问题,先补索引再做其他调整通常一步到位。
把 STRAIGHT_JOIN 长期固化在业务 SQL 里风险很高:数据分布一变,写死的顺序反而更慢,它只适合作为临时验证手段。

易错点

  • 只调大 join_buffer_size:扫描量没有变化,只是用内存换取更少的重复扫描,掩盖了缺索引问题
  • STRAIGHT_JOIN 固化进业务代码:表数据量或分布变化后计划更差,且不易被发现
  • 统计信息陈旧不更新:估算行数偏差导致选错驱动表,先 ANALYZE TABLE 再谈优化
  • 忽略过滤条件的类型:条件列发生隐式类型转换会导致索引失效,连接顺序再对也快不起来

数据来源与参考

  • MySQL 8.0 Reference Manual: Optimizing JOIN Queries
  • MySQL 8.0 Reference Manual: STRAIGHT_JOIN

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌