經常寫sql的人,基本都會問怎么優化sql語句,做sql的性能調優,小編認為最核心的掌握表連接的三大方式。在數據庫中,join操作是最費資源的,實際生產環境中,一條慢sql,很多時候是數據庫選擇了錯誤的連接方式,導致查詢緩慢。oracle 數據庫的表連接,在內存中有三種連接方式,1.nest loop join 2.hash join 3.merge join
1.nest loop join


這種連接方式是早期數據庫中就存在的,可以通俗地叫它“循環連接”,為什么叫循環連接呢?
如圖 Outer Table 就表示驅動表,row1表示第一行數據,它會去關聯 被驅動表(inner table),row1第一次去找inner table 時,屬于一次隨機讀,被驅動表有M條,row1就會去關聯M次,row1對inner table的訪問包括一次隨機讀,M-1條順序讀,相當于找inner table要花費一個隨機讀,找到之后,對inner table 遍歷就屬于順序讀了,隨機讀的性能比順序讀差一千倍左右,一個隨機讀可以想象成10ms,一個順序讀大概0.1ms。假設驅動表N條數據,被驅動表M條數據,就會產生N*M次關聯,其中N次隨機讀,inner table要被全表掃描N次。隨機讀,全表掃描,都是很費資源的,所以說驅動表不能太大,N不能太大。
我們經常聽說說驅動表要選擇小一點的表,根本原因之一就是如此,驅動表的每一條數據都要去把inner table全表掃描一遍,就像程序里面的for循環,for(驅動表每條數據取一次){ 每條驅動表的數據 都全表掃面inner table 做連接匹配 },“循環連接”這個名字就是這么來的。
舉個極端的例子,表1 有10條數據,表2有100萬條數據,如果選大表作為驅動表,那么表1短時間內要被訪問一百萬次,表2每次去關聯表1都是一次隨機讀,100萬個隨機讀很費時間如果調整一下,把表1這個小表,當作驅動表,這時候只有10個隨機讀,10次表2的全表掃描,全表掃描是順序讀,性能還勉強看的過去。
通過上面的解釋,應該清楚為什么nest loop join 時驅動表要選擇小表,主要原因是因為隨機讀和全表掃描。那有什么辦法優化呢?這時候很多書本會告訴你建立連接列的索引,為什么建連接列的索引就可以優化呢?


建立連接列索引后,進行連接匹配的階段,壓根就不需要訪問表,直接訪問索引就可以進行匹配,索引的大小相對于表還是很小的,兩個索引進行匹配,可以想象成兩個小表進行匹配,大的數據才有性能問題,小的東西當然快,這只是次要原因,主要原因還是索引結構帶來的加速,有些人認為建連接列索引是為了消除大量隨機讀,我不這么認為,我們可以認為索引就是有結構的小表,兩個索引之間的匹配還是像表之間的nest loop一樣,n條索引數據,產生n條隨機讀,并不會減少隨機讀,索引帶來的巨大優勢是減少被驅動表的順序讀,沒有索引時,被驅動表只能全表掃描,被驅動表1千方條數據,就要一千萬的順序讀,有索引后,因為索引的結構,存儲千萬級別的數據只要5層索引結構,千萬級別數據量中搜索一條數據,只要5次IO,千萬次和5次,差別很大。連接列建立索引并不能消除大量隨機讀,大量隨機讀本身就是nest loop join的缺陷,后面就提出的hash join能改善這種大量隨機讀導致的性能問題。建立連接列索引后,nest loop join對于返回結果集特別小的查詢,十分友好,比如驅動表經過where過濾后只有10條數據,這時整個驅動表不需要置入內存,只要拿這10條數據,與被驅動表的連接列索引匹配,速度很快。返回數據少,用nest loop join,返回數據多,用hash join (hash 需要把驅動表置入內存,如果只返回少量數據,還要用hash join有點浪費內存資源)
今天只講nest loop join,下次再講hash join ,merge join,今天主要核心知識點:隨機讀,順序讀,循環連接,索引層級
版權聲明:本文內容由互聯網用戶自發貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發現本站有涉嫌抄襲侵權/違法違規的內容, 請發送郵件至 舉報,一經查實,本站將立刻刪除。