首页 > 解决方案 > 为什么我的参数化查询不能正确使用索引?

问题描述

这是在 SQL Server 2014 中,但我在 2008、2012 和 2016 以及 Sybase ASE 15.7 中看到了相同的行为。

我有一个简单的查询,如下所示:

SELECT myField
FROM myTable
WHERE someIndexedField = @myParam

如果我从 SSMS 运行此查询(将 @myParam 替换为 'myValue'),查询会在一秒钟内运行,因为 someIndexedField 已编入索引,并且查找速度应该非常快。但是,如果我在 C# 程序中创建与参数化查询字符串相同的查询,则查询需要 20 到 30 秒。DBA 的分析表明查询计划没有使用 someIndexedField 列上的索引,而是执行表扫描。

更奇怪的是,如果我执行完全相同的参数化查询,而是将其稍微更改为:

DECLARE @_myParam char(13)
SET @_myParam = @myParam

SELECT myField
FROM myTable
WHERE someIndexedField = @_myParam

...这个版本突然再次使用索引,性能恢复到亚秒级响应时间。我在各种复杂的查询中看到了同样的行为,但对于不同的查询并不是 100% 一致——有时服务器确实决定使用索引。但是,对于任何给定的查询,它都是一致的。在尝试之前,我永远不知道哪些查询会受到影响,但如果给定的查询有这个问题,它总是有问题。此外,没有问题的查询似乎永远不会在以后开发它。

我注意到的另一件奇怪的事情是,有时,更改查询的总长度实际上会改变这种行为的显示方式。我有一个例子,在查询中添加额外的回车符(基本上是双倍行距)实际上导致服务器突然开始按预期使用索引。从字面上看,没有代码被改变。但是,我无法确定发生这种情况的确切长度。此外,这个特殊的“解决方案”似乎只适用于 Sybase ASE——我无法在 SQL Server 上重现该解决方案。

(顺便提一下,我也可以通过hint来推送服务器使用合适的索引,这样也解决了问题。不过,索引提示如果能避免的话一般不是个好主意,看来服务器应该是完全能够自行选择索引,尤其是对于这样一个简单的查询。)

这里发生了什么?为什么第一个版本运行起来好像表上没有索引?为什么简单地将参数放入本地定义的变量中会突然导致使用索引?

标签: sqlsql-serversap-asesql-execution-plan

解决方案


推荐阅读