繁体   English   中英

如何防止SQL服务器多次运行同一个子查询

[英]How to prevent SQL Server from running the same subquery multiple times

我有一个遵循以下结构的查询:

SELECT * 
FROM 
    ... <generated code> ...
    (SELECT <fields>,  
        CASE(SELECT TOP 1 ID FROM [Configuration] WHERE IsDefault=1 ORDER BY ID)
            WHEN 1 THEN t.FirstName
            WHEN 2 THEN t.LastName END As Identifier
     FROM <table> t) AS tmp
... <generated code> ...
WHERE <generated filters>

在查询执行计划中,我看到Configuration表上的Clustered Index Scan的执行次数与<table>中的数字相同,但是,我知道这些扫描的结果总是相同的,当我更换

SELECT TOP 1 ID 
FROM [Configuration] 
WHERE IsDefault = 1 
ORDER BY ID

部分对于配置的当前值,此查询运行速度很快。

我正在寻找一种方法来告诉 SQL 服务器这个子查询总是有相同的结果以便它运行得很快,我看到的最明显的方法是用该查询的值声明一个临时变量并在主查询中使用该变量,问题是查询的开始和结束是由应用程序代码生成的,我无法手动控制它。

对我来说,理想的解决方案是创建一个运行该查询的确定性 function,并让 SQL 服务器知道,由于 function 是确定性的,并且它不依赖于当前行,它只需要运行一次,但对于出于某种原因,它只是没有用,它仍然运行了很多次。

go 我应该怎么优化这个? 我误解了确定性函数吗? 我刚才是不是把 function 弄错了? 还有别的办法吗?

如评论中所述,使用CROSS JOIN有效,最终查询为:

SELECT * 
FROM 
     ... <generated code> ...
    (SELECT <fields>,  
        CASE config.ID
            WHEN 1 THEN t.FirstName
            WHEN 2 THEN t.LastName END As Identifier
     FROM <table> t
     CROSS JOIN (SELECT TOP 1 ID FROM [Configuration] WHERE IsDefault=1 ORDER BY ID) config) AS tmp
... <generated code> ...
WHERE <generated filters>

正如问题中提到的,使用临时变量会修复执行计划,但对我来说不是一个选项,因为查询的顶部是由来自不同组件的代码生成的

DECLARE @config INT
SET @config = (SELECT TOP 1 ID FROM [Configuration] WHERE IsDefault=1 ORDER BY ID)
SELECT * 
FROM 
     ... <generated code> ...
    (SELECT <fields>,  
        CASE @config
            WHEN 1 THEN t.FirstName
            WHEN 2 THEN t.LastName END As Identifier
     FROM <table> t) AS tmp
... <generated code> ...
WHERE <generated filters>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM