概述一般在做SQL優(yōu)化的時候講究使用EXISTS帶替代IN的做法,理由是EXISTS執(zhí)行效率要比IN高。 個人理解: IN表示范圍,指某一字段在某一范圍之內(nèi),這個范圍一般使用子查詢來獲取,由此可知IN子查詢返回的結(jié)果應(yīng)該就是這個范圍集。 EXISTS表示存在,指至少存在一處,這個條件由EXISTS子查詢來完成,但是在這里EXISTS子查詢返回的結(jié)果卻不再是一個結(jié)果集,而是一個布爾值(true或false),其實這個挺好理解的,EXISTS就表示如果子查詢能查到值則返回true,則執(zhí)行EXISTS之前的語句。 測試數(shù)據(jù)員工參數(shù)課程培訓(xùn)數(shù)據(jù),兩次不同課程培訓(xùn)分別存在CLASS_A 和 CLASS_B 兩張表中。 CLASS_A: CLASS_B: 需求:查找同時參加了兩門課程的員工。 兩種方式實現(xiàn)下面分別使用in 和 exists兩種方式實現(xiàn)。 1、in 方式查詢 SELECT *FROM class_aWHERE id IN ( SELECT id FROM class_b); 2、exists 方式查詢 SELECT *FROM class_a AWHERE EXISTS ( SELECT * FROM class_b B WHERE A.id = B.id); 說明: 上述兩種方法查詢結(jié)果一樣,但exists 方式速度要快。分析如下: 1)如果連接列id 上有索引,那么查詢CLASS_B時,無需查詢實際表,僅需要查索引就可以了。 2)使用exists ,那么只有查到一行數(shù)據(jù)滿足條件就會終止查詢,不會產(chǎn)生臨時表。 3)使用in查詢時,數(shù)據(jù)庫首先會執(zhí)行子查詢,然后將結(jié)果保存在臨時表中,然后掃描整個臨時表,很多情況下非常耗費資源。 如何用exists來代替in假如有一個表user,它有兩個字段id和name,要查詢名字中帶a的用戶信息: 最簡單的SQL:select * from user where name like '%a%'; 使用IN的SQL:select u.* from user u where u.id in (select uu.id from user uu where uu.name like '%a%'); 將使用IN的SQL修改為使用EXISTS的SQL該怎么寫呢? 一開始我直接將u.id in 替換為EXISTS,獲得如下語句 : select u.* from user u where exists(select uu.id from user uu where uu.name like '%a%'); 經(jīng)過測試發(fā)現(xiàn)輸出結(jié)果錯誤,該語句將所有的用戶全部一個不漏的查詢出來了,相信你也發(fā)現(xiàn)了問題,后來我對上述語句做了修改如下: select u.* from user u where exists (select uu.id from user uu where uu.name like '%a%' and uu.id=u.id); 只是在子查詢中添加了“and uu.id=u.id”,結(jié)果查詢結(jié)果正確。 總結(jié):EXISTS子查詢可以看成是一個獨立的查詢系統(tǒng),只為了獲取真假邏輯值,EXISTS子查詢與外查詢查詢的表是兩個完全獨立的毫無關(guān)系的表(當(dāng)?shù)诙€表中的name中有包含a的姓名存在,那么就執(zhí)行在第一個表中查詢所有用戶的操作),當(dāng)我們在子查詢中添加了id關(guān)聯(lián)之后,EXISTS子查詢與外查詢查詢的表就統(tǒng)一了,是二者組合組建的虛表,是同一個表(這樣當(dāng)子查詢查詢到虛表中當(dāng)前行的uu.name中包含a時,則將虛表當(dāng)前行中對應(yīng)的u.id與u.name查詢到了) 所以一切的重點就在這個ID關(guān)聯(lián)之上,添加ID關(guān)聯(lián),數(shù)據(jù)庫會先將兩張表通過ID關(guān)聯(lián)組合成一張?zhí)摫?,所有的查詢操作都在這張?zhí)摫砩贤瓿桑僮鞯氖峭粡埍?,?dāng)然就不會出現(xiàn)之前的那種情況了! 總結(jié)exists 方式查詢 比 in 方式查詢效率高,但in 可讀性較好。建議盡可能使用exists方式,避免使用子查詢,除非in 的參數(shù)為數(shù)值列表。 |
|
|