概念
语法 | 用途 | 常用场景 |
---|---|---|
IN |
判断是否在某个列表 | 列表是静态值(IN (1,2,3) )或子查询 |
EXISTS |
判断是否存在匹配 | 子查询里经常配合外层列 |
JOIN |
真正把两表关联起来,输出结果 | 需要拿到匹配列时 |
底层
IN | EXISTS | JOIN | |
---|---|---|---|
执行原理 | 将子查询结果先计算成一个临时集合,外层值去匹配 | 外层值带进去跑子查询,看是否至少存在一行 | 两张表做笛卡尔积 + 连接条件过滤,或用索引、Hash Join、Nested Loop 加速 |
适用场景 | 小范围列表/短子查询结果 | 子查询通常跟外层值有关(correlated subquery) | 需要输出连接列 |
优化器行为 | 对 IN 和 EXISTS 常可相互转换 |
对 IN 和 EXISTS 有时会改写成半连接 |
JOIN 可以是 Nested Loop / Hash Join / Merge Join |
性能
场景 | 谁更快 |
---|---|
IN (静态值) vs EXISTS |
IN 更快(因为直接转 OR) |
IN (子查询) vs EXISTS (子查询) |
大多数情况下 EXISTS 更优,尤其是子查询和外层相关时 |
JOIN vs EXISTS |
如果只是判断是否匹配,EXISTS 比 JOIN 更省内存,不会产生笛卡尔积;JOIN 在需要取出列时更方便 |
何时用
需求 | 推荐 |
---|---|
判断某值是否属于固定列表 | IN |
判断是否存在匹配记录 | EXISTS |
需要取匹配行的列 | JOIN |
子查询和外层列有依赖关系 | EXISTS 通常比 IN 更优 |
大集合匹配 | 优先 JOIN (配合索引) |
示例
写法 | 解释 |
---|---|
WHERE id IN (1, 2, 3) |
最快,直接 OR |
WHERE id IN (SELECT id FROM big_table) |
如果 big_table 很大,EXISTS 更合适 |
WHERE EXISTS (SELECT 1 FROM big_table WHERE big_table.id = small_table.id) |
如果 big_table 有索引,EXISTS 很快 |
JOIN |
如果要输出 big_table 的列,必须用 JOIN |
实战经验
-
IN
的子查询结果集比较大时会变慢(内部先 materialize) -
EXISTS
通常对相关子查询更友好(会 index lookup) -
JOIN
要注意是否会产生重复行(笛卡尔积),如果只需要“是否有匹配”,不要用JOIN
判断方法
一定要看 EXPLAIN
!
因为 MySQL 优化器有时会把:
-
IN
改成EXISTS
-
EXISTS
改成 Semi-Join -
JOIN
改成 Hash Join
你只要记住: |
---|
只需判断是否存在:用 EXISTS |
小范围值匹配:用 IN |
要输出匹配的列:用 JOIN |