2013-05-02 68 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列的索引。我猜这里的区别与表统计有关,但是(再一次)我们必须看到查询计划确切地知道发生了什么。