多表連線的三種方式詳解 HASH JOIN MERGE JOIN NESTED LOOP【3】
SQL server 內部實現了三種類型的內連線運算,大多數人從來沒有聽說過這些連線型別,因為它們不是邏輯連線也很少被用於程式碼中。那麼它們什麼時候會被用到呢?答案是要依情況而定。這就意味著要依賴於記錄集和索引。查詢優化器總是智慧的選擇最優的物理連線型別。我們知道SQL優化器建立一個計劃開銷是基於查詢開銷的,並依據此來選擇最佳連線型別。
那查詢優化器究竟是怎樣從內部選擇連線型別的呢?
SQLServer在內部為查詢優化器對連線型別的選擇實現了一些演算法,讓我們來看下面的一些練習示例,最後來做總結。
首先我給出一些基本的思想,連線是怎樣工作什麼時候工作,優化器又是怎樣決定使用哪種型別的內連線。
· 取決於表大小
· 取決於連線列是否有索引
· 取決於連線列是否排序
測試環境:
記憶體:4GB
資料庫伺服器:SQLServer 2008 (RTM)
- createtable tableA (id int identity ,namevarchar(50))
- declare @i int
- set @i=0
- while (@i<100)
- begin
- insertinto tableA (name)
- selectnamefrom master.dbo.spt_values
-
set
- end
- --select COUNT(*) from dbo.tableA --250600
- go
- createtable tableB (id int identity ,namevarchar(50))
- declare @i int
- set @i=0
- while (@i<100)
- begin
- insertinto tableB (name)
- selectnamefrom master.dbo.spt_values
- set @[email protected]+1
- end
-
-- select COUNT(*) from dbo.tableB --250600
- select * from dbo.tableA A join tableB B
- on (a.id=b.id)
測試1:大表,沒有索引
現在來建立一個聚族索引:
- createunique clustered index cx_tableA on tableA (id)
- createunique clustered index cx_tableB on tableB (id)
測試1:大表,有索引
如果連線中的任何一個表有索引那麼將採用Hash Join。我並沒有貼上所有結果截圖,如果你感興趣你可以刪除任何一個表中的索引來做測試。
測試2:中表,沒有索引
首先建立表:
- createtable tableC (id int identity,namevarchar(50))
- insertinto tableC (name)
- selectnamefrom master.dbo.spt_values
- -- select COUNT(*) from dbo.tableC --2506
- createtable tableD (id int identity,namevarchar(50))
- insertinto tableD (name)
- selectnamefrom master.dbo.spt_values
- select * from dbo.tableC C join tableD D
- on (C.id=D.id)
- -- select COUNT(*) from dbo.tableD --2506
測試2:中表,有索引
首先還是建立一個聚族索引:
- createunique clustered index cx_tableC on tableC (id)
- createunique clustered index cx_tableD on tableD (id)
對於中等大小的表,如果連線中的任何一個表有索引,那麼將採用Merge Join。
測試3:小表,沒有索引- createtable tableE (id int identity,namevarchar(50))
- insertinto tableE (name)
- selecttop 10 namefrom master.dbo.spt_values
- -- select COUNT(*) from dbo.tableE --10
- createtable tableF (id int identity,namevarchar(50))
- insertinto tableF (name)
- selecttop 10 namefrom master.dbo.spt_values
- -- select COUNT(*) from dbo.tableF --10
測試3:小表,有索引
建立聚族索引:
- createunique clustered index cx_tableE on tableE (id)
- createunique clustered index cx_tableF on tableF (id)
對於小表,如果任何一個表中有索引,那麼將採用Nested Loop Join。
同樣也可以從另一個方向來做比較,比如大表對比中表對比小表。
- select * from dbo.tableA A join tableC C
- on (a.id=C.id)
- select * from dbo.tableA A join tableE E
- on (a.id=E.id)
- select * from dbo.tableC C join tableE E
- on (C.id=E.id)
在這種情況下若所有或部分表都有索引則採用Nested Loop Join,如果都沒有則使用HashJoin。
當然你也可以強制優化器使用任何一種連線型別,但這並不是一種值得推薦的做法。查詢優化器很智慧,能夠動態的選擇最優的一個。這裡我只是顯示呼叫了MergeJoin,所以優化器使用MergeJoin替代本來應使用HashJoin (測試1沒有索引)。
- select * from dbo.tableA A join tableB B
- on (A.id=B.id)option (merge join)
- select * from dbo.tableA A inner merge join tableB B
- on (A.id=B.id)
表1 測試唯一聚族索引
根據上表:
Ø 如果兩個表都沒有索引則查詢優化器內部會選擇Hash Join
Ø 如果兩個表都有索引則內部會選擇Merge Join(大表)/NestedLoop Join(小表)
Ø 如果其中的一個表有索引則查詢優化器內部會選擇Merge Join(中表)/HashJoin(大表)/NestedLoop Join(小表&大表 vs 小表)
表2 測試聚族索引(create
clustered index
cx_tableA on
tableA (id))
Table size |
With index (Both) |
Without Index(Both) |
Either of table has index |
|
Big (Both) |
HASH |
HASH |
HASH |
|
Medium (Both) |
HASH |
HASH |
HASH |
|
Small (Both) |
NESTED LOOP |
NESTED LOOP |
HASH |
|
Big Vs Small(medium) |
HASH |
HASH |
HASH |
根據上表:
這個測試是在沒有使用唯一聚族索引下完成,可以知道如果建立索引的時候沒有使用UNIQUE關鍵字則無法保證SQLServer會知道這是UNIQUE資料,所以它預設會建立4位元組整數來作為唯一識別符號。
根據上表如果建立聚族索引沒有使用Unique關鍵字則不會使用MergeJoin。
謝謝@Dave的郵件,現在加上第二個圖表了。
總結:
Merge Join
Merge Join是為那些在連線列上有索引的表,索引可以是聚族索引或者非聚族索引。Merge是這種情況最好的Join型別,需要兩個表都有索引,所以它已經排好序並更容易匹配和返回資料。
Hash Join
Hash Join是為那些沒有索引或者其中任一個有索引的大表。對於這種情況它是最好的Join型別,為什麼呢?因為它能夠很好的工作於沒有索引的大表和並行查詢的環境中,並提供最好的效能。大多數人都說它是Join的重型升降機。
Nested Loop Join
Nested Loop Join是為那些有索引的小表或其中人一個有索引的大表。它對那些小表連線,需要迴圈執行從一個到另一個表的按行比較的情況下工作最好的。
我希望你現在能理解查詢優化器是如何選擇最優的查詢型別。
相關推薦
多表連線的三種方式詳解 hash join、merge join、 nested loop
在多表聯合查詢的時候,如果我們檢視它的執行計劃,就會發現裡面有多表之間的連線方式。多表之間的連線有三種方式:Nested Loops,Hash Join 和 Sort Merge Join.具體適用哪種型別的連線取決於 當前的優化器模式 (ALL_ROWS 和 RULE) 取決於表大小 取決於連線列
多表連線的三種方式詳解 HASH JOIN MERGE JOIN NESTED LOOP
在多表聯合查詢的時候,如果我們檢視它的執行計劃,就會發現裡面有多表之間的連線方式。 之前打算在sqlplus中用執行計劃的,但是格式看起來有點亂,就用Toad 做了3個截圖。
多表連線的三種方式詳解 HASH JOIN MERGE JOIN NESTED LOOP【3】
SQL server 內部實現了三種類型的內連線運算,大多數人從來沒有聽說過這些連線型別,因為它們不是邏輯連線也很少被用於程式碼中。那麼它們什麼時候會被用到呢?答案是要依情況而定。這就意味著要依賴於記錄集和索引。查詢優化器總是智慧的選擇最優的物理連線型別。我們知道SQL優
【REACT NATIVE 系列教程之四】重新整理元件RENDER(重新渲染)的三種方式詳解
開發過遊戲的都應該很清楚,“刷屏”是多麼的重要。其實開發應用也如此,當元件的資料被修改後,如何及時更新元件呈現出最新的資料與效果一樣至關重要。那麼這裡Himi大概講三種常用的方式:this.setState() 【最為常用】這是在事件處理函式中和請求回撥函式中觸發 UI 更新的主要方法。一般情況下setSt
spring建立物件的三種方式詳解
前言 我們知道spring框架的核心就是IOC容器了,那麼IOC容器主要的作用就是建立物件和處理物件之間的依賴關係。本文主要講解IOC容器建立物件的三種方式。 建立物件的三種方式 1) 呼叫無引數構造器 2) 帶引數構造器 3) 工廠建立物件
css3中建立動畫的三種方式詳解
$div1.transition({ transform : "translateX(300px)" },3000,"linear", function(){ $div2.transition({ transform : "translateX(300px)" },30
mysql備份的三種方式詳解
mysql> FLUSH TABLES WITH READ LOCK; 請求讀鎖 注:不要退出,另起一個終端: mysql> SHOW MASTER STATUS; 檢視二進位制檔案的位置 +------------------+----------+----------
javascript函式定義三種方式詳解
定義函式的三種方式 function語句式 function test1() { console.info("test1"); } 函式的直接變數 ECMAScript var test2 = function () { cons
往HIVE表中匯入匯出資料的幾種方式詳解
一:往HIVE表中匯入匯出資料語法結構:[ ]帶括號的表示可選擇欄位LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTOTABLE tablename
用 Python 連線 MySQL 的幾種方式詳解
儘管很多 NoSQL 資料庫近幾年大放異彩,但是像 MySQL 這樣的關係型資料庫依然是網際網路的主流資料庫之一,每個學 Python 的都有必要學好一門資料庫,不管你是做資料分析,還是網路爬蟲,Web 開發、亦或是機器學習,你都離不開要和資料庫打交道,而 MySQL 又是最
JS創建對象的幾種方式詳解
演員 sta say object ron 操作 tar obj 構造 Js是一門面向對象的語言,裏面沒有類的思想,所以直接是創建對象,下面介紹幾種創建對象的方法: 1.對象字面量的方法:記住鍵值對格式:{key:value,key :value} 實例: Var
new和delete的三種形式詳解
分別是 額外 ID 調用 pre else class code alloc 一、new操作符、delete操作符 class String { public: String(const char *str="") { if
排列硬幣 arrange coins 三種解法詳解
* 排列硬幣 * https://leetcode-cn.com/problems/arranging-coins/description/ * 你總共有 n 枚硬幣,你需要將它們擺成一個階梯形狀,第
Mysql 刪除資料表的三種方式
刪除程度可從強到弱如下排列: 1. drop table tb; drop 是直接將表格刪除,無法找回。例如刪除 user 表: drop table user; 2. truncate (table) tb; truncate 是刪除表中所有資
jQuery使用JSONP實現跨域獲取資料的三種方法詳解
本文例項講述了jQuery使用JSONP實現跨域獲取資料的三種方法。分享給大家供大家參考,具體如下: 第一種方法是在ajax函式中設定dataType為'jsonp' $.ajax({ dataType: 'jsonp', url: 'http://www.a
PHP實現鏈式操作的三種方法詳解
ret 思想 ont 過濾字符 一個 詳解 rgs 通過 span 這篇文章主要介紹了PHP實現鏈式操作的三種方法,結合實例形式分析了php鏈式操作的相關實現技巧與使用註意事項,需要的朋友可以參考下 本文實例講述了PHP實現鏈式操作的三種方法。分享給大家供大家參考,具
Spring boot實現熱部署的兩種方式詳解
熱部署是什麼大家都知道在專案開發過程中,常常會改動頁面資料或者修改資料結構,為了顯示改動效果,往往需要重啟應用檢視改變效果,其實就是重新編譯生成了新的 Class 檔案,這個檔案裡記錄著和程式碼等對應的各種資訊,然後 Class 檔案將被虛擬機器的 ClassLoader 載入。而熱部署正是利用了這個特點,它
SpringMVC的controller向jsp傳遞資料的五種方式詳解
第一種 使用model來儲存資料到前臺我的專案目錄為我的controller頁面程式碼@RequestMapping("/demo") public String Model(Model model
web頁面跳轉幾種方式詳解
在做web開發中,頁面跳轉的方式有很多種,然而有些時候這些跳轉如何用到恰到好處卻很容易被忽視。 客戶端觸發跳轉有如下幾種 使用meta元資訊 ? 1 2 <!--如下表示
SpringMVC4.3x教程之七國際化的三種實現詳解
國際化(internationalization)是設計和製造容易適應不同區域要求的產品的一種方式。它要求從產品中抽離所有地域語言,國家/地區和文化相關的元素。換言之,應用程式的功能和程式碼設計考慮在不同地區執行的需要,其程式碼簡化了不同本地版本的生產。開發這樣