MySQL和PostgreSQL在多表連接算法上的差異

參考文章:MySQL和PostgreSQL在多表連接算法上的差異

我們知道mysql沒有hash join,也沒有merge join,所以在連接的時候只有一種算法nest loop join,nl join使用驅動表的結果集作爲外表到內表中查找每一條記錄,如果有索引,就會走索引掃描,沒有索引就會全表掃。

nl join並不能適用所有場景,例如兩個表都是很大的表的等值連接,這種場景是hash join所擅長的,而且是生產環境中最常見的場景。mysql在這個時候就顯得力不從心,所以在使用mysql時我們可能會制定如下規範:禁止使用大表連接。這也是mysql永遠的痛。不過據說8.0版本已經將hash join作爲一個需求納入了,我們拭目以待吧。

相比起來,postgresql的優化器十分的強勁。支持了hash join、nest loop、sort merge join,掃描算法支持seq scan、index scan、index only scan,同時還支持堆內元組技術(HOT)在postgresql11版本中還加入了並行掃描,親測在兩張大表(一張1.6億一張256萬數據,均無索引)做join結果集300多萬,pg開啓並行大概20s以內就跑出結果,強於其他數據庫。

上面討論了兩表join的算法,下面看看多表join時mysql和pg是如何處理的。多表join其實涉及到一個問題:如何找到代價最小的最優路徑。爲什麼會有這個問題呢?因爲在多表連接時,每兩個表之間連接具有一個代價值,優化器會根據代價估算調整不同表join的順序,最後算出一個最優或者近似最優代價,使用這個代價生成執行計劃,這樣就涉及到圖論中的最短路徑問題,不同的連接順序組合代表了圖的遍歷,最優代價其實就是求無源圖的最短路徑問題。我們知道兩種主流的最短路徑算法是迪傑斯特拉(Dijkstra)算法和弗洛伊德(floyd)算法,這兩種算法也是動態規劃中的經典算法。

在mysql中計算最優代價使用貪心算法,而pg使用的是動態規劃。

Mysql:

Mysql連接使用貪心算法,下面這個圖表明瞭貪心算法的過程:

 

貪心算法的前提是確定源點,算法思想也和名字很像,只找當前步驟的最優解,是一種深度優先的解法,算法複雜度是O(n²)找到後繼續深入下一層,直至達到終點。比如上圖從A到G,使用貪心算法的路徑是A->B->D->G算法,代價是1+2+6=9,很明顯這並不是最優解,最優解我們肉眼可以看出來是A->C->F->G,代價是2+3+1=6。所以我們看貪心算法並不是全局最優的,但是優點是算法複雜度低,mysql可能也是基於這種考慮而使用貪心算法,不想將時間都浪費在計算代價上了,因爲如果關聯的表特別多,那麼代價的計算是指數級增長,所以貪心算法雖然不是最優解,但是在連接表的數量很大的情況下具有一定優勢。

Postgresql:

再來看看pg使用的動態規劃,動態規劃解決的是無源最短路徑問題,我們想象一下其實多表連接本身就是一個無源最短路徑問題,只是mysql在進行連接的時候隨機選了一個作爲起點而已。

動態規劃的思想是將問題分解爲子問題,將問題遞推爲子問題進行解決。以floyd算法爲例。算法使用鄰接矩陣來表示每個點之間的距離,如果沒有連線,則代表無窮大。比如下面這個圖:

 

弗洛伊德算法使用矩陣記錄節點直接距離,它的強大之處在於它經過若干次計算後得到任意兩個節點直接的最短距離,是真正意義上的無源最短路徑算法,但是它的算法複雜度也比較高,是O(n³)。下面介紹一下該算法,算法的核心思想是如果a[ij]>a[ik]+a[kj],那麼a[ij]=a[ik]+a[kj],對於每兩個節點ab之間的距離,如果存在第三個中間節點c使得acb的距離更短,那麼ab的距離使用acb代替,並更新到矩陣。這樣的遍歷過程我們大致就理解了需要三層循環,裏面的兩層循環是對於ab、ac、ad...de總共(n-1)*(n-1)種選擇(自己對自己的距離不用計算)計算每個中間節點(最外層循環)的距離是否更小。矩陣計算過程如下:

對於第一行,依次計算ab,ac,ad,ae的距離是否有第三個節點進行替換,對於ab計算發現,ab<ac+cb&&ab<ad+db&&ab<ae+eb,所以ab不用更新,同理ac也不用更新,對於ad,計算得到ab+bd=6,ac+cd=∞,ae+ed=∞,於是更新ad=6,同理計算更新ae=8;然後依次計算下面幾行。全部遍歷完,經歷了三層循環,算法複雜度是O(n³)。pg使用該算法能夠得到最優執行計劃,但是在表的個數很多時計算代價所付出的代價也很大。

綜上,mysql使用貪心算法只能得到局部最優執行計劃,但是計算最優解所消耗的代價較小,而pg使用動態規劃能夠得到最優執行計劃,但是計算最優解算法複雜度較高,代價較大。但是總體上mysql的優化器相比pg還是有很大差距,pg的優化器甚至引入了基因算法,有很多比較學術的考量,當得起學術派數據庫的稱號,也希望mysql能夠越來越好吧。

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