如何在 MS SQL Server 中获得查询计划重用

Posted

技术标签:

【中文标题】如何在 MS SQL Server 中获得查询计划重用【英文标题】:How to get Query Plan Reuse in MS SQL Server 【发布时间】:2017-07-19 14:54:03 【问题描述】:

我继承了一个数据库应用程序,该应用程序有一个包含大约 450 个查询的表。有一个调用程序将@QueryId@TheId 作为输入参数。执行这些查询的唯一方法是通过此过程。查询是这样的:

@sql = replace('insert into #temp select col1, col2, col3, col4
from SomeTable st join OtherTable ot on matching_column
where st.TheID = ##TheId##', '##TheId##', @TheId);

exec sp_executesql @sql;

我想获得计划重用,所以我将##TheId## 替换为@TheId,然后执行如下查询:

exec sp_executesql @sql, N'@TheId int', @TheId;

但是,即使@sql 字符串已经编译并在过程缓存中,我仍然看到每个计划都是唯一计划的相同行为。

现在字符串是这样的

...where where st.TheID = @TheId

问题:如何在参数化查询中根据需要获得计划重用?

【问题讨论】:

这不是参数化查询。通过建立一个字符串,您已经完全击败了这里的参数。您应该将参数传递给动态 sql,或者更好地避免使用动态 sql。从您发布的内容来看,这里根本不需要动态 sql。 不要使用动态 SQL。这不是参数化查询,它只是一个普通的字符串,像任何其他 SQL 字符串一样容易受到 SQL 注入的影响 这是一个很好的方法,因为它(更重要的是)解决了 SQL 注入问题。 我正在尝试修复过程缓存膨胀。有 450 条不同的规则,但它们每天要针对各种记录执行数千次。我昨晚看了看制作,看到了 50,000 多个不同的计划。我想将其减少到〜450。然后我可以调整表现不佳的人,看看哪些最昂贵,等等。我不能用 50,000 个查询来做到这一点 每个不同计划的 sql 文本是否完全相同? 【参考方案1】:

如果您将其修改为以下内容,您应该可以重用计划,因为这将使其成为参数化查询:

@sql = replace('insert into #temp select col1, col2, col3, col4
from SomeTable st join OtherTable ot on matching_column
where st.TheID = ##TheId##', '##TheId##', '@TheId');

exec sp_executesql @sql, N'@TheID INT', @TheID;

https://technet.microsoft.com/en-us/library/ms175580(v=sql.105).aspx

【讨论】:

哎呀,原来如此。我想问题可能出在#temp 表周围。您可能希望通过捕获 sql_statement_recompile 的 XE 来查看运行该查询时是否获得了新的重新编译。我相信插入会导致重新编译。 谢谢!!!我应该知道是#temp 表把我搞砸了!解决方案是从查询中删除“插入#temp”。然后我将执行改写为:insert #temp exec sp_executesql @sql, N'@id int', @id'【参考方案2】:

您是否尝试在不使用动态查询的情况下创建存储过程?

尝试以下方法:

CREATE PROCEDURE insertdata 
(
    @TheId INT -- or whatever data type is being used
)   
AS
BEGIN 
    INSERT INTO #temp 
    SELECT 
        col1
        , col2
        , col3
        , col4
    FROM SomeTable st 
    JOIN OtherTable ot ON matching_column
    WHERE st.TheID = @Theid;
END

当你想执行它时,你只需这样做:

EXEC insertdata 123;

【讨论】:

不需要使用存储过程。一个简单的参数化查询就足够了 谢谢,我虽然是这么想的...但是创建 450 多个程序比我想解决的道路更艰难。我很想重写这个,但是没有兴趣修复真正没有被破坏的东西。

以上是关于如何在 MS SQL Server 中获得查询计划重用的主要内容,如果未能解决你的问题,请参考以下文章

如何使 MS Access 直通查询在 SQL Server 中正确运行

如何将 MS-SQL Server SELECT 查询转换/迁移到 Oracle 和 MySQL?

如何对通过 MS JDBC 驱动程序运行的 MS SQL Server 查询强制执行查询超时?

如何查看sqlserver执行计划来判断SQL语句效率

MS SQL Server 中的链接 Informix 表忽略标准?

SQL Server - 条件语句的查询执行计划