2014-09-10 55 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 2014-09-10 14:33:36

+0

请澄清 - 是你的光标内的一个单一的选择运行缓慢与相同的参数选择,但外部光标比较,或您的6500迭代这个选择的总数比你期望的慢? – 2014-09-10 14:33:41

+0

@Andy,选择外部光标的时间少于8秒,参数相同但内部时间超过1分钟。在同一个游标中有很多其他的select查询运行正常,但为了使这个例子更短,我已经包含了一个运行缓慢的例子。我已经更新了我的问题,其中有很多正在运行的其他查询 – user1263981 2014-09-10 14:40:46

回答

4

无需在这里光标里面好 - 你可以使用INSERT INTOSELECT,加入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 JOINInspector表。取决于你的数据和期望的结果。

+0

我已经使用INSERT INTO和SELECT,但想知道为什么它在光标内运行时速度太慢。 – user1263981 2014-09-10 15:15:46

+0

@ user1263981 - 游标非常缓慢。一般来说,尽量远离它们。在使用游标时,您正在运行选择/插入多次,对于您的检查器表中的每个记录都会执行1次。因此,如果您的检查器表中有100条记录,那就是200个SQL调用!这只是运行一次。 – sgeddes 2014-09-10 15:28:47

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 2014-09-10 15:12:43

+0

@ user1263981:那么你需要开始检查你的索引 - 所有的**外键**列正确索引?你有'vd.DocType'和'v.VisitDate'的索引吗? – 2014-09-10 15:25:59

0

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

所以在你的循环中,你将有一个while循环,在你的表中用你的Id中的WHERE子句遍历你的表。

这要快得多。