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的性能優化也不是絕對的,這個就是另一個話題了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章