17370845950

SQL 为什么小表 JOIN 大表更快?
小表JOIN大表更快,关键在于小表作驱动表可减少外层循环次数,配合大表连接字段的索引实现高效查找,降低总匹配开销、提升缓存命中率,并优化I/O性能。

小表 JOIN 大表更快,核心在于数据库执行连接时的算法机制和资源利用效率。它不是靠“表小所以快”的直觉,而是由嵌套循环连接(Nested Loop Jo

in)的执行逻辑、索引配合、内存与 I/O 特性共同决定的。

减少外层循环次数,压低总匹配开销

数据库大多采用嵌套循环方式处理 JOIN:外层表每读一行,就去内层表中查找匹配项。

  • 若大表作驱动表(如 100 万行),外层要循环 100 万次,每次查小表(如 1000 行)→ 总比较量 ≈ 100 万 × 1000 = 10 亿次
  • 若小表作驱动表(1000 行),外层只循环 1000 次,每次查大表 → 总比较量仍是 1000 ×(平均匹配行数),但关键在于:只要大表连接字段有索引,单次查找是 O(log n),不是全表扫

被驱动表必须有索引,否则优势归零

小表驱动大表的前提是:大表上用于 JOIN 的字段(如 order.user_id)必须有有效索引。

  • 有索引时,每次根据小表的一条记录去大表定位,只需走 B+ 树几层,毫秒级完成
  • 没索引时,每次都要扫描整个大表,1000 次 × 全表 100 万行 = 同样 10 亿行扫描,和谁驱动没区别
  • 所以“小表驱动”真正快的是“小表行数少 + 大表索引快查”的组合效果

更友好地利用缓存与磁盘 I/O

小表数据量小,更容易被整个加载进内存缓冲池(如 InnoDB Buffer Pool):

  • 驱动表在内存中反复访问,几乎没有磁盘读取
  • 被驱动表虽大,但借助索引随机读取,局部性好,命中率高
  • 反之,大表驱动会导致大量顺序/随机 I/O,缓存频繁换入换出,拖慢整体响应

实际“小表”看的是过滤后结果集,不是原始行数

别机械数表里有多少行。真正该当驱动表的,是 经过 WHERE 条件筛选后行数最少的那个表

  • 比如 orders 表有 500 万行,但加了 WHERE created_at > '2026-01-01' 后只剩 2000 行
  • users 表只有 10 万行,却没有任何过滤
  • 此时 orders 才是事实上的“小表”,应优先驱动