2009-08-26 14 views
2

Was ist die beste Alternative zur Verwendung eines Cursors in SQL, wenn ich unter Leistungsproblemen leide?Cursor in SQL vermeiden

Ich habe den folgenden Code, in dem Cursor zum Durchschleifen und Einfügen von Datensätzen verwendet.

 DECLARE @AuditBatchID_logRow INT, 
    @AuditOperationID_logRow INT, 
    @RowIdentifier_logRow nvarchar(200), 
    @AuditDBTableID_logRow INT, 
    @AuditLogRowID INT, 

    @AuditDBColumnID INT, 
    @NewValue nvarchar(200), 
    @PreviousVaue nvarchar(200), 
    @NewDisplayValue nvarchar(200) 

    DECLARE Crsr_AUDITLOGROW CURSOR LOCAL FORWARD_ONLY STATIC 
     FOR 
     SELECT [t0].[AuditBatchID], 
       [t1].[AuditOperationID], 
       [t1].[RowIdentifier], 
       [t0].[AuditTableID], 
       [t1].[AuditLogRowID] 
     FROM [AuditBatchTable] AS [t0] 
     INNER JOIN [AuditLogRow] AS [t1] 
       ON [t0].[AuditBatchTableID] = [t1].[AuditBatchTableID] 

    Open Crsr_AUDITLOGROW 

    FETCH NEXT FROM Crsr_AUDITLOGROW 
    INTO @AuditBatchID_logRow, 
      @AuditOperationID_logRow, 
      @RowIdentifier_logRow, 
      @AuditDBTableID_logRow, 
      @AuditLogRowID 

    While(@@FETCH_STATUS = 0) 
    BEGIN 
     INSERT INTO AuditLog(AuditLogRowID, AuditColumnID, 
          NewValue, OldDisplayValue, NewDisplayValue) 
     (SELECT @AuditLogRowID, 
       [ac].[AuditColumnID], 
       [t0].[UserEnteredValue], 
       [t0].[PreviousDisplayValue], 
       [t0].[DisplayValue] 
      FROM FMG_PROD.dbo.AuditLog AS [t0] 
      INNER JOIN FMG_PROD.dbo.AuditDBColumn AS [t1] 
      ON [t0].[AuditDBColumnID] = [t1].[AuditDBColumnID] 
      INNER JOIN FMG_PROD.dbo.AuditDBTable AS [t2] 
      ON [t1].[AuditDBTableID] = [t2].[AuditDBTableID] 
      INNER JOIN AuditTable AS [AT] 
      ON [t2].AuditDBTable = [AT].AuditTable 
      INNER JOIN AuditColumn AS [AC] 
      ON [AT].AuditTableID = [AC].AuditTableID 
      WHERE  
      ([t0].[AuditBatchID] = @AuditBatchID_logRow) 
      AND ([t0].[AuditOperationID] = @AuditOperationID_logRow) 
      AND ([AT].[AuditTableID] = @AuditDBTableID_logRow) 
      AND [AC].AuditColumn = [t1].AuditDBColumn 
      AND (@RowIdentifier_logRow = 
       CASE ISNUMERIC(@RowIdentifier_logRow) 
        WHEN 1 then 
         CAST ([t0].[RowID] AS VARCHAR(200)) 
        ELSE 
         CAST([t0].[RowGUID] AS VARCHAR(200)) 
    END)) 

     FETCH NEXT FROM Crsr_AUDITLOGROW 
      INTO @AuditBatchID_logRow, 
       @AuditOperationID_logRow, 
       @RowIdentifier_logRow, 
       @AuditDBTableID_logRow, 
       @AuditLogRowID 
END 

CLOSE Crsr_AUDITLOGROW 
DEALLOCATE Crsr_AUDITLOGROW 

Antwort

8

Nun, Sie denken und Codierung wie ein strukturierter Programmierer - linear, eins nach dem anderen, in tighest Steuerung des Programmablaufs. So haben wir (fast) alle gedacht, um zu programmieren.

Sie müssen wie ein SQL-Typ denken - in SETS von Daten (nicht einzelne Zeilen, jeweils einzeln).

die Notwendigkeit vermeiden zu eng jeden Schritt des Algorithmus steuern - stattdessen nur SQL Server sagen WAS Sie wollen - nicht WIE jeden Schritt zu tun!

Am Ende fügen Sie eine Reihe von Zeilen in die Tabelle AuditLog ein. Warum brauchst du dafür einen Cursor?

INSERT INTO AuditLog(...list of columns.....) 
    SELECT (....list of columns....) 
    FROM Table1 
    INNER JOIN .......... 
    INNER JOIN ......... 
    WHERE ........ 

und fertig! Definieren Sie was Sie wollen in die Tabelle eingefügt werden - DO NOT SQL Server in quälenden Detail sagen, wie es geht - es wird sehr gut wissen, danke!

Marc

+1

+1 für die Bedeutung des Denkens in Sätzen. – APC

+0

Dank Marc hat mir sehr geholfen. Reduziert viel Code und hat eine bessere Leistung. – Sreedhar

+0

Großartig! Froh, dass ich helfen konnte! –