2009-06-08 15 views

Antwort

5

Versuch nie Schleife, die Arbeit an Datensätzen.

Sie können mehrere Zeilen gleichzeitig einfügen, aktualisieren oder löschen. Hier in einem Beispiel einfügen von mehreren Zeilen:

Wenn Sie eine Schleife betrachten, sehen Sie, was es darin getan hat. Wenn es sich nur um Einfügungen/Löschungen/Aktualisierungen handelt, schreiben Sie neu, um einzelne Befehle zu verwenden. Wenn IFs vorhanden sind, prüfen Sie, ob dies CASE-Anweisungen oder WHERE-Bedingungen für Einfügungen/Löschungen/Aktualisierungen sein können. Wenn dies der Fall ist, entfernen Sie die Schleife und verwenden Sie set-Befehle.

Ich habe Schleifen genommen und sie mit den Set-basierten Befehlen ersetzt und die Ausführungszeit von Minuten auf ein paar Sekunden reduziert. Ich habe Prozeduren mit vielen verschachtelten Schleifen und Prozeduraufrufen gemacht und die Schleifen behalten (es war unmöglich, nur Einfügungen/Löschungen/Aktualisierungen zu verwenden), aber ich entfernte den Cursor und habe weniger Sperren/Blockierungen und massive Leistungssteigerungen gesehen. Hier sind zwei Looping Methoden, die besser sind als Cursor-Loops ...

wenn Sie eine Schleife haben, über einen Satz etwas tun, wie folgt aus:

--this looks up each row for every iteration 
DECLARE @msg VARCHAR(250) 
DECLARE @hostname sysname 

--first select of currsor free loop 
SELECT @hostname= min(RTRIM(hostname)) 
    FROM master.dbo.sysprocesses (NOLOCK) 
    WHERE hostname <> '' 

WHILE @hostname is not null 
BEGIN 
    set @msg='exec master.dbo.xp_cmdshell "net send ' 
     + RTRIM(@hostname) + ' ' 
     + 'testing "' 
    print @msg 
    --EXEC (@msg) 

    --next select of cursor free loop 
    SELECT @hostname= min(RTRIM(hostname)) 
     FROM master.dbo.sysprocesses (NOLOCK) 
     WHERE hostname <> '' 
     and hostname > @hostname 
END 

wenn Sie eine angemessene Menge von Elementen (nicht 100.000) in einer Schleife über Sie dies tun können:

--this will capture each Key to loop over 
DECLARE @msg VARCHAR(250) 
DECLARE @From int 
DECLARE @To  int 
CREATE TABLE #Rows 
(
    RowID  int not null primary key identity(1,1) 
    ,hostname varchar(100) 
) 

INSERT INTO #Rows 
SELECT DISTINCT hostname 
    FROM master.dbo.sysprocesses (NOLOCK) 
    WHERE hostname <> '' 
SELECT @From=0,@[email protected]@ROWCOUNT 

WHILE @From<@To 
BEGIN 
    SET @[email protected]+1 

    SELECT @msg='exec master.dbo.xp_cmdshell "net send ' 
     + RTRIM(hostname) + ' ' 
     + 'testing "' 
     FROM #Rows WHERE [email protected] 
    print @msg 
    --EXEC (@msg) 
END 
2

Nun, oft wird ein App-Entwickler, der an prozedurale Programmierung gewöhnt ist, aus Gewohnheit versuchen, alles auch in SQL prozedural zu machen.

Meistens kann ein SELECT mit den richtigen Parametern tun - oder vielleicht handelt es sich um eine UPDATE-Anweisung.

Der Punkt ist wirklich: Sie müssen beginnen, in Set-Operationen zu denken und sagen Sie Ihrem RDBMS, was Sie tun wollen - nicht, wie es Schritt für Schritt geht.

Es ist schwer, eine einzige, "richtige" Antwort zu geben ... Sie müssten es fast mit einem konkreten Beispiel zeigen.

Marc

0

ich schrieb einig Code, der zu einem bestimmten Jahr im Zusammenhang für Finanzdaten laufende Summen berechnet. In jedem Quartal musste ich den Wert für das laufende Quartal zur laufenden Summe addieren, während NULLs entsprechend behandelt wurden, sodass die laufende Summe für das vorangegangene Quartal übernommen wurde, wenn der Wert für das aktuelle Quartal NULL war.

Ursprünglich habe ich dies mit einem Cursor gemacht und funktionell erfüllt dies die Geschäftsanforderungen. Aus technischer Sicht erwies es sich als Show-Stopper, denn mit zunehmender Datenmenge nahm der Code exponentiell mehr Zeit in Anspruch. Die Lösung bestand darin, den Cursor durch eine korrelierte Unterabfrage zu ersetzen, die die funktionalen Anforderungen erfüllte und jegliche Leistungsprobleme beseitigte.

hoffe, das hilft,

Bill

4

Ich habe einige Cursor mit WHILE-Schleifen ersetzt.

DECLARE @SomeTable TABLE 
(
    ID int IDENTITY (1, 1) PRIMARY KEY NOT NULL, 
    SomeNumber int, 
    SomeText varchar 
) 

DECLARE @theCount int 
DECLARE @theMax int 

DECLARE @theNumber int 
DECLARE @theText varchar 

INSERT INTO @SomeTable (SomeNumber, SomeText) 
SELECT Number, Text 
FROM PrimaryTable 

SET @theCount = 1 
SELECT @theMax = COUNT(ID) FROM @SomeTable 

WHILE (@theCount <= @theMax) 
BEGIN 

    SET @theNumber = 0 
    SET @theText = '' 

    SELECT @theNumber = IsNull(Number, 0), @theText = IsNull(Text, 'nothing') 
    FROM @SomeTable 
    WHERE ID = @theCount 

    -- Do something. 
    PRINT 'This is ' + @theText + ' from record ' + CAST(@theNumber AS varchar) + '.' 

    SET @theCount = @theCount + 1 

END 

PRINT 'Done' 
Verwandte Themen