MySQL 中的 IN 和 EXISTS 子句有什么区别?
IN和EXISTS`均用于 “子查询条件判断”,核心区别在于 “查询逻辑” 和 “性能”,具体对比如下:
# 1. 核心区别
| 对比维度 | IN | EXISTS |
|---|---|---|
| 查询逻辑 | 先执行子查询,将结果集作为条件(如IN (1,2,3)),再执行主查询 | 先执行主查询,将主查询的每行数据传入子查询,判断子查询是否返回结果(存在则保留该行) |
| 子查询结果集 | 只能返回单列数据(如SELECT id FROM user) | 可返回任意列(通常返回1,如SELECT 1 FROM order WHERE user_id = u.id) |
| 空值处理 | 子查询返回 NULL 时,IN条件恒为 FALSE(如WHERE id IN (NULL),无结果) | 子查询返回 NULL 时,EXISTS条件恒为 FALSE |
| 性能差异 | 子查询结果集小时,性能优(内存中处理条件) | 子查询结果集大时,性能优(主查询过滤后再执行子查询,减少子查询次数) |
| 适用场景 | 子查询结果集小(如 1000 行以内),主查询数据量大 | 子查询结果集大(如 10 万行以上),主查询数据量小 |
# 2. 语法示例与执行逻辑
# 测试数据:
CREATE TABLE user (id INT PRIMARY KEY, name VARCHAR(20)); -- 主查询表(10万行)
CREATE TABLE `order` (id INT PRIMARY KEY, user_id INT); -- 子查询表(100万行)
1
2
2
# (1)IN 示例(子查询结果集小)
需求:查询有订单的用户(子查询返回有订单的 user_id,结果集 1 万行)。
SELECT * FROM user WHERE id IN (SELECT user_id FROM `order`);
1
# 执行逻辑:
- 先执行子查询
SELECT user_id FROM order,返回 1 万行 user_id(如 1,2,3...); - 主查询
SELECT * FROM user WHERE id IN (1,2,3...),在 user 表中匹配 id,返回结果。
# (2)EXISTS 示例(子查询结果集大)
需求:查询有订单的用户(主查询先取 user 表的行,传入子查询判断)。
SELECT * FROM user u WHERE EXISTS (SELECT 1 FROM `order` o WHERE o.user_id = u.id);
1
# 执行逻辑:
- 主查询取 user 表的第一行数据(u.id=1);
- 子查询
SELECT 1 FROM order o WHERE o.user_id=1,判断是否有结果(有则返回 TRUE,无则返回 FALSE); - 若子查询返回 TRUE,保留该行数据;否则丢弃;
- 主查询取 user 表的下一行数据,重复步骤 2-3,直到所有行处理完成。
# 3. 性能优化建议
子查询结果集小(<1 万行):优先使用 IN(子查询结果集加载到内存,主查询快速匹配);
子查询结果集大(>10 万行):优先使用 EXISTS(主查询过滤后,子查询仅执行匹配的行,减少子查询次数);
避免 IN 的子查询返回大量数据:若子查询返回 10 万行以上,IN 的条件会占用大量内存,性能下降,改为 EXISTS;
NOT IN 与 NOT EXISTS:NOT IN 性能极差(子查询返回 NULL 时结果不准确),优先使用 NOT EXISTS;
-- 不推荐:NOT IN 性能差 SELECT * FROM user WHERE id NOT IN (SELECT user_id FROM `order`); -- 推荐:NOT EXISTS 性能优 SELECT * FROM user u WHERE NOT EXISTS (SELECT 1 FROM `order` o WHERE o.user_id = u.id);1
2
3
4
5
上次更新: 12/30/2025