如何在 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 查询强制执行查询超时?