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

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

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

这是顶级查询:

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

当我添加这个 where 子句时:

Where i.InvoiceID = 109581

查询大约需要 3 秒才能运行。同样,当我添加此 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 秒才能返回。不过,客户的数据比我多得多。

知道从哪里开始解决这个问题吗?

编辑:

在下面的评论之后,我重建了索引和统计信息,这提高了前两个 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)

运行:65 分钟返回 31 行

最佳答案

您遇到的问题(几乎可以肯定)是由于缓存的查询计划造成的,该计划适用于传递给查询的某些版本的参数,但不适用于其他版本(又名 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)

关于SQL Server 查询超时取决于 Where 子句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12362221/

相关文章:

SQL 服务器 : split a column with varied data into 3 specific columns grouped by ID

sql-server - SSIS Foreach 循环 - Excel 工作表 - 'xlnm#_FilterDatabase'(幻影/幽灵工作表)

sql - Microsoft SQL Server Native Client 10.0 登录超时已过期

SQL Server 2008 R2 Express - 实例不断启动数据库

MySQL 忽略异常值

sql - 批量插入期间会出现其他字符

java - hibernate 中有没有一种方法可以在一个字符串中操作多个查询

sql-server - 如何在 SQL Server 触发器中复制插入、更新、删除的行

sql-server - SQL Server 和事务中间的连接丢失

sql-server - 您如何知道自上次使用以来 SQL 表是否已更改?