>最近我有一个性能调优的经验,我想在这里分享它,并试图理解为什么会发生这种改进。
在我的一个过程中,我想返回一个基于其他一些记录存在的数据集。
我的查询:
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 …
我已经看到亚当·马查尼奇在对安德鲁·凯利的帖子的评论中指出了这一点 存在与计数(*) - 战斗永无止境:
有趣的是,在SQL Server 2005中,如果有一个索引 可用于允许搜索,COUNT(*)> 0 测试将得到优化,并且 行为与存在相同。
亚当在那里提供了一个演示。
2)有时EXISTS
比COUNT
更糟糕:
如果存在,则花费的时间比嵌入的选择语句长
检查存在与存在优于计数!不?
正如保罗·怀特(Paul White)所写:
使用
EXISTS
引入了行目标,其中优化程序生成 旨在快速找到第一行的执行计划。在这样做的过程中, 它假定数据是均匀分布的。例如,如果 统计数据显示,100,000 行中有 100 个预期匹配项,它 将假设它只需要读取 1,000 行才能找到第一个 火柴。如果这样做,这将导致执行时间比预期的更长 事实证明,假设是错误的。例如,如果 SQL Server 选择 一种访问方法(例如无序扫描),恰好找到 第一个匹配值在搜索的后期很晚,它可能会导致 几乎完全扫描。另一方面,如果匹配的行碰巧 在前几行中找到,性能会非常好。 这是行目标的基本风险 - 不一致 性能。
如果你的数据分布是偏斜的,或者你预计在大多数情况下COUNT
为零(即无论如何你都必须扫描整个表才能得到答案),那么你应该尝试在没有行目标的情况下获得计划(即没有EXISTS
)。
您已经发现的一种明显方法是将COUNT
的结果保存到变量中。