SQL中EXISTS与IN并不能完全等价替代

背景

很多文章中都声称,为了优化效率,可以使用exists去替代in,但实际上在一些特殊业务情况下,两者并不能等同。

实例

今天刚好记录一下碰到的情况,以ORACLE为例,EXISTS用于校验子查询是否为true,而in用于判断条件是否位于子查询中,现需求如下,获取某日期段内的用户所有以往记录,比如
A、2014-06-01~2014-06-02有操作记录的用户
B、根据该用户ID找到所有该用户操作记录

IN方式则可以很简单得出结果

SELECT
	TMP.patient_id,
	TMP.event_no,
	TMP.retrieve_date
FROM
	t_user TMP
WHERE
	TMP.PATIENT_ID IN (
		SELECT
			AP.PATIENT_ID
		FROM
			t_user ap
		WHERE
			AP.retrieve_date >= TO_DATE ('2014-06-01', 'yyyy-MM-dd')
		AND AP.retrieve_date <= TO_DATE ('2014-06-02', 'yyyy-MM-dd')
	)

order by TMP.patient_id desc

在这里插入图片描述
而使用EXISTS的话,则达不到想要的结果,条件被过滤了,只能获得2014-06-01~2014-06-02的记录

SELECT
	TMP.patient_id,
	TMP.event_no,
	TMP.retrieve_date
FROM
	t_user TMP
WHERE
	EXISTS (
		SELECT
			AP.PATIENT_ID
		FROM
			t_user ap
		WHERE
			AP.patient_id = TMP.patient_id
		AND AP.event_no = TMP.event_no
		AND AP.orgcode = TMP.orgcode
		AND AP.retrieve_date >= TO_DATE ('2014-06-01', 'yyyy-MM-dd')
		AND AP.retrieve_date <= TO_DATE ('2014-06-02', 'yyyy-MM-dd')
	)

在这里插入图片描述
而如果将内外表表关联条件去掉的话,则全部用户数据都查出来了,也显然不符合要求。

分析

exists的意义在于子查询是否为真,如果不与外表关联的话,则条件恒为真的情况下,外表所有数据的where条件也恒为真,所以所有数据全部可查;而与外表关联的话,则变成了外表的数据必须满足内表条件,比如外表数据也必须在2014-06-01~2014-06-02之间才能使内表条件为真。
这个时候IN则避开了这点,只要内表的数据内容与外表条件匹配即可,查询即等价于
select * from A where A.id in (‘1001’,‘1002’,‘1003’)

总结

所以EXISTS与IN的互换还需要具体问题具体分析,否则很可能得到错误的结果。EXISTS对IN的性能优化也不是绝对的,这个就是另一个话题了。

发布了25 篇原创文章 · 获赞 22 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/fzuzhanghao1993/article/details/93891799