我在周末从sql server 2000升级到2008。现在,一个查询运行速度非常慢(大约50行,大约30秒)。
查询是:
SELECT TOP 200 AccData.SurName + ', ' + AccData.FirstNames AS Name,
DATEDIFF(day, COALESCE (AccData.DateReceived, AccData.DateOpened,
AccData.InjuryDate),
GETDATE()) AS Duration, AccData.M46No, Clients.ClientName,
AccData.HomePhone, AccData.WorkPhone, AccData.InjuryDate,
AccData.ClaimID,
luClaimStatus.Meaning AS Status, AccData.Claim,
vw_LastMedCert.Fitness, vw_LastMedCert.UntilDate
FROM AccData INNER JOIN
Clients ON AccData.ClientID = Clients.ID
INNER JOIN
luClaimStatus ON AccData.ClaimStatus = luClaimStatus.ClaimStatus
LEFT OUTER JOIN
vw_LastMedCert ON AccData.Claim = vw_LastMedCert.Claim
WHERE AccData.ClientID>1 and CaseManagerId = :CaseManagerID
and (DateClosed is null or AccData.ClaimStatus ='R')
order by Surname, FirstNames
问题与LastMedCert
有关ALTER VIEW [dbo].[vw_LastMedCert] WITH SCHEMABINDING
AS
SELECT Claim, ClaimId, ReferralID, FromDate, UntilDate, Fitness, DateSeen,
DateEntered, PeriodFor
FROM dbo.Med_cert
WHERE (ReferralID IN
(SELECT MAX(ReferralID) AS MaxOfReferralID
FROM dbo.Med_cert AS Med_cert_1
WHERE (Fitness IS NOT NULL)
GROUP BY Claim))
有什么想法吗?我重建了索引并更新了统计信息
执行计划是:
|--Compute Scalar(DEFINE:([Expr1020]=datediff(day,[Expr1024],getdate())))
|--Nested Loops(Left Outer Join, OUTER REFERENCES:([CmsDB].[dbo].[AccData].[Claim]))
|--Nested Loops(Inner Join, OUTER REFERENCES:([CmsDB].[dbo].[AccData].[ClientID]))
| |--Nested Loops(Inner Join, OUTER REFERENCES:([CmsDB].[dbo].[AccData].[ClaimStatus]))
| | |--Compute Scalar(DEFINE:([Expr1019]=((([CmsDB].[dbo].[AccData].[SurName]+', ')+[CmsDB].[dbo].[AccData].[FirstNames])+' ')+CASE WHEN [CmsDB].[dbo].[AccData].[MiddleNames] IS NOT NULL THEN [CmsDB].[dbo].[AccData].[MiddleNames] ELSE '' END, [Expr1024]=CASE WHEN [CmsDB].[dbo].[AccData].[DateReceived] IS NOT NULL THEN [CmsDB].[dbo].[AccData].[DateReceived] ELSE CASE WHEN [CmsDB].[dbo].[AccData].[DateOpened] IS NOT NULL THEN [CmsDB].[dbo].[AccData].[DateOpened] ELSE [CmsDB].[dbo].[AccData].[InjuryDate] END END))
| | | |--Nested Loops(Inner Join, OUTER REFERENCES:([Uniq1002], [CmsDB].[dbo].[AccData].[Claim], [CmsDB].[dbo].[AccData].[SurName], [CmsDB].[dbo].[AccData].[FirstNames], [Expr1027]) WITH ORDERED PREFETCH)
| | | |--Index Seek(OBJECT:([CmsDB].[dbo].[AccData].[IX_AccData_ByCaseManagerId]), SEEK:([CmsDB].[dbo].[AccData].[CaseManagerID]=(100346)) ORDERED FORWARD)
| | | |--Clustered Index Seek(OBJECT:([CmsDB].[dbo].[AccData].[byName]), SEEK:([CmsDB].[dbo].[AccData].[SurName]=[CmsDB].[dbo].[AccData].[SurName] AND [CmsDB].[dbo].[AccData].[FirstNames]=[CmsDB].[dbo].[AccData].[FirstNames] AND [CmsDB].[dbo].[AccData].[Claim]=[CmsDB].[dbo].[AccData].[Claim] AND [Uniq1002]=[Uniq1002]), WHERE:([CmsDB].[dbo].[AccData].[ClientID]>(1) AND ([CmsDB].[dbo].[AccData].[DateClosed] IS NULL OR [CmsDB].[dbo].[AccData].[ClaimStatus]='R')) LOOKUP ORDERED FORWARD)
| | |--Clustered Index Seek(OBJECT:([CmsDB].[dbo].[luClaimStatus].[PK_luClaimStatus_1__172]), SEEK:([CmsDB].[dbo].[luClaimStatus].[ClaimStatus]=[CmsDB].[dbo].[AccData].[ClaimStatus]) ORDERED FORWARD)
| |--Index Seek(OBJECT:([CmsDB].[dbo].[Clients].[PK_Clients_2__13]), SEEK:([CmsDB].[dbo].[Clients].[ID]=[CmsDB].[dbo].[AccData].[ClientID]), WHERE:([CmsDB].[dbo].[Clients].[ID]>(1)) ORDERED FORWARD)
|--Nested Loops(Inner Join, WHERE:([Expr1018]=[CmsDB].[dbo].[Med_cert].[ReferralID]))
|--Clustered Index Seek(OBJECT:([CmsDB].[dbo].[Med_cert].[byClaim]), SEEK:([CmsDB].[dbo].[Med_cert].[Claim]=[CmsDB].[dbo].[AccData].[Claim]) ORDERED FORWARD)
|--Table Spool
|--Stream Aggregate(GROUP BY:([CmsDB].[dbo].[Med_cert].[Claim]) DEFINE:([Expr1018]=MAX([CmsDB].[dbo].[Med_cert].[ReferralID])))
|--Clustered Index Scan(OBJECT:([CmsDB].[dbo].[Med_cert].[byClaim]), WHERE:([CmsDB].[dbo].[Med_cert].[Fitness] IS NOT NULL) ORDERED FORWARD)
我通过重写初始查询解决了这个问题。它现在运行大约1秒钟,但我仍然想知道出了什么问题,所以如果它再次出现我可以解决它。
摘要 初始查询运行时间约为2分钟,具体取决于参数。按照exeqution计划和dm_db_missing_index_details的建议添加索引可将运行时间减少到大约4秒。 添加哈希提示可将运行时间缩短至2秒。
这是一个艰难的决定,决定接受哪个答案,大多数答案提供了一些帮助。
答案 0 :(得分:2)
比较两台机器上的actual execution plan
。图形版本可能是最有用的;您可以比较树木,并检查2008服务器上哪个箭头非常大。
要在Stack Overflow上发布,请以文本形式检索计划,如:
set showplan_text on
go
<your query>
编辑:执行计划提到了聚集索引扫描:
|--Clustered Index Scan(OBJECT:([CmsDB].[dbo].[Med_cert].[byClaim]),
WHERE:([CmsDB].[dbo].[Med_cert].[Fitness] IS NOT NULL) ORDERED FORWARD)
我会在med_cert(fitness,claim,ReferralID)
上使用索引来尝试此操作。更好的是,您可以在SQL事件探查器中运行它并遵循它生成的索引建议。另请查看SSMS中的messages
标签;它有时包括索引建议。
答案 1 :(得分:1)
查询只是第一次或每次都慢吗?如果是前者,那可能是一个缓存问题。
新系统是否使用与旧系统相同的磁盘子系统?如果没有,问题可能与您用于数据文件的磁盘速度有关。
您是否将数据库从兼容模式90升级到100,或者您将其保持在90?
您是否也从旧系统中提取了所有数据?如果不是,可能统计数据不同,导致查询计划不同(且速度较慢)。
您是否尝试过使用SQL 2008中缺少的索引功能?
SELECT * FROM sys.dm_db_missing_index_details
答案 2 :(得分:0)
没有什么特别突出的问题。虽然我注意到一些小问题,但我会提到。
同一查询的查询计划是什么?我在计划中看到对AccData.MiddleNames的引用,但在查询中没有。
我确实有一些观察......
该计划表明您在AccData上的聚集索引是SurName,FirstName,Claim。这不理想;你更喜欢PK或者为你的聚集索引很好地组合的数据。如果您不使用PK,则必须执行如下图所示的“书签查找”,以通过聚集索引获取完整记录。如果优化器看到/预测这种情况发生得太多,它可能更喜欢进行表扫描并可能对数据进行排序。
| | | |--Nested Loops(Inner Join, OUTER REFERENCES:([Uniq1002], [CmsDB].[dbo].[AccData].[Claim], [CmsDB].[dbo].[AccData].[SurName], [CmsDB].[dbo].[AccData].[FirstNames], [Expr1027]) WITH ORDERED PREFETCH)
| | | |--Index Seek(OBJECT:([CmsDB].[dbo].[AccData].[IX_AccData_ByCaseManagerId]), SEEK:([CmsDB].[dbo].[AccData].[CaseManagerID]=(100346)) ORDERED FORWARD)
| | | |--Clustered Index Seek(OBJECT:([CmsDB].[dbo].[AccData].[byName]), SEEK:([CmsDB].[dbo].[AccData].[SurName]=[CmsDB].[dbo].[AccData].[SurName] AND [CmsDB].[dbo].[AccData].[FirstNames]=[CmsDB].[dbo].[AccData].[FirstNames] AND [CmsDB].[dbo].[AccData].[Claim]=[CmsDB].[dbo].[AccData].[Claim] AND [Uniq1002]=[Uniq1002]), WHERE:([CmsDB].[dbo].[AccData].[ClientID]>(1) AND ([CmsDB].[dbo].[AccData].[DateClosed] IS NULL OR [CmsDB].[dbo].[AccData].[ClaimStatus]='R')) LOOKUP ORDERED FORWARD)
我在您的查询中注明了WHERE ClientID>1
;这似乎很奇怪,也许是多余的。通过强迫它考虑实际上是多余的东西,它更有可能使查询优化器的工作变得复杂。
查询计划使用“嵌套循环”显示所有连接。如果每次连接的数据量不是太多,这通常没问题。 (您可以在图形计划中查看)。基本上,该计划似乎在所有连接上都达到了适当的索引。确保没有确切地看到这些索引是什么,并且没有看到涉及的数据量,这很棘手。
作为提示,下次遇到此问题时,请查看图形查询计划,并查看哪些节点非常昂贵。它将指导您检查索引的位置(用于创建或重建)。
答案 3 :(得分:0)
我有一个非常类似的问题从2000年到2005年。我们查看了100万行的表(有自联接等),查询运行了三个多小时(我们永远不会让它完成,所以我们不知道它是否会回归)。我的问题似乎与表中“嵌套循环”的数量直接相关。我在你的执行计划中看到了不少:
Nested Loops(Left Outer Join, OUTER REFERENCES:([CmsDB].[dbo].[AccData].[Claim]))
|--Nested Loops(Inner Join, OUTER REFERENCES:([CmsDB].[dbo].[AccData].[ClientID]))
| |--Nested Loops(Inner Join, OUTER REFERENCES:([CmsDB].[dbo].[AccData].[ClaimStatus]))
我在所有有问题的联接上使用了Query Hint:Hash,并且将查询的时间缩短到了30-45分钟。
我也很想找到根本原因,但这是一个基本的工作。