Sql server 如何在mssqlserver中实现查询计划重用

Sql server 如何在mssqlserver中实现查询计划重用,sql-server,sql-execution-plan,sp-executesql,Sql Server,Sql Execution Plan,Sp Executesql,我继承了一个数据库应用程序,它有一个包含大约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##', @T

我继承了一个数据库应用程序,它有一个包含大约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;
exec sp_executesql @sql, N'@TheId int', @TheId;
我想得到计划重用,所以我用
@TheId
替换
@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;
exec sp_executesql @sql, N'@TheId int', @TheId;
然而,我仍然看到相同的行为,其中每个计划都是唯一的计划,即使
@sql
字符串已经编译并在过程缓存中

现在绳子是这样的

...where where st.TheID = @TheId

问题:如何在参数化查询中获得所需的计划重用

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

尝试以下几点:

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;

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

尝试以下几点:

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;

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

@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;

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

@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;

这不是一个参数化查询。通过建立一个字符串,您已经完全击败了这里的参数。您应该将参数传递给动态sql,或者最好避免使用动态sql。从您发布的内容来看,这里根本不需要动态sql。不要使用动态sql。这不是一个参数化查询,它只是一个普通的旧字符串,容易受到SQL注入的攻击,就像任何其他SQL字符串一样。这是一个很好的方法,因为它(更重要的是)解决了SQL注入问题。我正在尝试修复过程缓存膨胀。有450条不同的规则,但每天对不同的记录执行数千次。我昨晚查看了制作,看到了50000多个不同的计划。我想把这个减少到450左右。然后我可以调整表现不佳的人,看看哪一个是最昂贵的,等等。我不能用50000个查询做到这一点。对于每个不同的计划,sql文本是否完全相同?这不是一个参数化查询。通过建立一个字符串,您已经完全击败了这里的参数。您应该将参数传递给动态sql,或者最好避免使用动态sql。从您发布的内容来看,这里根本不需要动态sql。不要使用动态sql。这不是一个参数化查询,它只是一个普通的旧字符串,容易受到SQL注入的攻击,就像任何其他SQL字符串一样。这是一个很好的方法,因为它(更重要的是)解决了SQL注入问题。我正在尝试修复过程缓存膨胀。有450条不同的规则,但每天对不同的记录执行数千次。我昨晚查看了制作,看到了50000多个不同的计划。我想把这个减少到450左右。然后我可以调整表现不佳的人,看看哪一个是最昂贵的,等等。我不能用50000个查询来做到这一点。对于这些不同的计划,sql文本是否完全相同?不需要使用存储过程。一个简单的参数化查询就足够了谢谢,我想。。。但创建450多个程序比我想解决的要困难得多。我很想重写它,但是没有兴趣修复真正没有损坏的东西,也没有必要使用存储过程。一个简单的参数化查询就足够了谢谢,我想。。。但创建450多个程序比我想解决的要困难得多。我很想重写这篇文章,但是没有兴趣去修复真正没有被破坏的东西。哎呀,就是这样。我想问题可能就在那张临时桌上。您可能希望通过捕获xeforsql_语句_recompile来查看在运行该查询时是否获得了新的重新编译。我相信插入正在导致重新编译。谢谢!!!我应该知道是临时桌子把我搞砸了!解决方案是从查询中删除“insert-into#temp”。然后我将执行修改为:
insert 35; temp exec sp_executesql@sql,N'@id int',@id'
Yikes,就是这样。我想问题可能就在那张临时桌上。您可能希望通过捕获xeforsql_语句_recompile来查看在运行该查询时是否获得了新的重新编译。我相信插入正在导致重新编译。谢谢!!!我应该知道是临时桌子把我搞砸了!解决方案是从查询中删除“insert-into#temp”。然后我将执行修改为:
insert\temp exec sp\u executesql@sql,N'@id int',@id'