应让过滤后结果集最小的表作驱动表,而非物理小表;explain中rows小且type为ref/range/eq_ref的表才是有效驱动表,key为null或type=all说明索引失效或误判。

应该,但不是“只要小表放前面就自动生效”,而是必须让优化器真正选中小表作驱动表——否则写法再对也白搭。
EXPLAIN 里怎么看哪张表是驱动表
别猜,直接看 EXPLAIN 输出的 rows 和 type 列:
-
rows值明显小的那张表,大概率是驱动表(外层) -
type是ALL或index且rows接近全表行数 → 这张表很可能是被驱动表(内层),正在被反复扫描 -
key为NULL或没命中索引 → 即使是小表,也可能因索引失效被迫全扫,失去“轻驱动”优势
小表驱动失效的典型写法陷阱
这些操作会让优化器“看不懂”小表,甚至把它当成重表来用:
-
SELECT *:触发回表或宽字段读取,小表物理体积暴涨,驱动成本翻倍 -
WHERE UPPER(name) = 'ABC':函数导致小表索引失效,只能全表扫描 -
ON a.id = b.user_id但a.id是INT、b.user_id是VARCHAR:隐式类型转换让任一端索引失效 -
LEFT JOIN big_table ON ...把小表放右边:左表固定驱动,小表被动全扫
真正可控的强制手段有哪些
当统计信息不准、数据倾斜或优化器持续误判时,得主动干预:
- MySQL 用
STRAIGHT_JOIN:写在SELECT后,强制按 FROM 表顺序执行,small_table STRAIGHT_JOIN big_table - Hive 必须开
SET hive.auto.convert.join=true,且确保小表压缩后 ≤ 150MB(默认阈值) - 给小表建覆盖索引:
CREATE INDEX IX_small_status_id ON small_table (status) INCLUDE (id),避免回表 - Java 应用层可先查出小表 ID 列表,再用
IN或临时表方式关联大表,绕过 JOIN
LEFT JOIN / RIGHT JOIN 下的小表位置逻辑
这类 JOIN 的驱动方向是语法固定的,不能靠“换顺序”解决:
-
LEFT JOIN:左表永远是驱动表 → 小表必须放左边 -
RIGHT JOIN:右表永远是驱动表 → 小表必须放右边 -
INNER JOIN:顺序有暗示作用,但不保证;真正起效的是索引 + 统计信息 + 是否显式STRAIGHT_JOIN
最常被忽略的一点:所谓“小表”,不是看原始行数,而是看经过 WHERE 过滤后实际参与 JOIN 的结果集大小。一张千万行的表,加了强过滤条件后可能只剩几十行——它才是真正的驱动候选。别只盯着 SHOW TABLE STATUS 里的 Rows 字段。










