从应用程序执行参数化查询时执行计划发生变化

Execution plan changes while executing parameterized query from application

我们正在开发 SQL Server 2008。Java Web 应用程序用作前端。

从应用程序触发的每个查询都作为存储过程执行,如查询 #1 所示。

我们在执行简单的 SELECTUPDATE 查询时观察到来自应用程序执行计划的不同。

查询 #1 执行需要 3 秒:

declare @p1 int
exec sp_prepexec @p1 output, N'@P4 nvarchar(4000)',
                 N' SELECT KEY FROM dbo.DETAIL   
                    WHERE KEY = @P4',N'SIND-60068635-R-202'
select @p1

查询 #2 的执行时间不到 1 秒:

SELECT KEY 
FROM DETAIL 
WHERE KEY = 'SIND-60068635-R-202'    

我们观察到两个查询的执行计划不同。对于第二个查询,正在应用在 KEY 上创建的索引,因此查询响应良好,但同一索引未用于查询 #1,因此查询响应时间很差。

如有任何解决此问题的建议,我们将不胜感激。

是的,有一个问题,当我们切换到使用存储过程中的参数时,SQL服务器无法有效地使用过滤索引。要解决此问题,一种方法是使用

之类的索引提示
SELECT * FROM <Table> WITH (INDEX(<indexName>))

但为此我们必须继续使用相同的索引名称

其他方法是使用字符串连接,即通过强制 SQL 服务器查看文字值(参数)

例如

 DECLARE @sql AS NVARCHAR(MAX) = N'';
 DECLARE @p1 AS VARCHAR(10)='test'
 SET @sql += 'SELECT KEY FROM dbo.DETAIL WHERE KEY = ' + CAST(@p1 AS NVARCHAR(10));
 EXEC sp_executesql @sql;

访问这个url - https://www.brentozar.com/archive/2013/11/filtered-indexes-and-dynamic-sql/

通过将 nvarchar 更改为 varchar 有助于获得性能优势(索引扫描到索引查找)。此外,JDBC 在将参数作为 nvarchar 而不是 varchar 传递时会产生此问题。我们参考了以下博客

https://blogs.msdn.microsoft.com/sqlcat/2010/04/05/character-data-type-conversion-when-using-sql-server-jdbc-drivers/