SQL Server nested loop join 效率試驗
從很多網頁上都看到,SQL Server有三種Join的算法, nested loop join, merge join, hash join. 其中最常用的就是nested loop join.
在介紹nested loop join的很多文章裏,都提到如果兩個表做nested loop join,取行數較小的表作為外循環表,行數較多的表作為內循環表, join的效率會比較高.
其中之一的原因是如果內循環表做join的列上有合適的索引的話,那麽外循環的每一條輸入數據可以做索引的seek,這樣就不會把整個的內循環表讀一遍,尤其是內循環表比較大的話,節省的成本更高. 但是如果內外循環表都沒有合適的索引,這樣做join,為什麽效率也比較高呢?
舉個例子,外循環表有10行數據,內循環表有1000行數據,按照nested loop join 的算法,外循環表中取一條,和內循環表的所有數據匹配一遍,輸出匹配的數據行. 這樣就是要進行10*1000=10000次的匹配; 如果反過來,外循環1000行,內循環10行,那麽外循環表中取一條數據,內循環表中遍歷10行數據,總計也是1000*10=10000次. 粗看來都一樣啊..為什麽都說外循環表小的話,效率高呢? 做個試驗看看吧.
use tempdb
go
--創建兩個表,測試nested loop join的效率
CREATE TABLE TempA (string VARCHAR(1000))
go
CREATE TABLE TempB (string VARCHAR(1000))
go
--插入數據, 讓表TempA中的數據剛好存在1頁裏
INSERT INTO TempA SELECT REPLICATE(‘a‘ , 1000)
INSERT INTO TempA SELECT REPLICATE(‘b‘ , 1000)
INSERT INTO TempA SELECT REPLICATE(‘c‘ , 1000)
INSERT INTO TempA SELECT REPLICATE(‘d‘ , 1000)
INSERT INTO TempA SELECT REPLICATE(‘e‘ , 1000)
INSERT INTO TempA SELECT REPLICATE(‘f‘ , 1000)
INSERT INTO TempA SELECT REPLICATE(‘g‘ , 1000)
--往TempB中插入數據,讓TempB的數據是TempA的100倍
insert into TempB select * from TempA
go 100
--檢驗一下表TempA 和 TempB的大小
set statistics io on
select * from TempA
select * from TempB
--返回的結果如下:
/*
Table‘TempA‘. Scan count 1, logical reads 1
Table‘TempB‘. Scan count 1, logical reads 100
*/
--由此可以看出表TempA有7行,存儲在1個頁; TempB有700行,存儲在100個頁裏.
--執行以下查詢,將TempA作為外循環表,TempB作為內循環表,看看執行的成本如何
SELECT *FROM TempA a INNER LOOP JOIN TempB b
ONa.string = b.string OPTION (FORCE order)
/*
Table‘TempB‘. Scan count 1, logical reads 700
Table‘TempA‘. Scan count 1, logical reads 1
*/
從結果可以看出從TempA讀了1個頁,從TempB讀了700個頁,合計701個邏輯讀, 也就是說外循環的表,做一次全表讀,有多少頁就有多少邏輯讀; 內循環的表,對應外循環表的每1條記錄,都要讀一次全表讀,即7乘以100,700個邏輯讀.
如果按照這個規律,調換內外循環表的位置,得到的邏輯讀應該是 TempB的一次全表讀, 100個邏輯讀加上700行乘以TempA的全表讀(1頁),就是700個邏輯讀,合計是800個邏輯讀.
--對調一下join的順序,再看看執行成本:
SELECT *FROM tempb b INNER LOOP JOIN tempa a
ONa.string = b.string OPTION(FORCE ORDER)
/*
Table‘TempA‘. Scan count 1, logical reads 700
Table‘TempB‘. Scan count 1, logical reads 100
*/
果不其然,和預計的一樣.
所以在這種假定的情況下,外循環表較小的話,join的成本更低.
實驗的表結構比較特殊,如果往一般情況推演一下,可以做出這樣的假設:
假設表X有a頁,平均每頁有b行,表Y有c頁,平均每頁有d行.
則以表X為外循環,表Y為內循環,則nested loop join的成本是 a+(a*b*c), 而已表Y為外循環,表X為內循環,則nested loop join的成本是 c+(c*d*a)
SQL Server nested loop join 效率試驗