2009-12-06 4 views
1

주말에 SQL Server 2000에서 2008로 업그레이드되었습니다. 이제 하나의 쿼리가 실제로 느리게 실행됩니다 (약 50 개 행에 대해 30 초 이상).Sql Server 2008로 업그레이드되었습니다. 이제는 하나의 쿼리가 실제로 느리게 실행 중입니다.

쿼리는 다음과 같습니다

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

쿼리 계획은 어떻게 생겼습니까? –

답변

1

쿼리가 처음으로 느려 집니까? 전자의 경우 캐싱 문제 일 수 있습니다.

새 시스템이 기존 시스템과 동일한 디스크 하위 시스템을 사용하고 있습니까? 그렇지 않은 경우 문제는 데이터 파일에 사용중인 디스크의 속도와 관련이있을 수 있습니다.

DB를 호환성 모드 90에서 100으로 업그레이드 했습니까 아니면 90으로 유지 했습니까?

이전 시스템에서 모든 데이터를 가져 왔습니까? 그렇지 않은 경우 통계가 달라 결과적으로 쿼리 계획이 달라집니다.

SQL 2008에서 누락 된 색인 기능을 사용해 보셨습니까?

SELECT * FROM sys.dm_db_missing_index_details 
+0

매번 느립니다. 동일한 서버 및 디스크입니다. 또한 같은 데이터. 데이터베이스 호환성이 80이었습니다. 지금은 개선 된 사항이 100입니다. 누락 된 색인 기능은 더 개선 된 항목이있는 다른 색인을 제안했습니다. 쿼리 시간이 4 초로 현저히 향상되었습니다. – SeanX

2

두 컴퓨터의 actual execution plan을 비교하십시오. 그래픽 버전이 가장 유용 할 것입니다. 당신은 나무를 비교할 수 있으며, 어떤 화살이 2008 년 서버에서 실제로 큰지 확인할 수 있습니다.

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 탭을 확인하십시오. 때로는 색인 제안을 포함합니다.

+0

op가 더 이상 비교할 수 없다고 생각합니다. 업그레이드를 했습니까? 병목을 찾기위한 실행 계획을 언급 한 경우에도 1을 더한 금액입니다. – Colin

+0

새로운 SQL Server 버전을 이전 버전과 나란히 설치해야하는 이유가 있습니다. 문제가 발생할 경우 이러한 종류의 비교를 수행 할 수 있습니다. – DOK

+0

색인을 추가하면 한 번의 테스트에서 2 분에서 45 초까지 개선되었지만 여전히 느린 속도입니다. – SeanX

0

특별히 문제가되는 것은 없습니다. 비록 내가 언급 할 몇 가지 사소한 쟁점에 주목한다.

동일한 쿼리에 대한 쿼리 계획이 있습니까? 계획에서 AccData.MiddleNames에 대한 참조가 있지만 조회에는 표시되지 않습니다.

나는 몇 가지 관찰을 할

...

계획은 ACCDATA에 클러스터 된 인덱스가 성, 이름, 청구 있음을 나타냅니다. 이것은 이상적인 것이 아닙니다. 클러스터 된 인덱스에 대해 그룹화 된 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을 기록했습니다. 이것은 아마도 이상하게 보입니다. 실제로 쿼리 중복을 고려하여 쿼리 최적화 프로그램의 작업을 복잡하게 만들 가능성이 더 큽니다.

쿼리 계획에는 '중첩 루프'를 사용하는 모든 조인이 표시됩니다. 각 조인시 데이터 양이 너무 많지 않다면 이는 대개 괜찮습니다. (그래픽 계획에서이를 확인할 수 있습니다.) 기본적으로이 계획은 모든 조인에 대해 적절한 인덱스를 사용하는 것으로 보입니다. 이러한 인덱스가 무엇인지 정확히 알지 못하고 관련된 데이터의 양을 보지 못하는 것은 까다로운 일입니다.

다음 번에이 문제가 발생하면 그래픽 쿼리 계획을보고 어떤 노드가 매우 비싼 지 확인하십시오. 인덱스를 확인할 위치를 안내합니다 (만들기 또는 다시 작성).

0

2000 년에서 2005 년 사이에 비슷한 문제가 발생했습니다. 자체 조인 등을 통해 1 백만 개의 행을 볼 수 있었으며 쿼리를 3 시간 이상 실행했습니다. 우리는 그것이 다시 돌아올 지 모른다). 내 문제는 테이블의 "Nested Loops"의 수와 직접적으로 관련이있는 것처럼 보였다. 내 모든 문제가 조인에 Hash, 그리고보다 관리 30-45분에 쿼리 시간을 감소 :

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 사용 : 당신의 실행 계획에 적지을 참조하십시오.

근본 원인을 찾는 것도 좋지만 기본 해결 방법입니다.

+0

해시 조인을 추가하면 더 많은 작업이 향상됩니다. 이제 2 초 남았습니다. – SeanX

관련 문제