SQL連線操作符介紹(迴圈巢狀, 雜湊匹配和合並連線)
今天我將介紹在SQLServer 中的三種連線操作符型別,分別是:迴圈巢狀、雜湊匹配和合並連線。主要對這三種連線的不同、複雜度用範例的形式一一介紹。
簡介:什麼是連線操作符
連線操作符是一種演算法型別,它是SQLServer優化器為了實現兩個資料集合之間的邏輯連線選擇的操作符。優化器可以基於請求查詢、可用索引、統計資訊和估計行數等不同的場景為每一套資料選擇不同的演算法
通過檢視執行計劃可以發現操作符如何被使用。接下來我們看一下如何具體使用。
NESTED LOOPS(迴圈巢狀)
我們通過下面的例子來展示一下(查詢2001年7月份的資料):
SELECT OH.OrderDate, OD.OrderQty, OD.ProductID, OD.UnitPrice FROM Sales.SalesOrderHeader AS OH JOIN Sales.SalesOrderDetail AS OD ON OH.SalesOrderID = OD.SalesOrderID WHERE OH.OrderDate BETWEEN '2001-07-01' AND '2001-07-31'
執行計劃的結果如下:
圖右上方的叫“outer input”,在其下面的叫做“inner input”
本質上講,“Nested Loops”操作符就是:為每一個記錄的外部輸入找到內部輸入的匹配行。
技術上講,這意味著外表聚集索引被掃描獲取外部輸入相關的記錄,然後內表聚集索引查詢每一個匹配外表索引的記錄。
我們可以通過把滑鼠放在聚集索引掃描操作符上面來驗證這個資訊,請看這個tooltip:
看這個執行的估計行數是1,索引查詢tooltip如下:
這次發現執行的估計行數是179,這是很接近返回的外部輸入行的。
按照複雜度計算(假設N是外部輸出的行數,M是總行數在SalesOrderDetai表的):查詢複雜度是O(NlogM),這裡logM是在內部輸入表的每次查詢的複雜度。
當外部輸入比較小並且內部輸入有索引在連線的欄位上的時候SQLServer 優化器更喜歡選擇這種操作符型別(Nested Loop)。外部和內部輸入的資料行差距越大,這個操作符提供的效能越高。
MERGE Join(合併連線)
“Merge”演算法是連線兩個較大且按序儲存的在連線鍵上最有效的方式。請看一下下面這個查詢例子(查詢返回使用者和銷售表的ID):
SELECT OC.CustomerID, OH.SalesOrderID FROM Sales.SalesOrderHeader AS OH JOIN Sales.Customer AS OC ON OH.CustomerID = OC.CustomerID
查詢執行計劃如下:
- 首先我們注意到兩套資料是在CustomerID上是有序的:因為聚集索引是有序的且在SalesorderHeader表上該欄位是非聚集索引。
- 根據在操作符的箭頭(滑鼠放在上面),我們能看到每個返回結果行數都是很大的。
- 除此之外,在On 的子句後面要用=操作符。
就是這三個因素會導致優化器選擇Merge Join查詢操作符。
使用這種連線操作符的最大的效能就是兩個輸入操作符執行一次。我們能把滑鼠放在兩個資料的上面看一下執行的次數都是1,也就是說演算法是很有效率的。
合併連線同時讀取兩個輸入然後比較他們。如果匹配就返回,否則,行數較小的被放棄,因為兩邊輸入是有序的。放棄的行不再匹配任何行。
知道其中一個表完畢一直重複匹配,即使另一個表還有資料,那麼最大的時間複雜的消耗就是兩個表完全不同鍵值,那麼最大的複雜度就是: O(N+M)。
HASH Match(雜湊匹配)
“Hash”連線是我們稱為 “the go-to guy” 的操作符。當其他連線操作符都不支援的場景時,就會選擇這種操作符。比如當表恰好不排序,或者沒有索引時。當優化器選擇這種操作符,一般來說可能是我們沒有做好一些基礎工作(例如,加索引)。但是有些情況(複雜查詢)沒有別的方式,只能選擇它。
請看下面這個查詢(獲取contacts 表中姓和名中以“John”開始的包含銷售的ID欄位的資料集):
SELECT OC.FirstName, OC.LastName, OH.SalesOrderID FROM Sales.SalesOrderHeader AS OH JOIN Person.Contact AS OC ON OH.ContactID = OC.ContactID WHERE OC.FirstName LIKE 'John%'
The execution plan looks like this:
由於ContactID列沒有索引,所以選擇雜湊操作符。
在深入理解這個例子之前,介紹兩個重要的概念:一個是“Hashing”函式,一個是“Hash Table”。
函式是一個程式性函式,它接收1或者多個值然後轉換他們為一個符號值(通常是數字)。這個函式通常是單向的,意味著不能反轉回來原始值,但是確定性保證如果你提供了相同的值,符號值是完全一樣的。也就是說,幾個不同的輸入值,可以有相同的Hash值。
“Hash Table”是一個數據結構,把所有行都放到一個相同尺寸的桶裡面。每一個桶代表一個雜湊值。這意味著當你啟用函式的行,使用結果你就會知道它屬於哪個桶。
利用統計資訊,SQLServer 會選擇較小的兩個資料輸入來提供構造輸入,並且輸入被用來在記憶體中建立雜湊表。如果沒有足夠的記憶體,在tempdb中會使用物理磁碟。在雜湊表建立後,SQLServer將從較大的表中得到資料,叫做探測輸入。利用雜湊匹配函式與雜湊表比較,然後返回匹配行。在圖形執行計劃中,構造輸入的查詢在上面,探測輸入的查詢在下面。
只要較小的表非常小,這個演算法就是非常有效的。但是如果兩個表都非常大,這可能是非常低效的執行計劃。
查詢Hints
利用Hints,破事SQLServer使用指定的連線型別。但是強烈不推薦這麼做,尤其在生產環境,因為沒有永恆的最佳選擇(因為資料在變化),並且優化器通常是正確的。
新增OPTION 子句作為查詢的結尾,使用關鍵字LOOP JOIN, MERGE JOIN 或者 HASH JOIN可以強制執行連線。
看看如何實現:
SELECT OC.CustomerID, OH.SalesOrderID FROM Sales.SalesOrderHeader AS OH JOIN Sales.Customer AS OC ON OH.CustomerID = OC.CustomerID OPTION (HASH JOIN) SELECT OC.FirstName, OC.LastName, OH.SalesOrderID FROM Sales.SalesOrderHeader AS OH JOIN Person.Contact AS OC ON OH.ContactID = OC.ContactID WHERE OC.FirstName LIKE 'John%' OPTION (LOOP JOIN) SELECT OC.FirstName, OC.LastName, OH.SalesOrderID FROM Sales.SalesOrderHeader AS OH JOIN Person.Contact AS OC ON OH.ContactID = OC.ContactID WHERE OC.FirstName LIKE 'John%' OPTION (MERGE JOIN)
總結
Nested Loops
- 複雜度: O(NlogM)。
- 其中一個表很小的時候。
- 較大的表允許使用索引查詢連線欄位。
Merge Join
- 複雜度: O(N+M)。
- 兩個輸入的連線欄位是有序的。
- 使用=操作符
- 適合非常大的表
Hash Match
- 複雜度: O(N*hc+M*hm+J)
- 最後預設的操作符
- 使用雜湊表和動態雜湊匹配函式匹配行
本篇隨筆詳細介紹了三種連結操作符和它們的觸發機制,當然這些也都是動態的,就像前面說的沒有最佳的操作符,只有最合適的,要根據實際請款選擇不同的操作符。
相關推薦
SQL連線操作符介紹(迴圈巢狀, 雜湊匹配和合並連線)
今天我將介紹在SQLServer 中的三種連線操作符型別,分別是:迴圈巢狀、雜湊匹配和合並連線。主要對這三種連線的不同、複雜度用範例的形式一一介紹。 簡介:什麼是連線操作符 連線操作符是一種演算法型別,它是SQLServer優化器為了實現兩個資料集合之間的邏輯連線選擇的操作符。優化器可以基
向標準輸出上列印一些用ASCII字元組成的圖形(彙總)(迴圈巢狀)(關鍵是找要輸出物與行數n之間的關係,找規律)
1 #include <stdio.h> int main() { int i,j,n; scanf("%d",&n);//有n行 for(i=1;i<=n;i++) {for(j=1;j<=2*
java基礎(二)迴圈巢狀與控制跳轉
迴圈巢狀 package com.st.basis.day04; /* * 迴圈巢狀 * 外層控制行數 * 內層控制列數 * */ public class LoopNesting { public static void main(String[] args) { //
oracle 表連線方式: nested loop 巢狀迴圈和Hash Join的比較
一、建立兩張實驗用表:wireless_site.merchant和wireless_site.bb SQL> select count(*) from wireless_site.merchant; COUNT(*) ---------- 14005
vue v-for迴圈巢狀的探索(二)
使用v-for迴圈的目的就是為了處理大量型別重複的資料,歸根結底是一種有規律的資料,但是有些規律卻不是那麼容易的,很多時候,我們會使用到迴圈,甚至多重迴圈的巢狀,不同的迴圈巢狀對應著不同的json資料的結構,本篇主要講述的是使用v-for迴圈解決部分同,部分不同的情況,主要是
微信小程式-跟隨選單(樓梯效果)和迴圈巢狀載入資料
效果如圖: 程式碼如下: wxml //使用迴圈巢狀data資料格式寫對即可 <scroll-view class="left" scroll-y> <view wx:for="{{left}}" class="le
continue 在 switch中使用 (switch巢狀在while迴圈中)
如果你在switch中使用continue,continue生效是對於while迴圈 如果你在switch中使用break,break生效是對於switch。 #include <stdio.h> int main() { int i_index;
豬豬的IT之路---Java成長之路day04(do...while,for,迴圈使用關鍵字,迴圈巢狀)
迴圈: While(迴圈條件){ 迴圈體; } 迴圈條件為true時迴圈或重複執行迴圈體,直到迴圈條件為false迴圈結束 注意: 1.迴圈開始條件一般要定義在迴圈結構前面 2.迴圈操作(迴圈體)中一般都應該存在步進操作(++或–) do…while迴圈語句 do…while迴圈語句和whi
SQL WHILE 迴圈 巢狀
摘錄自:http://imysqldba.blog.51cto.com/1222376/595433 - 內迴圈變數在選環後要重新賦初值,否則不能迴圈。 程式碼如下: DELIMITER $$ USE `qqfs_db_items`$$ DROPPROCEDURE
思考專案 求1+2的2次方+3的3次方+4的4次方+5的5次方+6的6次方的值。(異種迴圈巢狀)
/* * Copyright (c) 2014, 煙臺大學計算機學院 * All rights reserved. * 檔名稱:test.cpp * 作 者:劉暢 * 完成
MySQL用while實現for迴圈巢狀(插入學生成績資訊功能)
本次實驗的目的在於實現mysql中自動插入學生成績資訊,即給每個學生自動插入1~6號課程的成績, 屬性如下: 學生學號(i):1~23 課程號(j):1~6 成績:用rand()函式來實現自動填成績 此功能在java中用兩個for迴圈巢狀即可,程式碼如下: for(in
vue v-for 迴圈巢狀的探索(一)
舉一個簡單的例子:1、結構部分內容(1)html 、css部分<div class="Classfily" v-for="(subtitle) in pdata.subtitle"><el-row><!--分類--> <el-col
Lua 迴圈巢狀
Lua 程式語言中允許迴圈中嵌入迴圈。以下例項演示了 Lua 迴圈巢狀的應用。 語法 Lua 程式語言中 for 迴圈巢狀語法格式: for init,max/min value, increment do for init,max/min value, inc
for迴圈巢狀 案例列印各種形狀的星星
案例:各種形狀星星列印 //方形 /* for(var i=0;i<6;i++){ for(var j=0;j<6;j++){ &
迴圈巢狀如何執行和switch break區別
for語句裡巢狀if語句 當for語句裡第一個條件不滿足if語句時,則繼續執行for迴圈,若滿足,執行if語句 例: for(i=0;i<=4;i++) for(j=0;j<=4;j++) if(i!=j) { for(k=0;k<
【pykafka】爬蟲篇:python使用python連線kafka介紹(四)
本人菜雞,最近還更新python的爬蟲系列,有什麼錯誤,還望大家批評指出! 該系列暫時總共有4篇文章,連線如下: 【python】爬蟲篇:python連線postgresql(一):https://blog.csdn.net/lsr40/article/details/83311860
Java 知識點整理-10.Java集合框架 去除ArrayList中重複字串、自定義物件 棧和佇列 泛型 JDK5新特性 asList() toArray(T[] a) ArrayList迴圈巢狀
詳細標題:去除ArrayList中重複字串、自定義物件元素方式 棧和佇列 泛型 JDK5新特性(增強for迴圈 三種迭代(普通for、迭代器、增強for)中的元素能否刪除 靜態匯入 可變引數)Arrays工具類的asList() Collection中toArray(T[] a) 集合巢狀之Arra
for迴圈巢狀的使用
雙重迴圈排序 雙重迴圈排序演算法是一種非常簡單的排序演算法,這種演算法很容易讓人理解,也很實用,但是排序的效率很低。基本思路是用第一個數與後面的所有數進行比較,然後把最小的數放到第一個位置,然後用第二個數與後面的所有數進行比較,然後把第二個最小的數放到第二個位置,然後
兩種超詳細的遠端連線工具介紹(從安裝到使用)
眾所周知,個人電腦與伺服器不同,伺服器一般都是執行在IDC機房中,我們通常不會直接接觸到伺服器硬體,而是通過各種遠端方式對伺服器進行控制。於是遠端連線工具便應運而生了,下面簡單介紹一種常用的 linux 連線工具。 一、 Notepad++ Notepad++是一套非常有特色的自由
第11課 迴圈巢狀和演算法
一、迴圈巢狀 1、列印九九乘法表 for i in range(1, 10): # 行數 for j in range(1, i + 1): # print('{} * {} = {}'.format(j, i, i * j), end = '\t' ) #