一段 SQL 查詢走進酒吧,看見兩張桌子(tables)。 他走上前問:「我可以加入(join)你們嗎?」
——出處不明
Join 為什麼對效能敏感#
join 運算把正規化模型中的資料,轉換成適合特定處理目的的反正規化形式。由於它要組合散落各處的資料片段,因此對磁碟尋道延遲特別敏感。
適當的索引依然是縮短回應時間的最佳解法——但正確的索引取決於查詢使用了三種常見 join 演算法中的哪一種。
所有 join 演算法的共同點#
不論哪種演算法,它們一次只處理兩張表。涉及更多表的 SQL 查詢需要多個步驟:先 join 兩張表產生中間結果集,再把結果與下一張表 join,依此類推。
join 順序不影響最終結果,卻影響效能。最佳化工具因此會評估所有可能的 join 順序排列,選出最好的那個。這意味著——光是最佳化一段複雜敘述本身就可能變成效能問題:要 join 的表越多,要評估的計畫變體就越多,數學上是 n!(階乘成長)。
敘述越複雜,使用繫結參數就越重要。不使用繫結參數,就像每次執行都重新編譯一次程式。
延伸:中間結果的管線化
雖然「中間結果」很好地解釋了演算法,但這不代表資料庫真的必須把它具體化(materialize)——也就是在開始下一次 join 之前,先把第一次 join 的中間結果存起來。
實際上資料庫使用**管線化(pipelining)**來降低記憶體用量:中間結果中的每一列一產出,就立刻被送進下一個 join 操作,因而不需要儲存整個中間結果集。