sql-server – IF EXISTS比嵌入式select语句花费更长时间

前端之家收集整理的这篇文章主要介绍了sql-server – IF EXISTS比嵌入式select语句花费更长时间前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
当我运行以下代码时,它需要22.5分钟,并完成1.06亿次读取.但是,如果我只运行内部select语句,它只需要15秒,并且读取264k.作为旁注,select查询不返回任何记录.

任何想法为什么IF EXISTS会让它运行得更长并且读取更多?我还将select语句改为SELECT TOP 1 [dlc].[id],我在2分钟后杀了它.

作为临时修复,我将其更改为count(*)并将该值赋给变量@cnt.然后它做IF 0<>. @cnt声明.但我认为EXISTS会更好,因为如果在select语句中返回了记录,它会在找到至少一条记录后停止执行扫描/搜索,而count(*)将完成整个查询.我错过了什么?

IF EXISTS
   (SELECT [dlc].[ID]
   FROM TableDLC [dlc]
   JOIN TableD [d]
   ON [d].[ID] = [dlc].[ID]
   JOIN TableC [c]
   ON [c].[ID] = [d].[ID2]
   WHERE [c].[Name] <> [dlc].[Name])
BEGIN
   <do something>
END

解决方法

Any idea why the IF EXISTS would make it run so much longer and do so many more reads? I also changed the select statement to do SELECT TOP 1 [dlc].[id] and I killed it after 2 minutes.

正如我在回答这个相关问题时解释的那样:

How (and why) does TOP impact an execution plan?

使用EXISTS引入了一个行目标,优化器生成一个旨在快速定位第一行的执行计划.在此过程中,它假定数据是均匀分布的.例如,如果统计信息显示100,000行中有100个预期匹配项,则假设它必须只读取1,000行才能找到第一个匹配项.

如果这个假设结果有问题,这将导致执行时间超过预期.例如,如果sql Server选择在搜索中很晚就找到第一个匹配值的访问方法(例如无序扫描),则可能导致几乎完全扫描.另一方面,如果在前几行中发现匹配的行,则性能将非常好.这是行目标的基本风险 – 性能不一致.

As a temporary fix I have changed it to do a count( * ) and assign that value to a variable

通常可以重新构造查询,以便不分配行目标.如果没有行目标,查询仍然可以在遇到第一个匹配行时终止(如果写得正确),但执行计划策略可能会有所不同(希望更有效).显然,count(*)将需要读取所有行,因此它不是一个完美的替代方案.

如果您运行的是sql Server 2008 R2或更高版本,则通常也可以使用documented and supported trace flag 4138获取没有行目标的执行计划.也可以使用supported hint OPTION(QUERYTRACEON 4138)指定此标志,但要注意它需要运行时sysadmin权限,除非与计划指南一起使用.

不幸

以上都不适用于IF EXISTS条件语句.它仅适用于常规DML.它将与您尝试的备用SELECT TOP(1)配方一起使用.这可能比使用COUNT(*)更好,后者必须计算所有限定行,如前所述.

也就是说,有许多方法可以表达此要求,这将允许您避免或控制行目标,同时尽早终止搜索.最后一个例子:

DECLARE @Exists bit;

SELECT @Exists =
    CASE
        WHEN EXISTS
        (
            SELECT [dlc].[ID]
            FROM TableDLC [dlc]
            JOIN TableD [d]
            ON [d].[ID] = [dlc].[ID]
            JOIN TableC [c]
            ON [c].[ID] = [d].[ID2]
            WHERE [c].[Name] <> [dlc].[Name]
        )
        THEN CONVERT(bit,1)
        ELSE CONVERT(bit,0)
    END
OPTION (QUERYTRACEON 4138);

IF @Exists = 1
BEGIN
    ...
END;

猜你在找的MsSQL相关文章