我遇到了Sql Server 2008 R2的性能问题,我已经缩小到查询优化器(我认为!)。我正在寻找一个明确的“为什么发生这种情况,还是它是一个错误?”。查询优化不使用索引
为了讨论的缘故,我将使用这个例子,但是在同一个场景中多个sprocs中也出现了相同的问题。 我们有一张包含付款方式的表格;关键字段是PaymentMethodId和UserId。 PaymentMethodId是一个int,而PK; UserId是一个具有非聚集索引的nvarchar(255)。
查询类似于以下内容:
存储过程PARAMS值得一提: @id INT = NULL @userId为nvarchar(255)= NULL 有一个if语句在存储过程的开始禁止两个参数都是空的。
select * from PaymentMethods (nolock) pm
where (@userId is null or @userId = pm.UserId)
and (@id is null or @id = pm.PaymentMethodId)
在@userId为空的情况下,我希望优化器检测到第一个where子句始终为true;如果@userId不为空,我期望它使用UserId上的索引。 我对@id有同样的期望。
我们看到的是,无论输入值为何,数据库都会选择执行全表扫描。虽然这涉及到其自身,但它变得更有趣。
将查询where子句更新为下面的等效项时,它正确使用indecies。
select * from PaymentMethods (nolock) pm
where ((@userId is null and pm.UserId is null) OR @userId = pm.UserId)
and (@id is null or @id = pm.PaymentMethodId)
这是怎么回事?为什么每个记录都会考虑“@userId为null”,或者是真正的问题坐在他们的键盘前面?
可能是因为(a)你的表很小(行数很少),或者(b)因为你使用'SELECT *',索引无法“覆盖”该查询,所以很多密钥查找将是必要的,并且最终这将比仅执行全表扫描更昂贵。 –
表中有1130万条记录,并且实际查询通过名称而不是*调用字段。 – Jon
请发布查询计划的快照。你有表格定义和样本数据吗?几条记录。 –