2014-09-10 4 views
1

6500 검사기에 대해 일부 통계를 실행하도록 커서를 설계했지만 너무 오래 걸립니다. 커서에는 다른 많은 선택 쿼리가 있지만 괜찮아 보이지만 다음 선택은 매우 느리게 실행됩니다. 커서를 선택하지 않으면 쿼리가 완벽하게 정상적으로 실행됩니다.커서가 너무 오래 걸리는 쿼리

요건 :

  • Inspectors: InspectorID
  • InspectionScope: ScopeID, InspectorID (FK)
  • : 방문 문서 (1 또는 2 또는 13)에 업로드 한 각 검사

    테이블에 대한 방문

    번호

  • Visits: VisitID, VisitDate ScopeID (FK)
  • VisitsDoc: DocID, DocType, VisitID (FK)

커서 코드 :

DECLARE 
     @curInspID int, 
     @DateFrom date, @DateTo date; 

SELECT @DateTo = CAST(GETDATE() AS DATE) 
     ,@DateFrom = CAST(GETDATE() - 90 AS DATE) 


DECLARE 
     @InspectorID int, 
     @TotalVisits int; 


DECLARE @Report TABLE (
     InspectorID int, 
     TotalVisits int) 


DECLARE curList CURSOR FOR 
    SELECT InspectorID FROM Inspectors ;   


OPEN curList 
FETCH NEXT FROM curList INTO @curInspID; 

WHILE @@FETCH_STATUS = 0 
BEGIN 

SELECT 
    @curInspID = s.InspectorID  
    ,@TotalVisits = COUNT(distinct v.visitID) 
from Visits v 
inner join InspectionScope s on s.ScopeID = v.ScopeID 
inner join VisitDocs vd on vd.VisitID = v.VisitID 
where s.InspectorID = @curInspID and vd.DocType IN (1,2,13) 
and v.VisitDate BETWEEN @DateFrom and @DateTo 
group by s.InspectorID 


INSERT INTO @Report VALUES(@curInspID,@TotalVisits); 

FETCH NEXT FROM curList INTO @curInspID; 
END 

CLOSE curList 
DEALLOCATE curList 

SELECT * FROM @Report 

다음 쿼리가 여기에 커서 필요가

,@TotalVisitsWithReportScore = (select COUNT(v.visitid) from visits v 
         inner join InspectionScope s on s.ScopeID = v.ScopeID 
         where v.ReportStandard not in (0,9) and v.VisitType = 1 
          and v.VisitDate BETWEEN @DateFrom and @DateTo 
          and s.InspectorID = @curInspID 
          ) 

    ,@TotalVisitsWith_ReportScore_RejectionFeedBack = (select COUNT(v.visitid) from visits v 
         inner join InspectionScope s on s.ScopeID = v.ScopeID 
         where v.ReportStandard not in (0,9) and v.VisitType = 1 
          and v.DiscrepancyType IN (2,5,6,7,8) 
          and v.VisitDate BETWEEN @DateFrom and @DateTo 
          and s.InspectorID = @curInspID 
        ) 
+0

커서를 사용하여 쿼리를 실행하기 전에 문제가 발생했습니다. 반쯤 취소하면 열려있는 커서가 메모리에 유지됩니다. – Donal

+0

제발, clarify - 동일한 매개 변수를 선택하지만 커서 밖에서 천천히 실행되는 커서 내부의 단일 선택 또는이 선택의 총 6500 반복은 예상보다 느립니다? –

+0

@Andy, 외부 커서 선택은 동일한 매개 변수로 8 초 미만이지만 내부에는 1 분 이상 걸립니다.이 동일한 커서에는 잘 실행되는 많은 다른 선택 쿼리가 있지만이 예제를 더 짧게 만들려면 느리게 실행되는 쿼리를 포함 시켰습니다. – user1263981

답변

4

같은 커서 내부 괜찮 실행 - 당신이 INSERT INTO을 사용할 수 없습니다 SELECT, Inspector 테이블에 합류.

INSERT INTO @Report 
SELECT 
    s.InspectorID  
    , COUNT(distinct v.visitID) 
from Visits v 
    inner join InspectionScope s on s.ScopeID = v.ScopeID 
    inner join VisitDocs vd on vd.VisitID = v.VisitID 
    inner join Inspector i on s.InspectorID = i.InspectorId 
where vd.DocType IN (1,2,13) 
and v.VisitDate BETWEEN @DateFrom and @DateTo 
group by s.InspectorID 

당신이 다른 테이블에 존재하지 않는 테이블에 결과가있는 경우 Inspector 테이블이있는 OUTER JOIN를 사용해야 할 수 있습니다. 데이터 및 원하는 결과에 따라 다릅니다.

+0

SELECT를 사용하여 INSERT INTO를 이미 사용했지만 커서가 내부에서 실행될 때 너무 느린 이유를 알고 싶습니다. – user1263981

+0

@ user1263981 - 커서가 매우 느립니다. 일반적으로 말하자면, 그들로부터 멀리 떨어져있게하십시오. 커서를 사용할 때 인 스 뷰어 테이블의 각 레코드에 대해 1 회 선택/삽입을 실행합니다. 인스펙터 테이블에 100 개의 레코드가 있으면 200 개의 SQL 호출입니다! 이것은 단지 한 번 실행됩니다. – sgeddes

1

커서를 빠르게하는 가장 좋은 방법은을 제거하는 것입니다 ... ! 할 것입니다 간단한 SELECT을 - - 여기

, 당신은 확실히 커서를 필요가 없습니다 빠른 실질적으로을해야합니다!

DECLARE @Report TABLE (InspectorID int, TotalVisits int) 

DECLARE curList CURSOR FOR 
    SELECT InspectorID FROM Inspectors ;   


OPEN curList 
FETCH NEXT FROM curList INTO @curInspID; 

WHILE @@FETCH_STATUS = 0 
BEGIN 

INSERT INTO @Report (InspectorID, TotalVisits) 
    SELECT 
     i.InspectorID, 
     COUNT(v.visitID) 
    FROM 
     dbo.Inspectors i 
    INNER JOIN 
     dbo.InspectionScope s ON s.InspectorId = i.InspectorId 
    INNER JOIN 
     dbo.Visits v ON s.ScopeID = v.ScopeID 
    INNER JOIN 
     dbo.VisitDocs vd ON vd.VisitID = v.VisitID 
    WHERE 
     vd.DocType IN (1, 2, 13) 
     AND v.VisitDate BETWEEN @DateFrom AND @DateTo 
    GROUP BY 
     s.InspectorID 

SELECT * FROM @Report 
+0

여전히 너무 오래 걸립니다 ... – user1263981

+0

@ user1263981 : 그렇다면 색인 생성을 확인해야합니다. ** 모든 외래 키 ** 열이 적절하게 색인되어 있습니까? 당신은'vd.DocType'과'v.VisitDate'에 인덱스를 가지고 있습니까 ?? –

0

커서는 더 이상 권장되지 않습니다. 임시 테이블에 데이터를 삽입하고 기본 키를 추가하는 것이 좋습니다.

루프에서 임시 테이블의 ID에 WHERE 절을 사용하여 테이블을 반복하는 while 루프가 생깁니다.

훨씬 더 빠릅니다.

관련 문제