Rozumiem, że chcę uniknąć konieczności używania kursora ze względu na koszty ogólne i niedogodności, ale wygląda na to, że ma miejsce poważna mania-fobia-kursor, w której ludzie robią wiele, aby uniknąć konieczności używania jednego.
Na przykład jedno pytanie dotyczyło tego, jak zrobić coś oczywiście trywialnego z kursorem, a akceptowana odpowiedź zaproponowana za pomocą zapytania rekurencyjnego wspólnego wyrażenia tabelowego (CTE) z rekursywną funkcją niestandardową, mimo że ogranicza to liczbę wierszy, które można przetworzyć do 32 (ze względu na limit wywołań funkcji rekurencyjnych w serwerze sql). Wydaje mi się, że jest to straszne rozwiązanie zapewniające trwałość systemu, nie wspominając o ogromnym wysiłku, aby uniknąć używania prostego kursora.
Jaki jest powód tego poziomu szalonej nienawiści? Czy jakiś „uznany autorytet” wydał fatwę przeciwko kursorom? Czy w sercu kursorów czai się jakieś niewyobrażalne zło, które psuje moralność dzieci czy coś takiego?
Pytanie na Wiki, bardziej zainteresowane odpowiedzią niż przedstawicielem.
Powiązane informacje:
SQL Server Fast Forward Cursors
EDYCJA: chcę być bardziej precyzyjny: rozumiem, że kursory nie powinny być używane zamiast normalnych operacji relacyjnych ; to nie myślenia. To, czego nie rozumiem, to to, że ludzie robią wszystko, co w ich mocy, aby unikać kursorów, takich jak mają cipy lub coś w tym rodzaju, nawet jeśli kursor jest prostszym i / lub wydajniejszym rozwiązaniem. To irracjonalna nienawiść, która mnie zaskakuje, a nie oczywiste techniczne zalety.
32
jest bezsensowna. Prawdopodobnie myślisz rekurencyjnych wyzwalaczy i max@@NESTLEVEL
od32
. Można ustawić w zapytaniuOPTION (MAXRECURSION N)
z wartością domyślną100
i0
nieograniczoną.Odpowiedzi:
„Narzut” z kursorami to tylko część interfejsu API. Kursory wskazują, jak części RDBMS działają pod maską. Często
CREATE TABLE
iINSERT
mająSELECT
instrukcje, a implementacja jest oczywistą implementacją wewnętrznego kursora.Użycie „operatorów opartych na zbiorach” wyższego poziomu łączy wyniki kursora w jeden zestaw wyników, co oznacza mniej API w przód iw tył.
Kursory są starsze niż współczesne języki, które zapewniają zbiory pierwszej klasy. Stare C, COBOL, Fortran itd. Musiały przetwarzać wiersze pojedynczo, ponieważ nie istniało pojęcie „kolekcji”, które można by szeroko stosować. Java, C #, Python itp. Mają pierwszorzędne struktury list zawierające zestawy wyników.
Problem powolny
W niektórych kręgach łączenia relacyjne są tajemnicą i ludzie będą pisać zagnieżdżone kursory zamiast zwykłego łączenia. Widziałem naprawdę epickie zagnieżdżone operacje pętli zapisane jako wiele, wiele kursorów. Pokonanie optymalizacji RDBMS. I działa bardzo wolno.
Proste przepisywanie kodu SQL w celu zastąpienia zagnieżdżonych pętli kursora łączeniami, a pojedyncza, płaska pętla kursora może sprawić, że programy będą uruchamiane 100 razy. [Myśleli, że jestem bogiem optymalizacji. Wszystko, co zrobiłem, to zastąpienie zagnieżdżonych pętli łączeniami. Nadal używano kursorów.]
To zamieszanie często prowadzi do postawienia kuratorów w stan oskarżenia. Jednak to nie kursor, tylko niewłaściwe użycie kursora jest problemem.
Kwestia rozmiaru
W przypadku naprawdę imponujących zestawów wyników (tj. Zrzucania tabeli do pliku) niezbędne są kursory. Operacje oparte na zbiorach nie mogą zmaterializować naprawdę dużych zestawów wyników jako pojedynczej kolekcji w pamięci.
Alternatywy
W miarę możliwości staram się używać warstwy ORM. Ale ma to dwa cele. Po pierwsze, kursorami zarządza komponent ORM. Po drugie, SQL jest oddzielony od aplikacji do pliku konfiguracyjnego. Nie chodzi o to, że kursory są złe. Chodzi o to, że kodowanie tych wszystkich operacji otwierania, zamykania i pobierania nie jest programowaniem z wartością dodaną.
źródło
Kursory powodują, że ludzie nadmiernie stosują proceduralny sposób myślenia w środowisku opartym na zestawie.
I są WOLNE !!!
Z SQLTeam :
źródło
Powyżej znajduje się odpowiedź, która mówi: „kursory są NAJLEPSZYM sposobem uzyskiwania dostępu do danych w SQL Server ... kursory są ponad trzydzieści razy wolniejsze niż alternatywy oparte na zestawach”.
To stwierdzenie może być prawdziwe w wielu okolicznościach, ale jako ogólne stwierdzenie jest problematyczne. Na przykład dobrze wykorzystałem kursory w sytuacjach, w których chcę wykonać operację aktualizacji lub usunięcia wpływającą na wiele wierszy dużej tabeli, która otrzymuje ciągłe odczyty produkcyjne. Uruchomienie procedury składowanej, która wykonuje te aktualizacje po jednym wierszu na raz, kończy się szybciej niż operacje oparte na zestawie, ponieważ operacja oparta na zestawie powoduje konflikt z operacją odczytu i powoduje przerażające problemy z blokowaniem (i może całkowicie zabić system produkcyjny, w ekstremalnych przypadkach).
W przypadku braku innych działań na bazie danych operacje oparte na zbiorach są zwykle szybsze. W systemach produkcyjnych to zależy.
źródło
Kursory są zwykle używane przez początkujących programistów SQL w miejscach, w których operacje oparte na zbiorach byłyby lepsze. Szczególnie, gdy ludzie uczą się SQL po nauczeniu się tradycyjnego języka programowania, mentalność „iteracji po tych rekordach” prowadzi ludzi do niewłaściwego używania kursorów.
Najpoważniejsze książki o języku SQL zawierają rozdział zalecający używanie kursorów; dobrze napisane jasno pokazują, że kursory mają swoje miejsce, ale nie powinny być używane do operacji opartych na zbiorach.
Są oczywiście sytuacje, w których kursory są właściwym wyborem, a przynajmniej właściwym wyborem.
źródło
Optymalizator często nie może użyć algebry relacyjnej do przekształcenia problemu, gdy używana jest metoda kursora. Często kursor jest świetnym sposobem rozwiązania problemu, ale SQL jest językiem deklaratywnym, aw bazie danych jest wiele informacji, od ograniczeń po statystyki i indeksy, co oznacza, że optymalizator ma wiele opcji rozwiązania problemu problem, podczas gdy kursor dość wyraźnie kieruje rozwiązaniem.
źródło
W Oracle PL / SQL kursory nie spowodują blokowania tabel i możliwe jest użycie zbiorczego gromadzenia / pobierania zbiorczego.
W Oracle 10 często używany niejawny kursor
for x in (select ....) loop --do something end loop;
pobiera niejawnie 100 wierszy naraz. Możliwe jest również jawne gromadzenie / pobieranie zbiorcze.
Jednak kursory PL / SQL są czymś w rodzaju ostateczności, używaj ich, gdy nie możesz rozwiązać problemu z SQL opartym na zestawie.
Innym powodem jest zrównoleglenie, ponieważ baza danych jest łatwiejsza do zrównoleglenia dużych instrukcji opartych na zestawie niż kod imperatywny wiersz po wierszu. Z tego samego powodu programowanie funkcjonalne staje się coraz bardziej popularne (Haskell, F #, Lisp, C # LINQ, MapReduce ...), programowanie funkcjonalne ułatwia równoległość. Liczba procesorów na komputer rośnie, więc zrównoleglenie staje się coraz większym problemem.
źródło
Ogólnie rzecz biorąc, ponieważ w relacyjnej bazie danych wydajność kodu używającego kursorów jest o rząd wielkości gorsza niż operacje na zbiorach.
źródło
Powyższe odpowiedzi nie podkreśliły wystarczająco znaczenia blokowania. Nie jestem wielkim fanem kursorów, ponieważ często powodują blokady na poziomie tabeli.
źródło
Co jest warte, przeczytałem, że "jedno" miejsce, na którym kursor wykona, jego odpowiednik oparty na zestawie jest w sumie bieżącej. W przypadku małej tabeli szybkość sumowania wierszy w kolejności według kolumn faworyzuje operację opartą na zestawie, ale gdy tabela zwiększa rozmiar wiersza, kursor będzie stawał się szybszy, ponieważ może po prostu przenosić bieżącą wartość całkowitą do następnego przebiegu pętla. Teraz, gdzie powinieneś zrobić sumę bieżącą, to inny argument ...
źródło
Poza (nie) problemami z wydajnością, myślę, że największą wadą kursorów jest to, że ich debugowanie jest bolesne. Zwłaszcza w porównaniu z kodem w większości aplikacji klienckich, w których debugowanie jest stosunkowo łatwe, a funkcje językowe są znacznie łatwiejsze. W rzeczywistości uważam, że prawie wszystko, co robi się w SQL za pomocą kursora, powinno prawdopodobnie mieć miejsce w aplikacji klienckiej.
źródło
Czy możesz opublikować przykład tego kursora lub link do pytania? Prawdopodobnie jest jeszcze lepszy sposób niż rekurencyjne CTE.
Oprócz innych komentarzy, niewłaściwe użycie kursorów (co często się zdarza) powoduje niepotrzebne blokowanie stron / wierszy.
źródło
Prawdopodobnie mógłbyś zakończyć swoje pytanie po drugim akapicie, zamiast nazywać ludzi „szalonymi” po prostu dlatego, że mają inny punkt widzenia niż ty i w inny sposób próbując kpić z profesjonalistów, którzy mogą mieć bardzo dobry powód, by czuć się tak, jak oni.
Jeśli chodzi o twoje pytanie, chociaż z pewnością są sytuacje, w których można wywołać kursor, z mojego doświadczenia wynika, że programiści decydują, że kursor „musi” być używany znacznie częściej niż jest to w rzeczywistości. Szansa, że ktoś pomyli się po stronie zbyt częstego używania kursorów vs. nieużywanie ich, kiedy powinny, jest moim zdaniem DUŻO wyższa.
źródło
w zasadzie 2 bloki kodu, które robią to samo. może to trochę dziwny przykład, ale to potwierdza. SQL Server 2005:
SELECT * INTO #temp FROM master..spt_values DECLARE @startTime DATETIME BEGIN TRAN SELECT @startTime = GETDATE() UPDATE #temp SET number = 0 select DATEDIFF(ms, @startTime, GETDATE()) ROLLBACK BEGIN TRAN DECLARE @name VARCHAR DECLARE tempCursor CURSOR FOR SELECT name FROM #temp OPEN tempCursor FETCH NEXT FROM tempCursor INTO @name SELECT @startTime = GETDATE() WHILE @@FETCH_STATUS = 0 BEGIN UPDATE #temp SET number = 0 WHERE NAME = @name FETCH NEXT FROM tempCursor INTO @name END select DATEDIFF(ms, @startTime, GETDATE()) CLOSE tempCursor DEALLOCATE tempCursor ROLLBACK DROP TABLE #temp
pojedyncza aktualizacja trwa 156 ms, podczas gdy kursor trwa 2016 ms.
źródło