sql - 为什么将查询计数分配给变量比直接检查它效果更好?

标签 sql sql-server tsql sql-server-2008-r2 query-performance

最近我有一次性能调优的经历,我想在这里分享一下,并试图理解为什么会出现这种改进。

在我的一个过程中,我想根据其他一些记录的存在返回一个数据集。

我的查询:

IF (SELECT COUNT(1) FROM ...) > 0
    SELECT …

此查询大约需要 5 秒。

我进行了更改,并将 IF 语句的输出分配给一个变量,然后检查它。

DECLARE @cnt INT = 0
SELECT @cnt = COUNT(1) FROM …

IF @cnt > 0
    SELECT …

这个运行时间不到 1 秒。

我也尝试了IF EXISTS,但在改进之前得到了相同的结果(5秒)。

我非常想知道为什么编译器的行为如此不同,以及是否有任何特定的答案。

谢谢

最佳答案

这里有两个部分。

1) SQL Server 优化器转换

IF (SELECT COUNT(1) FROM ...) > 0
    SELECT …

进入

IF EXISTS(SELECT 1 FROM ...)
    SELECT …

我已经看到 Adam Machanic 在对 Andrew Kelly 的帖子的评论中指出了这一点 Exists Vs. Count(*) - The battle never ends :

It's interesting to note that in SQL Server 2005 if there is a index available to allow a seek, the COUNT(*) > 0 test will be optimized and behave the same as EXISTS.

Adam 提供了一个演示。

<小时/>

2) 有时 EXISTSCOUNT 更糟糕:

IF EXISTS taking longer than embedded select statement

Check existence with EXISTS outperform COUNT! … Not?

正如保罗·怀特 wrote :

Using EXISTS introduces a row goal, where the optimizer produces an execution plan aimed at locating the first row quickly. In doing this, it assumes that the data is uniformly distributed. For example, if statistics show there are 100 expected matches in 100,000 rows, it will assume it will have to read only 1,000 rows to find the first match.

This will result in longer than expected execution times if this assumption turns out to be faulty. For example, if SQL Server chooses an access method (e.g. unordered scan) that happens to locate the first matching value very late on in the search, it could result in an almost complete scan. On the other hand, if a matching row happens to be found amongst the first few rows, performance will be very good. This is the fundamental risk with row goals - inconsistent performance.

<小时/>

如果您的数据分布存在偏差,或者您预计在大多数情况下 COUNT 为零(即您必须扫描整个表格才能获得答案),那么您应该尝试获得没有行目标的计划(即没有EXISTS)。

正如您已经发现的一个明显的方法是将 COUNT 的结果保存到变量中。

关于sql - 为什么将查询计数分配给变量比直接检查它效果更好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34912804/

相关文章:

sql - 如何解决 SQL Server 中的性能问题

sql - t sql select语句中的子查询

c++ - 为什么我的 C++ 扩展存储过程不写入控制台?

sql - 使用索引按字符串前缀选择

sql - 连接2个表并计算SQL中特定字段的出现次数

php - 带有 LinQ 过滤器和 jQuery tmpl 示例的 jQuery AJAX 请求

sql - SQL Server 2012如何计算各个阶段每个id的总支付金额并减少每个阶段后的支付金额

sql - 我可以在选项卡上显示存储过程名称吗

sql - 如何从 INSERT INTO SELECT FROM 查询中检索新键?

没有指定列的 SQL Server 插入