2017年10月20日 星期五

[SQL] JOIN - Hash Join

  • Hash Join (雜湊聯結):輸入兩資料表分為不同角色
    • Build Input (建置輸入)
      • 第一階段,較小的資料表
      • 掃描或計算整個 "Build Input",依據 "間直資料行" 產生 "Hash Key" (雜湊鍵) 並建立 "Hash Table" (雜湊表),再依據 "Hash Key" (雜湊鍵) 將每個 "Row" (資料列) 置入 "Hash Bucket" (雜湊桶)
    • Probe Input (探查輸入)
      • 第二階段,較大的資料表
      • 掃描或逐列計算整個 "Probe Input",針對每個 "探查輸入" 的資料列計算 "Hash Key" (雜湊鍵值),並掃描對應至 "Hash Bucket" (雜湊桶),並產生符合項目
    • "Merge Join" 與 "Hash Join" 之間差異,什麼樣的情況適合使用 "Merge Join" 或 "Hash Join"
  • 資料庫使用 Adventure Works for SQL Server 2012 的資料表 Sales.SalesOrderHeader 與 Sales.SalesOrderDetail 創建 3 個 table 如下
    • tbSalesOrderHeader
      • unique Clustered index:SalesOrderID
    • tbSalesOrderDetail01
    • tbSalesOrderDetail02
      • unique Clustered index:SalesOrderID, SalesOrderDetailID
    • 查詢
select *
from tbSalesOrderHeader o
join tbSalesOrderDetail01 od ON o.SalesOrderID = od.SalesOrderID

select *
from tbSalesOrderHeader o
join tbSalesOrderDetail02 od ON o.SalesOrderID = od.SalesOrderID
    • 查詢結果
      • 查詢 1:沒建立 "SalesOrderID" 為鍵值資料行的索引,因此採用 "Hash Join",若沒使用 "Hash Join" 將會增加 "排序" 作業,才能使用 "Merge Join",這樣成本更高
      • 查詢 2:建立 "SalesOrderID" 為鍵值資料行的索引,而經過排序,所以採用 "Merge Join"
    • 查詢 1 中 "tbSalesOrderHeader" 與 "tbSalesOrderDetail01" 屬於 "一對多" (或稱父子關係),因 "tbSalesOrderHeader" 資料列必定少於 "tbSalesOrderDetail01"
    • 所以 "Hash Join" 中的 "Build Input" (建置輸入) 為 "tbSalesOrderHeader",可見 "tbSalesOrderHeader" 被置放於上面的位置
    • Result:
      1. "Merge Join" 與 "Hash Join" 較適合大型的查詢,查詢資料較多的情況
      2. "Merge Join" 適合兩資料表都有 "索引" 或是經過事先排序過的情況
      3. 不適合 "Merge Join" 的情況下,將採用 "Hash Join"
  • REF:
    • SQL Server 效能調校

沒有留言:

張貼留言