1. 什么是「小表驱动大表」?
驱动表 = 循环外层的表(少循环) 被驱动表 = 循环内层的表(快查)
原理就像两层 for 循环:
// 小表驱动大表(快)for (小表100条) {去大表100万条里索引查一下}循环次数:100次
// 大表驱动小表(慢死)for (大表100万条) {去小表100条里索引查一下}循环次数:100万次
MySQL JOIN 优化器会自动选:数据量小的表当驱动表! 这就是 自动选择小表驱动大表。
2. 那 IN 子查询 能不能做到小表驱动大表?
不能!至少不能稳定做到!
甚至 MySQL 会故意把它变成 大表驱动小表!
3. 关键区别(核心)
✅ JOIN
优化器会自动分析两张表大小 永远优先用小表驱动大表 内层被驱动表可以走索引,极快
❌ IN (select …)
MySQL 优化器对子查询支持很弱 它会:
- 先执行子查询,生成一个临时结果集
- 再把主表 逐行 去匹配这个结果集
结果就是:
主表有多少行,就循环多少次! 主表如果 100 万行 → 循环 100 万次!
这就是 大表驱动小表(最差性能)
4. 最扎心的真相:IN 子查询的执行逻辑
你写的:
select * from aaa where user_id in (select user_id from bbb where ...);
MySQL 实际执行 是:
for (每一行数据 in aaa 表) {判断 user_id 是否在 (子查询结果) 里}
aaa 表越大,这条 SQL 越慢!
5. 那 JOIN 是怎么执行的?
select a.* from aaa ajoin bbb b on a.user_id = b.user_idwhere b.test <> 'hello';
MySQL 自动优化:
- 看看 a 和 b 谁小
- 小表当驱动表(外层循环)
- 大表走索引(内层快速查找)
循环次数 = 小表行数,超级快!
6. 最直观对比(100万大表 vs 100行小表)
| 方式 | 驱动方式 | 循环次数 | 性能 |
|---|---|---|---|
| INNER JOIN | 小表驱动大表 | 100 | 极快 |
| IN 子查询 | 大表驱动小表 | 100万 | 极慢 |
7. 那 EXISTS 呢?
select * from aaa awhere exists (select 1 from bbb b where b.user_id = a.user_id);
EXISTS 会自动小表驱动大表,性能 ≈ JOIN 但 写法不如 JOIN 直观。
8. 最终结论(开发必背)
- JOIN 会自动小表驱动大表,性能最好
- IN 子查询无法稳定小表驱动大表
- 数据量越大,IN 越慢,JOIN 优势越大
- 千万不要在大表上使用 IN (select …)
- 所有关联查询,优先用 JOIN
超级总结
- JOIN = 自动小表驱动大表 = 快
- IN 子查询 = 大表驱动小表 = 慢
用看 EXPLAIN 执行计划,一眼看到驱动表是谁。
