1. 程式人生 > >MySQL中的JOIN

MySQL中的JOIN

MySQL的官方文件上面是這麼寫的“MySQL executes joins between tables using a nested-loop algorithm or variations on it.”但是似乎又有其他演算法,這篇文章的題目就是《MySQL Isn’t Limited to Nested-Loop Joins》,作者還在文中抱怨說“I think the MySQL documentation could help a little by calling things names that normal users understand.”。 不管咋樣吧,我看了一下SQL Server的三種join型別(演算法),記得Oracle的join也是nested-loop join,merge join,hash join。要把表連線起來,總是要找個表作為基礎表,然後遍歷符合篩選條件的行(篩選條件要麼在join的and裡面,要麼在where裡面,在邏輯上來說where的執行順序在join之後,但是聰明的優化器會先用where條件過濾掉一部分不符合篩選條件的行),再去用連線條件找其他表裡面符合連線條件的行。

嚴格來說上面的這個表述只是nested-loop演算法,找其他表裡面符合連線條件的行時要麼遍歷表,要麼利用索引。merge join演算法是這樣,兩個表有聚簇索引(聚簇索引的順序就是資料的物理儲存順序,而對非聚簇索引的索引順序與資料物理排列順序無關),merge join的過程就相當於把兩個排好序的列表放在一起比較,看它們兩個有多少個項能對齊,這麼一想,還不是遍歷基礎表,只不過把對整表的遍歷換成了對聚簇索引的遍歷。我試著寫一下演算法程式碼,下面程式碼中list1和list2都是排好序的列表,result是最後兩個列表中可以“對齊”的項。這段python程式碼的語法應該是正確的

m = len
(list1) n = len(list2) result = [] i, j = 0, 0 while i < m: while j < n: if list1[i] == list2[j]: i += 1 j += 1 result.append(list1[i]) elif list1[i] > list2[j]: i = i j += 1 elif list1[i] < list2[j]: i +=
1 j = j

至於hash join,其實就是給一個表建了個臨時的索引,然後利用這個索引獲得連線時的效能提升,跟nested-loop join時非基礎表有索引是一樣的。

看到這裡,肯定有人覺得寫SQL語句時FROM之後表出現的順序很重要,其實不是,優化器會決定實際的連線順序。查詢執行計劃(query execution plan (QEP))指的就是執行查詢時實際的表連線順序和表中資料的檢索方法(access method),就不展開講了。

既然說MySQL執行表連線的演算法是nested-loop和它的變種,那麼我們來看一下變種是什麼。

Block Nested-Loop Join Algorithm,應該是叫塊內嵌迴圈連線演算法。這個演算法的想法是一次只取基礎表的一個值去比較太麻煩太慢了,一次性多拿出幾個來,然後去和其他表比較,這樣就可以減少比較次數。

Batched Key Access(BKA) Join Algorithm,批量關鍵碼訪問連線演算法?這個演算法跟Block Nested-Loop Join Algorithm有點類似,用在第二個表有索引的情況下,針對第一個表中符合篩選條件的行建立快取(buffer),BKA演算法會算出這些行的關鍵碼,把這些行的關鍵碼批量匯入資料庫引擎來對第二個表的索引執行查詢。可能沒表述清楚,原文件在這裡,感興趣的讀者可以自行查閱。