2013-05-02 66 views
6

我工作在以下查詢:SQL內連接VS子查詢

Query 1: SELECT * From TabA INNER JOIN TabB on TabA.Id=TabB.Id 
Query 2: SELECT * From TabA WHERE Id in (SELECT Id FROM TabB) 
Query 3: SELECT TabA.* From TabA INNER JOIN TabB on TabA.Id=TabB.Id 

我調查這些查詢與SQL Server探查,發現了一些有趣的事實。

  • 查詢1需要2.312秒
  • 查詢2取0.811秒
  • 查詢3取0.944秒

塔巴 48716行

塔布 62719行

基本上我問的是爲什麼查詢1需要很長時間,而不是查詢3.我已經知道'子查詢'比內部連接慢,但在這裏查詢2是最快的;爲什麼?

+1

爲什麼會有'C#'標記?這是無關緊要的。 – 2013-05-02 14:01:20

+6

你是否多次運行這些計時?查詢性能受到表格是否加載到頁面緩存中的影響很大。 – 2013-05-02 14:03:24

+3

請注意緩存。你是否在每次查詢後清理它? – 2013-05-02 14:03:47

回答

3

如果我不得不猜測我會說這是因爲查詢1是從兩個表中拉數據。查詢2和3(同時aprox)只是拉取TabA的數據。你可以檢查此

的一種方法是通過運行以下:

SET STATISTICS TIME ON 
SET STATISTICS IO ON 

當我跑

SELECT * FROM sys.objects 

我看到下面的結果。

SQL Server parse and compile time: 
    CPU time = 0 ms, elapsed time = 104 ms. 

(242 row(s) affected) 
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'sysschobjs'. Scan count 1, logical reads 10, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'syssingleobjrefs'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'syspalnames'. Scan count 1, logical reads 2, physical reads 1, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 866 ms. 

您可以查看每個查詢的掃描次數,邏輯讀取次數和物理讀取次數。物理讀取當然需要更長的時間,並代表從磁盤讀取到緩存中。如果你所有的讀取都是邏輯讀取,那麼你的表格完全在緩存中。

我願意,如果你看看你會看到塔布上查詢1比更大量的邏輯讀取下注2和3

編輯:

只是出於好奇,我做一些測試和博客結果here

+0

好的博客文章Kenneth。 – 2013-05-03 09:30:48

1

這只是因爲SQL不必執行JOIN。您只是執行兩個查詢,並且只有其中一個具有WHERE子句。

我必須承認我沒有想到這會有很大的不同。

+0

不錯!但是子查詢應該比內部連接查詢慢。 [參考](http://stackoverflow.com/questions/141278/subqueries-vs-joins) – 2013-05-02 14:27:03

+0

這就是教科書說的,是的,但它更有意義的是,在幕後發生的事情越少,你越快得到你的結果。我想知道如果您從JOIN查詢創建視圖並且測試了性能,會發生什麼情況。順便說一下,視圖或存儲過程比常規JOIN查詢快得多,因爲執行計劃已存儲。 – 2013-05-02 14:44:57

2

查詢1:
該查詢返回TabA和TabB中所有行的行,因此兩個表的覆蓋索引都需要包含來自每個表的所有行。要查看究竟發生了什麼,您需要查看查詢計劃。

查詢2 &查詢3:
您返回TabA的所有行,並且只需要TabB的Id列的索引。我猜這裏的區別與表統計有關,但是(再一次)我們必須看到查詢計劃確切地知道發生了什麼。