查询语句
1.not in
select distinct A.ID from A where A.ID not in (select ID from B)
容易理解,效率低:
2.left join
select A.ID from A left join B on A.ID=B.ID where B.ID is null
语句拆分
这条语句使用了左连接(LEFT JOIN),然后通过 WHERE B.ID is null
的条件来选择在表 A 中存在但在表 B 中不存在匹配的记录。
- 这个查询语句可能会扫描 A 表和 B 表,然后进行连接操作并过滤出匹配条件的结果。优化器可能会根据索引情况选择合适的连接方式。
- 这个查询语句通常能有效利用索引来进行连接和过滤,因此在合适的索引存在的情况下,性能可能较好。
3.子查询
select * from A where (select count(1) as num from B where B.ID = A.ID) = 0
语句拆分
select
* from
A
这是主查询的部分,意味着从表 A 中检索所有的列(使用 *
通配符)。
where
(select
count
(1) as
num from
B where
B.ID = A.ID) = 0
这是一个子查询,嵌套在主查询的 WHERE
子句中。
子查询使用了聚合函数 COUNT(1)
来计算匹配的记录数量,并将其作为 num
的别名返回。
- 对表 A 中的每个记录,使用子查询检查是否在表 B 中存在匹配的记录。对于每条 A 表的记录,都会执行子查询以计算满足条件的记录数。这个查询可能会在 A 表和 B 表之间执行很多次相关子查询,导致性能较差。
- 如果表 B 中的记录较多,或者数据量大,这种子查询方式可能会导致性能下降,特别是在没有合适索引的情况下。
如果表 A 很大,而表 B 很小,查询语句哪个更适合?
left join
原因:
- 左连接方式:第一个查询使用了 LEFT JOIN,它会返回表 A 中存在但在表 B 中不存在匹配的记录。由于表 B 很小,即使使用左连接,MySQL也能够迅速匹配并过滤掉与表 B 匹配的记录,以获取符合条件的结果。
- 利用索引:如果在表 A 和表 B 的 ID 字段上都有合适的索引,左连接操作通常能够利用这些索引,以较快的速度找到匹配和不匹配的记录,然后根据条件进行过滤。
- 子查询性能问题:当查询中使用了子查询,对于每个表 A 的记录都会执行一个相关子查询,这可能导致性能下降,特别是当表 A 很大时。即使表 B 很小,但是对于大型的表 A,多次执行相关子查询可能会消耗更多资源和时间。
例子
用户表[user]
会员表[member]
流程:
用户[user]激活的时候创建对应的会员[member],这样就能把会员和用户关联起来,其中关联的外建就是userId
查询:
查询用户已经激活,但是还没有创建会员的用户: in[user] & not in[member]
语句:
SELECT
u.*
FROM
user u
WHERE
u.activate = 1
AND (SELECT count(1) AS num FROM member m WHERE m.user_id = u.id) = 0;