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


前言

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

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

接下來我們看第一篇聯接綜合知識講解INNER JOIN和IN的比較分析,我們通過創建表來看INNER JOIN。

創建測試表1

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

插入測試數據

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

創建測試表2並插入數據

USE TSQL2012
GO

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

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

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萬條數據

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。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM