Navicat 部落格

理解 SQL Server 的 CROSS APPLY 和 OUTER APPLY 査詢 - 第 2 部分 2021 年 10 月 19 日,由 Robert Gravelle 撰寫

CROSS APPLY 和 OUTER APPLY 範例

上一篇文章介紹了 APPLY 運算子,並涵蓋了它與一般 JOIN 有何不同。在今天的後續部分中,我們將比較 APPLY 與 INNER JOIN 的效能,並學習如何將 APPLY 與資料表值函式一起使用。

APPLY 和 INNER JOIN 比較

回顧一下,在第 1 部分的最後,我們執行了一個由兩部分組成的査詢:第一個査詢從 Department 資料表中選取資料,並使用 CROSS APPLY 為 Department 資料表的每筆記錄評估 Employee 資料表;第二個査詢將 Department 資料表與 Employee 資料表聯結起來,以產生相同的結果:

CROSS APPLY vs INNER JOIN (88K)

Navicat 中,我們可以按一下「解釋」按鈕以取得有關資料庫執行計劃的重要資訊。以下是關於上述査詢的執行計劃:

explain_ex_1 (176K)

儘管這兩個査詢的執行計劃相似且成本相同,但它們的執行計劃確實有所不同:

  • APPLY 査詢使用計算純量。它是一個運算子,用於透過執行產生計算值的純量計算作業從現有列值計算新值。這些純量計算包括純量值的轉換或串連。請注意,計算純量運算子不是一個佔用大量資源的運算子,它只會給査詢的總體增加很少的成本,能導致最小的負擔。
  • JOIN 査詢包含額外的叢集索引掃描。當 SQL Server 從上到下讀取叢集索引中的列時(例如在非鍵欄中搜尋資料時),會發生這種情況。這是一個比計算純量稍微成本高一些的作業。

使用 APPLY 運算子聯結資料表值函式和資料表

資料表值函式是傳回資料表類型資料的使用者定義函式。資料表值函式的傳回類型是資料表,因此,你可以像使用資料表一樣使用資料表值函式。將資料表值函式與其他資料表聯結是 APPLY 運算子的設計目的。

讓我們建立一個資料表值函式,該函式接受 DepartmentID 作為其參數,並傳回屬於該部門的所有員工。在 Navicat 中,我們可以按一下主工具列上的大函式按鈕,然後按一下函式工具列上的新增函式來建立函式:

function_button (22K)

以下是按一下儲存按鈕後的 GetAllEmployeesForDepartment 函式:

GetAllEmployeesForDepartment_function (43K)

看看當我們使用 CROSS-OUTER 和 OUTER-APPLY 將新函式加入到每個部門時會發生什麼:

cross_apply_vs_outer_apply (94K)

在每種情况下,査詢都會從外部資料表運算式傳遞每一列的 DepartmentID,並為每一列計算函式,類似於一個相關的子査詢。CROSS APPLY 只傳回相關資料,而 OUTER APPLY 也會傳回非相關資料,這導致缺少的欄會顯示 NULL。

我們無法用 INNER JOIN/LEFT OUTER JOIN 取代上述査詢中的 CROSS/OUTER APPLY。這樣做將發生錯誤「The multi-part identifier "D.DepartmentID" could not be bound.」。這是因為外部(JOIN)査詢的執行內容不同於函式(或衍生資料表)的執行內容。因而,不能將外部査詢中的值或變數作為參數繫結至函式。因此,此類査詢需要 APPLY 運算子。

總結

我們對 CROSS APPLY 和 OUTER APPLY 陳述式的研究到此結束。總括而言,當你必須在査詢中使用資料表值函式時,APPLY 運算子是必需的,但它也可以與內嵌 SELECT 陳述式一起使用。

Navicat 文章
頻道記錄
分享
部落格封存檔