SQL Server查询超时取决于Where子句

时间:2012-09-11 03:11:30

标签: sql sql-server sql-server-2008r2-express

我有一个查询,它使用了3个函数和一些不同的视图,这些视图太复杂了,无法在此处发布。我遇到的奇怪的事情是,当运行顶级查询时,有超过1个搜索键导致查询需要大约一个小时才能运行,其中将查询分成两部分,每个查询大约需要5秒。

以下是顶级查询:

Select * 
from  dbo.vwSimpleInvoice i 
inner join dbo.vwRPTInvoiceLineItemDetail d on i.InvoiceID = d.InvoiceID 

当我添加where where子句时:

Where i.InvoiceID = 109581

查询大约需要3秒钟才能运行。同样,当我添加where where子句时:

Where i.InvoiceID = 109582

大约需要3秒钟。

当我添加这个where子句时:

Where i.InvoiceID in (109581, 109582)

我必须在大约50分钟后终止查询,并且它永远不会返回任何结果。

这是在运行SQL Server 2008 R2 Express的远程客户端服务器上发生的。当我在本地运行它时(也在SQL Server 2008 R2 Express上),我没有得到大量延迟,最后一个where子句需要大约30秒才能返回。客户端的数据比我多得多。

知道从哪里开始排除故障?

编辑:

在下面的评论之后,我重建了索引和统计数据,这改善了前2个where子句的性能,但对第三个没有影响。然后我讨论了查询,并发现如果我把它重写为:

Select * 
from  dbo.vwSimpleInvoice i 
inner join  
    (Select * from dbo.vwRPTInvoiceLineItemDetail) d on i.InvoiceID = d.InvoiceID 
Where i.InvoiceID in (109581, 109582)

性能恢复到预期水平,大约200毫秒。对于正在发生的事情,我现在比以往更加神秘......

编辑2:

实际上,我错了。它没有像那样重写查询,我在重写期间意外地将Where子句改为:

Where d.InvoiceID in (109581, 109582)

(将i更改为d)。

仍然有点不知道为什么这会导致内部加入的巨大差异?


进一步编辑:

更进一步,我仍然无法理解。

Select InvoiceId from tblInvoice Where CustomerID = 2000

返回:

80442, 4988, 98497, 102483, 102484, 107958, 127063, 168444, 168531, 173382, 173487, 173633, 174013, 174160, 174240, 175389

Select * from dbo.vwRPTInvoiceLineItemDetail
Where InvoiceID in 
(80442, 4988, 98497, 102483, 102484, 107958, 127063, 168444, 168531, 173382, 173487, 173633, 174013, 174160, 174240, 175389)

运行:31行返回110毫秒

Select * from dbo.vwRPTInvoiceLineItemDetail
Where InvoiceID in 
(Select InvoiceId from tblInvoice Where CustomerID = 2000)

运行:31行返回65分钟

1 个答案:

答案 0 :(得分:3)

您遇到的问题(几乎可以肯定)是由于缓存的查询计划,该计划适用于传递给查询的某些版本的参数,但不适用于其他版本(也称为Parameter Sniffing)。

这是一种常见现象,并且通常会因过时的统计数据和/或严重分散的索引而变得更糟。

第一步:确保您已重建所有索引,并且非索引列的统计信息是最新的。 (另外,确保您的客户有定期安排的索引维护工作)

exec sp_msforeachtable "DBCC DBREINDEX('?')"
go

exec sp_msforeachtable "UPDATE STATISTICS ? WITH FULLSCAN, COLUMNS"
go

这是规范参考:Slow in the Application, Fast in SSMS?

如果在重建索引和更新统计信息后问题仍然存在,那么您有几个选项:

  1. 使用动态SQL(但首先阅读:The Curse and Blessings of Dynamic SQL

  2. 使用OPTIMIZE FOR

  3. 使用WITH(RECOMPILE)