Są zapytania, w których gdy klikniemy „wykonaj”, pokazuje niektóre wiersze i wciąż rośnie, ale zapytanie jeszcze się nie skończyło. Czasami jednak czeka do końca zapytania.
Dlaczego to się dzieje? Czy istnieje sposób, aby to kontrolować?
źródło
Są zapytania, w których gdy klikniemy „wykonaj”, pokazuje niektóre wiersze i wciąż rośnie, ale zapytanie jeszcze się nie skończyło. Czasami jednak czeka do końca zapytania.
Dlaczego to się dzieje? Czy istnieje sposób, aby to kontrolować?
Odpowiedź, jak zwykle (w porządku, przez większość czasu), leży w planie wykonania.
Istnieją pewne operatory, które wymagają, aby wszystkie wiersze do nich dotarły, zanim będą mogły rozpocząć przetwarzanie tych wierszy i przekazywanie ich dalej, na przykład:
Z tego powodu nazywane są albo blokowaniem, albo operatorami „zatrzymaj i jedź”, i często są wybierani, gdy optymalizator uważa, że będzie musiał przetworzyć całą masę danych, aby znaleźć twoje dane.
Istnieją inni operatorzy, którzy mogą natychmiast rozpocząć transmisję strumieniową lub przekazać znalezione wiersze
Gdy zapytania zaczynają zwracać dane natychmiast, ale nie kończą się natychmiast, zwykle jest to znak, że optymalizator wybrał plan szybkiego zlokalizowania i zwrócenia niektórych wierszy przy użyciu operatorów o niższych kosztach uruchomienia.
Może się to zdarzyć z powodu celów rzędów wprowadzonych przez Ciebie lub przez optymalizatora.
Może się to również zdarzyć, jeśli z jakiegoś powodu zostanie wybrany zły plan (brak SARGability, wąchanie parametrów, niewystarczająca statystyka itp.), Ale to wymaga więcej wykopalisk.
Aby uzyskać więcej informacji, sprawdź blog Roba Farleya tutaj
I seria Paula White'a na temat bramek tutaj , tutaj , tutaj i tutaj .
Należy również zauważyć, że jeśli mówimy o SSMS, wiersze pojawiają się tylko po wypełnieniu całego bufora, a nie tylko nie chcąc.
Jeśli rozumiem, co obserwujesz, w ten sposób Management Studio renderuje wiersze i ma niewiele wspólnego z tym, jak SQL Server zwraca wiersze. W rzeczywistości często, gdy zwracasz duże wyniki do SSMS i próbujesz wyrenderować je w siatce, SSMS nie może nadążyć, a SQL Server czeka na przetworzenie przez aplikację większej liczby wierszy. W takim przypadku zobaczysz, że SQL Server gromadzi ASYNC_NETWORK_IO
oczekiwania.
Możesz to nieco kontrolować, używając wyników do tekstu zamiast wyników do siatki, ponieważ SSMS może rysować tekst szybciej niż może rysować siatki, ale prawdopodobnie okaże się, że może to wpłynąć na czytelność w zależności od liczby kolumn i typów danych. Oba mają wpływ na to, kiedy SSMS decyduje się faktycznie zapisać wyniki w tym okienku, co zależy od tego, jak pełny jest bufor wyjściowy.
Jeśli masz wiele instrukcji i chcesz zmusić bufor do renderowania wyników w okienku komunikatów, możesz zastosować małą sztuczkę drukowania między instrukcjami:
RAISERROR('', 0, 1) WITH NOWAIT;
Ale to nie pomoże, gdy próbujesz zmusić SSMS do szybszego renderowania wierszy, gdy wszystkie dane wyjściowe pochodzą z jednej instrukcji.
Bardziej bezpośrednio, możesz kontrolować to, ograniczając liczbę wyników renderowanych w SSMS. Często widzę, jak ludzie narzekają na to, ile czasu zajmuje powrót miliona wierszy do siatki. Nie mam pojęcia, co, u licha, zrobi milion wierszy w siatce SSMS.
Istnieje kilka takich hacków OPTION (FAST 100)
, które zoptymalizują pobieranie pierwszych 100 wierszy (lub dowolnych 100 wierszy, jeśli nie ma zewnętrznego ORDER BY
), ale może to kosztować znacznie wolniejsze wyszukiwanie pozostałych wierszy i planu, który jest bardziej ogólnie nieefektywne, więc tak naprawdę nie jest to opcja IMHO.
Twoje pytanie nie dotyczy samego SQLServera, ale:
Czy istnieje sposób, aby to kontrolować?
Krótka odpowiedź :
sqlcmd
zamiast ssms
lub sqlcmd
-mode zssms
Długa odpowiedź :
Oczywiście! Ale nie jeden - prob
sqlcmd
lub w sqlcmd
trybie -mms w ssms.spid
a otrzymasz pełną listę ustawień sesji. Porównaj z ustawieniami sqlcmd
sesji. Jeśli nic nie kliknie - skopiuj wszystkie ustawienia sesji z profilera do skryptu zapytania, uruchom w trybie sqlcmd
-mode i stopniowo zmieniając ustawienia znajdziesz swojego winowajcę.Powodzenia!
Aby dodać do odpowiedzi sp_BlitzErik, weź przykład używając a NOT IN ()
z wyborem podrzędnym. Aby ustalić, czy element jest wynikiem zagnieżdżonego zapytania, (ogólnie) konieczne jest pobranie całego wyniku.
Tak więc jednym ze sposobów, w jaki znalazłem sposób na poprawienie wydajności takich zapytań, jest przepisanie ich tak, aby LEFT OUTER JOIN
warunek dla RIGHT
strony był zerowy (możesz to odwrócić, oczywiście, ale kto używa RIGHT OUTER JOINS
?). Pozwala to na natychmiastowe rozpoczęcie wyników.
WHERE t.x IN (<complex SELECT subquery>)
, równoważne LEWE DOŁĄCZLEFT JOIN (<complex SELECT subquery>) AS r ON r.x = t.x .... WHERE r.x IS NULL
, wtedy również podzapytanie będzie musiało zostać ocenione (tak samo złożony plan z NOT W wersji).NOT EXISTS
ale OracleNOT IN
w zapytaniach. Ale dziś należy to uznać za błąd w generatorze planów