1. 程式人生 > >sql優化之in與

sql優化之in與

在我們開發過程中,初期可能不會去太關注我們自己寫的sql語句的效率怎麼樣,因為總是覺得可以拿取到資料就算是ok了,可能也會注意一下你的sql執行的時間,但是在開發的過程中因為資料量的原因,其實你不去了解一下sql的一些優化的手段其實是無法感知你的sql的效率問題。我之前部落格也寫過一篇關於sql的優化一些需要注意的點,而我們本節主要是針對in與exists的區別以及什麼時候使用in,什麼時候使用exists。

in與exists的區別

  • in:in是把外表和內表做hash連線,先查詢內表,再把內表結果與外表匹配,他是先將資料督導記憶體中,然後取與外表匹配。他要執行的次數是外表的長度*內表結果的長度
  • exists:exists是對外表做loop迴圈,每次loop迴圈再對內表(子查詢)進行查詢,那麼因為對內表的查詢使用的索引,他只需要執行的次數是外表的長度。 可能說完之後還是一臉懵逼,那麼接下來我們會通過一個簡單的例子來加以說明: 首先我們有a表和b表 a表有以下幾個欄位 id(學生id),name(學生姓名),age(學生年齡) b表有以下幾個欄位 course(課程名稱),studentId(學生ID) 規定一個學生可以選擇n們課程,然後我們需要查出學修了某些課程的所有學生的資訊, 通常對於上面的東西,我們有兩種方式實現: 使用in方式實現
   select * from a where id in(select studentId where name='xxx')

使用exists實現

 select * from a where exists (select studentId where name='xxx' and a.id=studentId)

in想必大家用的很多吧,原理也是很簡單就是和我們上面一樣,而exists的原理就不一樣了,他是通過子查詢返回的資料是否為null,如果不為null,那麼就會將當前的資料加入結果集,因此我們select * from a的時候,我們是從第一條資料開始執行的,每次執行都會去執行exists的子查詢,如果不為null就加入結果集,反之則不加入,直到最後執行完主查詢為止。

可能我們從網上去找sql優化的時候就會發現他會發現他們都建議我們將in換成exists。但是在仔細去找的時候,又會發現使用in和exists是分不同的場景的,主要是以下場景: 1、a表的資料少於b表的資料那麼就使用exists 2、如果a標的資料多餘b表的資料,那麼就使用in 3、如果一樣其實是沒有區別的 然後我就按照這個邏輯去弄了,順便除錯了下,發現沒有什麼區別(這個是資料量很少很少的情況下),然後我就閒著沒事,我就去增加了大資料(這時候a表的資料為2w條,b表的資料為(30w條)),這時候我就繼續去用這兩種方法去做實驗,如果按照我們之前的邏輯的話,那麼就必須使用exists來,但是事實上我發現了使用exists時的查詢耗時的時間是in的十幾倍,這時候我就納悶了, 使用in查詢結果耗時 在這裡插入圖片描述

使用exists查詢結果耗時: 在這裡插入圖片描述

這時候我就猜想他說b表資料要大於a表的意思是不是指查詢過後的資料,我就抱著這種想法去試一下,這時候我在次增加了b表的資料,但是這次是增加某門課程的資料(不同的學生)增加了10w條,然後我在次使用exists和in去查詢,這個時候就發現exists的查詢效率比in高好多。然後發現別人是不是寫錯了, 事實上別人沒有寫錯,只是我們誤解了,既然子查詢查出來的資料要大於a表,那麼b表的資料也就一定高於a表,因此他們的說發也沒問題。 使用in的場景:a表的資料大於b表的資料(關聯查詢後的資料) 使用 exists的場景:a表的資料小於b表的資料(關聯查詢後的資料) 如果資料量相同in和exists都可以使用,還有強調一點in是不會導致索引失效的

既然說到了in和exists,那麼我們就順便帶過一下not in 和not exists。 當我們要使用not in的時候建議直接將他替換成not exists,不論a表的資料與b表的資料相差多大。 有的人會問為什麼? 其實很簡單。我們資料庫只會告訴你資料在哪裡,而不會告訴你資料不在哪裡,因此使用not in一定會導致索引失效,那 not exists為什麼不會失效呢?因為not exists其實就相當於我們查詢出來的資料取反,即有和無,他本身是不參與sql的執行,因此他是不會導致所以失效的。