当前位置: 首页 > 面试题库 >

分配给变量时的sql执行延迟

计寒
2023-03-14
问题内容

以下查询将在约22秒内运行:

DECLARE @i INT, @x INT
SET    @i = 156567

SELECT 
TOP 1
    @x = AncestorId
FROM 
    dbo.tvw_AllProjectStructureParents_ChildView a
WHERE 
    ProjectStructureId = @i AND
        a.NodeTypeCode = 42 AND
        a.AncestorTypeDiffLevel = 1
OPTION (RECOMPILE)

问题出在 变量赋值上 (实际上是这一行:)@x = AncestorId。删除作业时,它最多可以加快15毫秒!我通过将结果插入到临时表中解决了这个问题,但我认为这是一种不好的方法。

任何人都可以帮助我解决问题的根源吗?

聚苯乙烯

错误的执行计划(22 s
):https :
//www.brentozar.com/pastetheplan/?id=Sy6a4c9bW

良好的执行计划(20 毫秒
):https :
//www.brentozar.com/pastetheplan/?id=Byg8Hc5ZZ


问题答案:

使用OPTION (RECOMPILE)SQL
Server时,通常可以执行参数嵌入优化。

它正在编译的计划是一次性的,因此它可以嗅探所有变量和参数的值并将其视为常量。

下面是一个简单的示例,该示例显示了实际的参数嵌入优化以及分配给变量的效果(未估算实际执行计划)。

DECLARE @A INT = 1, 
        @B INT = 2,
        @C INT;

SELECT TOP (1) number FROM master..spt_values WHERE @A > @B;
SELECT TOP (1) number FROM master..spt_values WHERE @A > @B OPTION (RECOMPILE);
SELECT TOP (1) @C = number FROM master..spt_values WHERE @A > @B OPTION (RECOMPILE);

计划如下

在此处输入图片说明

请注意,中间的一个甚至根本不涉及该表,因为SQL Server可以在编译时推导出该表,而事实@A > @B并非如此true。但是计划3回到表中,因为变量分配显然阻止了OPTION (RECOMPILE)计划2所示的效果。

(顺便说一句,第三个计划实际上并不比第一个计划贵4-5倍。分配给变量似乎也抑制了通常的行目标逻辑,在该逻辑中,索引扫描的成本将按比例缩小以反映TOP 1

在您的好计划中,将的@i值直接156567推入递归CTE锚点中的seek中,它返回了0行,因此递归部分无需执行任何操作。

在此处输入图片说明

在您的错误计划中,递归CTE会完全实现627,393次递归子树的执行,最后将谓词应用于最后的627,393行(丢弃所有行)

在此处输入图片说明

我不确定为什么SQL Server无法将带有变量的谓词下推。您尚未提供表的定义-
或带有递归CTE的视图。但是,谓词推送,视图和窗口函数也存在类似的问题。

一种解决方案是将视图更改为内联表值函数,该函数接受mainid参数,然后将其添加到WHERE定义的锚定部分的子句中。而不是依靠SQL
Server为您降低谓词。



 类似资料:
  • 我是helm的新手,我希望能够使用配置映射和共享环境变量将gitlab项目变量写入文件。 我为每个环境(其中

  • 问题内容: 假设我有一个功能 现在,我想将函数分配给一个名为的变量,这样,如果我使用,它将再次调用该函数。如果我只是做作业,它就会返回。 问题答案: 您根本不调用该函数。 括号告诉蟒蛇,你调用的函数,所以当你把它们放在那里,它调用的功能,并指定值 返回 的(在这种情况下)。

  • 目前,我遇到了一个与将Golang变量分配给Javascript变量相关的问题。我正在使用Golang模板,因此,我从后端发送了一个JSON变量,就像这样: 如您所见,我有一个切片,将其转换为Json,然后将Json转换为string,并将其发送到模板。然后,在前端我需要把它赋给一个变量,它应该是有效的JSON,我有这个: 但是,我得到的是语法错误:预期的属性名,得到的是“{” 所以,我的问题是:

  • 问题内容: 在上面,这是硬代码。我想将 变量 分配 给值。即,均值=注册; 让我知道! 问题答案: 您的问题不是很清楚。我假设变量是在Servlet中声明的,因为在JSP中使用Java是一种不好的做法。为了能够在转发到JSP的Servlet之间共享变量,您需要将此变量设置为request属性: 然后在JSP中,您可以使用JSP EL获得“ registration”属性的值: 您应该阅读Java

  • 问题内容: 我正在使用以下代码: 该值不警报。怎么了 问题答案: 实质上:

  • 您好,我正在开发一个swing聊天应用程序,其中聊天历史记录存储在一个xml文件中。在NetBeans项目中完成后,我能够获取xml文件并将其显示在表中 但是当转换成jar文件时,我无法使用xml文件。我尝试过各种方法,比如getClass()。getResource()方法,但它检索URL而不是字符串,如果使用toString()方法将其转换为字符串,则无法将其用作解析xml文件的有效路径。 下