2009-06-08 21 views
5

Chciałbym poznać twoje doświadczenia z zastąpieniem kursorów SQL Server w istniejącym kodzie lub sposobem, w jaki facet z procederem użył kursora do rozwiązania, i zrobił to na podstawie zestawu.Jakie są różne sposoby zastąpienia kursora?

W jakim problemie rozwiązano kursor? Jak zastąpiłeś kursor?

Odpowiedz

5

spróbuj nigdy pętla, praca na zbiorach danych.

można wstawiać, aktualizować, usuwać wiele wierszy jednocześnie. tutaj w przykładowej wstawce wielu wierszy:

INSERT INTO YourTable 
     (col1, col2, col3, col4) 
    SELECT 
     cola, colb+Colz, colc, @X 
     FROM .... 
      LEFT OUTER JOIN ... 
     WHERE... 

Patrząc na pętlę, zobacz, co w niej zrobiono. Jeśli jest to tylko wstawianie/usuwanie/aktualizowanie, przepisz ponownie, aby użyć pojedynczych poleceń. Jeśli istnieją IFs, sprawdź, czy mogą to być instrukcje CASE lub warunki WHERE dotyczące wstawiania/usuwania/aktualizacji. Jeśli tak, usuń pętlę i użyj poleceń set.

Pobrałem pętle i zastąpiłem je komendami opartymi na zestawie i skróciłem czas wykonywania z minut do kilku sekund. Zrobiłem procedury z wieloma zagnieżdżonymi pętlami i wywołaniami procedur i utrzymywałem pętle (nie było możliwe używanie tylko wstawek/usunięć/aktualizacji), ale usunąłem kursor i widziałem mniej blokowania/blokowania i potężne zwiększenie wydajności, jak również. Oto dwa sposoby wykorzystaniem pętli, które są lepsze niż pętle kursor ...

jeśli masz do pętli na zbiorze zrobić coś takiego:

--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 

jeśli masz rozsądny zestaw elementów (nie 100,000), aby wykonać pętlę, można to zrobić:

--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

Cóż, często programista aplikacji używany do programowania proceduralnego - z przyzwyczajenia - postaraj się zrobić wszystko proceduralnie, nawet w SQL.

Najczęściej może to być SELECT z odpowiednimi parametrami - a może masz do czynienia z instrukcją UPDATE.

Chodzi o to, że musisz zacząć myśleć w ustawieniach i powiedzieć RDBMS, co chcesz zrobić - nie, jak to zrobić krok po kroku.

Trudno podać jedną, "właściwą" odpowiedź na to ..... prawie trzeba pokazać to konkretnym przykładem.

Marc

0

Napisałem kod obliczający sumy bieżące dla danych finansowych związanych z danym rokiem. W każdym kwartale musiałem dodać wartość dla bieżącego kwartału do sumy roboczej, jednocześnie poprawnie przetwarzając wartości NULL, aby całkowita suma za poprzedni kwartał została przeniesiona, gdy wartość dla bieżącego kwartału była zerowa.

Pierwotnie zrobiłem to za pomocą kursora i z punktu widzenia funkcjonalności spełniło to wymóg biznesowy. Z technicznego punktu widzenia okazało się, że jest to przerywnik, ponieważ wraz ze wzrostem ilości danych kod zaczął się wykładać znacznie dłużej. Rozwiązaniem było zastąpienie kursora skorelowanym zapytaniem podrzędnym, które spełniało wymagania funkcjonalne i wyeliminowało wszelkie problemy z wydajnością.

Nadzieja to pomaga,

Bill

4

mam wymienić kilka kursorów z pętli while.

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' 
Powiązane problemy