SQL Server-聚焦INNER JOIN AND IN性能分析(十四)

前言

本節咱們來說講聯接綜合知識,咱們在大多教程或理論書上都在講用哪好,哪一個性能不如哪一個的性能,可是真正講到問題的實質卻不是太多,因此纔有了本系列每一篇的篇幅不是太多,可是確定是我用心去查找許多資料而寫出,簡短的內容,深刻的理解,Always to review the basics。性能

初次探討INNER JOIN和IN性能分析

接下來咱們看第一篇聯接綜合知識講解INNER JOIN和IN的比較分析,咱們經過建立表來看INNER JOIN。測試

建立測試表1spa

CREATE TABLE Table1  (
 id INT IDENTITY PRIMARY KEY,
 SomeColumn CHAR(4),
 Filler CHAR(100)
)

插入測試數據3d

Insert into Table1(SomeColumn) Values (1),(2),(3),(4),(5)

建立測試表2並插入數據code

USE TSQL2012
GO

CREATE TABLE Table2  (IntCol int)
Insert into Table2 (IntCol) Values (1),(2),(2),(3),(4),(5),(5)

接下來咱們對測試表1和測試表2中的SomeColumn和IntCol進行JOINblog

USE TSQL2012
GO

SELECT *
FROM Table1 b 
 INNER JOIN Table2 s ON b.SomeColumn = s.IntCol

此時咱們看到兩個測試表中都返回7行數據,由於在測試表2中有重複的數據都匹配上全部測試表1返回全部數據。此時咱們再來看看IN的查詢教程

USE TSQL2012
GO

SELECT *
 FROM Table1
 WHERE SomeColumn IN (Select IntCol FROM Table2)

此時則返回5條數據,從這裏咱們知道INNER JOIN和IN仍是有很大的區別,可是若在測試表2中沒有重複的數據,同時在測試表2中沒有須要的列,此時則查詢出的數據和測試表1是同樣的,此時兩者在性能上有什麼區別呢?接下來咱們在建立大量數據的前提下來進行測試看看。索引

建立兩個測試表性能分析

CREATE TABLE BigTable (
id INT IDENTITY PRIMARY KEY,
SomeColumn UNIQUEIDENTIFIER NOT NULL,
Filler CHAR(100)
)
 
CREATE TABLE SmallerTable (
id INT IDENTITY PRIMARY KEY,
LookupColumn UNIQUEIDENTIFIER NOT NULL,
SomeArbDate DATETIME DEFAULT GETDATE()
)

在BigTable表SomeColumn列中插入100萬條數據class

INSERT INTO BigTable (SomeColumn)
SELECT NEWID()
FROM dbo.Nums
WHERE n<1000001

取出BigTable中的25%數據插入到SmallerTable表LookupColumn列中

USE TSQL2012
GO

INSERT INTO SmallerTable (LookupColumn)
SELECT DISTINCT SomeColumn
FROM BigTable TABLESAMPLE (25 PERCENT)

這裏咱們分三種狀況來測試。

(1)未創建索引比較INNER和JOIN

SELECT BigTable.ID, SomeColumn
FROM BigTable
WHERE SomeColumn IN (SELECT LookupColumn FROM dbo.SmallerTable)
 
SELECT BigTable.ID, SomeColumn
FROM BigTable
INNER JOIN SmallerTable ON dbo.BigTable.SomeColumn = dbo.SmallerTable.LookupColumn

 

從上看出此時在不管是查詢開銷仍是IO上均沒有什麼差別,下面咱們再來看看創建索引的狀況

(2)創建非惟一非彙集索引比較INNER JOIN和IN

CREATE INDEX idx_BigTable_SomeColumn ON BigTable (SomeColumn)
CREATE INDEX idx_SmallerTable_LookupColumn ON SmallerTable (LookupColumn)

此時咱們發如今創建非惟一非彙集索引的狀況兩者在查詢開銷上開始有了比較大的差別,INNER JOIN的開銷是IN的兩倍而IO幾乎是等同的。

