选择Cursor中的查询耗时太长

时间:2014-09-10 14:26:01

标签: sql sql-server-2008 tsql

我设计了一个游标来对6500名检查员运行一些统计数据,但这花费的时间太长了。游标中有许多其他选择查询,但它们运行正常,但以下选择运行速度非常慢。没有光标选择查询运行完全正常。

要求:

访问上传文件(1或2或13)的每位检查员的访问次数

表格

  • Inspectors: InspectorID
  • InspectionScope: ScopeID, InspectorID (FK)
  • 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 
                    )

3 个答案:

答案 0 :(得分: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 

请注意,如果该表中的结果在其他表中不存在,则可能需要对OUTER JOIN表使用Inspector。取决于您的数据和期望的结果。

答案 1 :(得分: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

答案 2 :(得分:0)

不推荐使用游标。最好将数据插入临时表并向其中添加主键。

所以在你的循环中你将有一个while循环,它在你的表中循环,在你的Id中的临时表中有一个WHERE子句。

这要快得多。