1. 程式人生 > >SQL Server nested loop join 效率試驗

SQL Server nested loop join 效率試驗

看看吧 輸入 temp 兩個 stat from lock 應該 varchar

從很多網頁上都看到,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 效率試驗