(3)創建惟一非彙集索引比較INNER JOIN和IN

CREATE UNIQUE INDEX idx_BigTable_SomeColumn ON BigTable (SomeColumn)
CREATE UNIQUE INDEX idx_SmallerTable_LookupColumn ON SmallerTable (LookupColumn)

此時爲什麼索引變爲惟一彙集索引兩者性能開銷卻一致了呢?有點納悶,同時到這裏爲止是否是說明IN的查詢性能比JOIN的性能更好呢,徹底顛覆咱們的想法,在本文前言咱們討論過在教程中都會給出大部分JOIN比EXISTS性能好,而EXISTS比IN性能好,凡是仍是動手實踐,親自驗證纔是王道,咱們只能得出通常性結論:通常來講,JOIN比EXISTS性能好,而EXISTS比IN性能好僅此而已。這都是通常性狀況,本系列須要講述的是何時應該用EXISTS,何時應該用JOIN,還有何時應該用IN,後續內容會陸續討論這些內容。好了,有點跑題了,上述咱們經過100萬條數據得出IN的性能接近是INNER JOIN性能的兩倍,徹底出乎你個人意料,帶着這個疑問,接下來咱們進一步進行探討。

進一步探討INNER JOIN和IN性能分析 

上述在SmallerTable表從BigTable表中取出的25%的數據都是惟一的,接下來咱們將這25%數據的一部分設置爲重複的。咱們隨便從BigTable表中取出SomeColumn這列的數據,而後將SmallerTable表中的LookupColumn這列的數據設置重複的10000條,以下

USE TSQL2012
GO

UPDATE dbo.SmallerTable SET LookupColumn = '0067cb6c-64e1-46cc-b7f2-334a7dd812ff'
WHERE id>=1 AND id<=10000

此時咱們查詢包括重複的這10000條

USE TSQL2012
GO

SELECT BigTable.ID, SomeColumn
FROM BigTable
WHERE SomeColumn IN (SELECT LookupColumn FROM dbo.SmallerTable)
 
SELECT BigTable.ID, SomeColumn
FROM BigTable
INNER JOIN SmallerTable ON dbo.BigTable.SomeColumn = dbo.SmallerTable.LookupColumn

此時結果仍是IN性能比INNER JOIN性能要接近一半,接下來咱們在查詢SmallerTable表時將重複的LookupColumn列數據去除,此時咱們查詢變爲以下:

USE TSQL2012
GO

SELECT BigTable.ID, SomeColumn
FROM BigTable
WHERE SomeColumn IN (SELECT LookupColumn FROM dbo.SmallerTable)
 
SELECT BigTable.ID, SomeColumn
FROM BigTable
INNER JOIN (SELECT DISTINCT LookupColumn FROM dbo.SmallerTable) AS s
ON s.LookupColumn = dbo.BigTable.SomeColumn

終於查詢開銷和上述不同了,此時兩者查詢性能開銷是一致的,相信到了這裏咱們應該很清楚了。經過上述大量篇幅的貼圖和比較咱們能夠得出INNER JOIN和IN的性能開銷使用場景,當咱們在初步探討INNER JOIN和IN的性能分析時,當創建非惟一彙集索引時IN性能接近是INNER JOIN的兩倍,而當創建惟一彙集索引時,此時性能開銷一致,難免有點納悶,當咱們繼續向下探討時終於明白了這個緣由,至此咱們最終得出INNER JOIN和IN的性能開銷結論。

INNER JOIN和IN性能開銷結論:當INNER JOIN表中列數據是惟一的,此時INNER JOIN和IN的性能開銷是相同的,當INNER JOIN表中列數據是重複的,此時IN性能要INNER JOIN要好。

總結

本節咱們詳細敘述了INNER JOIN和IN的性能分析,最終得出一致性結論,下節咱們開始討論NOT EXISTS和NOT IN性能分析,簡短的內容,深刻的理解,咱們下節再會,good night。

相關文章
相關標籤/搜索