为啥当我的查询有 Where 时 SQL Server 有更多的 I/O?

Posted

技术标签:

【中文标题】为啥当我的查询有 Where 时 SQL Server 有更多的 I/O?【英文标题】:Why SQL Server has more I/O when my query has Where?为什么当我的查询有 Where 时 SQL Server 有更多的 I/O? 【发布时间】:2014-12-03 00:53:29 【问题描述】:

我使用SQL Server 2012 并编写此查询:

DBCC DROPCLEANBUFFERS;
SET STATISTICS IO ON; 

我在上面写了两行用于清洁现金并设置统计信息。

这些是我的查询:

SELECT C.custid, C.companyname, O.orderid, O.orderdate 
FROM Sales.Customers AS C 
     INNER JOIN Sales.Orders AS O 
        ON C.custid = O.custid 

SELECT C.custid, C.companyname, O.orderid, O.orderdate 
FROM Sales.Customers AS C 
    INNER JOIN Sales.Orders AS O 
        ON C.custid = O.custid 
WHERE O.custid < 5

但我得到了这个统计数据:

对于第一个查询: (受影响的 830 行) 表“工作台”。扫描计数 0,逻辑读取 0,物理读取 0, 预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。 表“订单”。扫描计数 1,逻辑读取 21,物理读取 1, 预读读取 25,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。 表“客户”。扫描计数 1,逻辑读取 2,物理读取 1, 预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。

对于第二个查询: (30 行受影响) 表“客户”。扫描计数 0,逻辑读取 60,物理读取 1, 预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。 表“订单”。扫描计数 1,逻辑读取 21,物理读取 0,预读读取 0, lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。

考虑到行数,为什么第二个查询中的logical reads 比第一个要多?

【问题讨论】:

【参考方案1】:

无条件:

Table 'Customers'. Scan count 1, logical reads 2

有条件:

Table 'Customers'. Scan count 0, logical reads 60,

区别在于第一种情况下的扫描(速度很快,因为表很小)与通过索引的重复随机访问(不是那么快,因为表太小而无法理解) )。

但是请注意,由嵌套循环连接引起的所有这些重复的逻辑读取不会导致实际的 I/O(物理读取),因为它们会一遍又一遍地访问相同的几个块(这些块在您的缓冲区缓存工作集)。

这会给您带来性能问题吗?看起来查询已经足够快了。希望优化器能正确处理真正重要的情况(即涉及大表的情况)。

【讨论】:

谢谢,什么是 Worktable? 这是用于收集 JOIN 数据的临时结构。第二个查询显然不需要它,因为这是通过索引访问直接选择行。您可以为这两个查询附加执行计划。这应该会显示更多细节。 你有它:哈希联接(需要工作表)与嵌套循环【参考方案2】:

也许第一个查询可以使用索引,而第二个查询不能。 custid 可能只是一个包含列,而不是索引中的键列。 您可以在执行计划中看到这一点。

【讨论】:

这很有趣。我将在我的 Owen SQL 安装中对此进行测试。但是现在,我会检查 Sales.Orders 上是否有索引,其中 custid 作为键,orderid 和 orderdate 作为 INCLUDED 列

以上是关于为啥当我的查询有 Where 时 SQL Server 有更多的 I/O?的主要内容,如果未能解决你的问题,请参考以下文章

为啥,当我在 WCF 服务中模拟时,当我尝试运行 LINQ to SQL 查询时,我的服务不能加载 System.Transactions?

为啥 SQL "WHERE" 从表中返回值是小写的? [复制]

为啥要在 SQL 中使用 WHERE 1=0 语句?

在 SELECT 语句中使用自定义函数时,为啥我的 SQL 查询的输出显示不正确?

为啥我的 SQL 查询会出现内部服务器错误?

为啥聚集函数不能出现在where子句中