Zainspirowany tym pytaniem, gdzie istnieją różne widoki na SET NOCOUNT ...
Czy powinniśmy używać SET NOCOUNT ON dla SQL Server? Jeśli nie, dlaczego nie?
Co robi Edytuj 6, 22 lipca 2011 r
Pomija komunikat „wpływ xx wierszy” po dowolnym DML. Jest to zestaw wyników i po wysłaniu klient musi go przetworzyć. Jest mały, ale mierzalny (patrz odpowiedzi poniżej)
W przypadku wyzwalaczy itp. Klient otrzyma wiele „wpływających wierszy xx”, co powoduje wszelkiego rodzaju błędy dla niektórych ORM, MS Access, JPA itp. (Patrz zmiany poniżej)
Tło:
Ogólnie przyjętą najlepszą praktyką (myślałem do tego pytania) jest stosowanie SET NOCOUNT ON
w wyzwalaczach i procedurach przechowywanych w SQL Server. Używamy go wszędzie, a szybkie google pokazuje wiele zgodnych MVP programu SQL Server.
MSDN twierdzi, że może to uszkodzić SQLDataAdapter .net .
Teraz oznacza to dla mnie, że SQLDataAdapter ogranicza się do całkowicie prostego przetwarzania CRUD, ponieważ oczekuje, że komunikat „n wierszy dotkniętych” zostanie dopasowany. Nie mogę więc użyć:
- JEŚLI ISTNIEJE, aby uniknąć duplikatów (komunikat nie ma wpływu na wiersze) Uwaga: należy zachować ostrożność
- GDZIE NIE ISTNIEJE (mniej wierszy niż oczekiwano
- Filtruj trywialne aktualizacje (np. Żadne dane w rzeczywistości się nie zmieniają)
- Czy wcześniej uzyskać dostęp do tabeli (np. Logowanie)
- Ukryj złożoność lub denormlisation
- itp
W pytaniu marc_s (który zna się na jego SQL-ach) mówi: nie używaj go. Różni się to od tego, co myślę (i uważam się za nieco kompetentnego w SQL).
Możliwe, że coś mi umknęło (nie krępuj się wskazać oczywiste), ale co tam myślicie ludzie?
Uwaga: minęły lata, odkąd widziałem ten błąd, ponieważ obecnie nie używam SQLDataAdapter.
Edycje po komentarzach i pytaniach:
Edycja: więcej myśli ...
Mamy wielu klientów: jeden może używać C # SQLDataAdaptor, inny może używać nHibernate z Java. Można to zmienić na różne sposoby SET NOCOUNT ON
.
Jeśli traktujesz przechowywane procy jako metody, to zła forma (anty-wzorzec) zakłada, że pewne wewnętrzne przetwarzanie działa w określony sposób na twoje własne potrzeby.
Edycja 2: wyzwalacz przerywający pytanie nHibernate , gdzie SET NOCOUNT ON
nie można ustawić
(i nie, to nie jest duplikat tego )
Edycja 3: Jeszcze więcej informacji, dzięki mojemu koledze z MVP
- KB 240882 , problem powodujący rozłączenia w SQL 2000 i wcześniejszych wersjach
- Demo zwiększenia wydajności
Edytuj 4: 13 maja 2011 r
Łamie także SQL Linq 2, gdy nie jest określony?
Edytuj 5: 14 czerwca 2011 r
Łamie JPA, przechowywane proc ze zmiennymi tabel: Czy JPA 2.0 obsługuje zmienne tabel SQL Server?
Edytuj 6: 15 sierpnia 2011 r
Siatka danych „Edycja wierszy” SSMS wymaga ustawienia USTAW NOCOUNT: Zaktualizuj wyzwalacz za pomocą GROUP BY
Edycja 7: 07 marca 2013
Bardziej szczegółowe informacje z @RemusRusanu:
Czy USTAW NOCOUNT naprawdę robi tak dużą różnicę w wydajności
Odpowiedzi:
Ok, teraz przeprowadziłem badania, oto oferta:
W protokole TDS
SET NOCOUNT ON
zapisuje tylko 9 bajtów na zapytanie, podczas gdy sam tekst „SET NOCOUNT ON” ma aż 14 bajtów. Kiedyś myślałem, że123 row(s) affected
został zwrócony z serwera zwykłym tekstem w osobnym pakiecie sieciowym, ale tak nie jest. W rzeczywistości jest to mała struktura o nazwieDONE_IN_PROC
osadzona w odpowiedzi. To nie jest osobny pakiet sieciowy, więc nie marnuje się żadna podróż w obie strony.Myślę, że możesz trzymać się domyślnego zachowania liczenia prawie zawsze, nie martwiąc się o wydajność. Są jednak przypadki, w których wcześniejsze obliczenie liczby wierszy wpłynęłoby na wydajność, na przykład kursor tylko do przodu. W takim przypadku NOCOUNT może być koniecznością. Poza tym, absolutnie nie ma potrzeby stosowania motta „używaj NOCOUNT tam, gdzie to możliwe”.
Oto bardzo szczegółowa analiza dotycząca nieistotności
SET NOCOUNT
ustawienia: http://daleburnett.com/2014/01/everything-ever-wanted-know-set-nocount/źródło
DONINPROC
(RPC) lubDONE
(BATCH) jest przesyłany strumieniowo zrowcount
ustawionymi wierszami, których dotyczy problem, podczas gdydone_count
flaga jesttrue
, niezależnie od tego, czyNO_COUNT
jestON
. Zależy od implementacji lib klienta w przypadkach, gdy zapytanie zawiera instrukcje SELECT lub wywołania RPC, które dokonują wyboru, może wymagać wyłączenia zliczania ... GDY wyłączone, wiersze są nadal liczone dla instrukcji select, ale flagaDONE_COUNT
jest ustawiona nafalse
. Zawsze czytaj to, co sugeruje twoja biblioteka lib, ponieważ zamiast ciebie interpretuje strumień tokena (wiadomości)Znalezienie prawdziwych danych porównawczych wokół NOCOUNT zajęło mi dużo czasu, więc pomyślałem, że podzielę się krótkim podsumowaniem.
źródło
SET NOCOUNT OFF;
i dlatego myślą, że nie otrzymają dodatkowych bajtów w odpowiedzi. Dokładnym punktem odniesienia byłoby zastosowanieSET NOCOUNT ON
wSET NOCOUNT OFF
procedurze przechowywanej po lewej i po prawej stronie. W ten sposób otrzymasz pakiet TDSDONEINPROC (SET NOCOUNT ...)
, jeszcze raz dziesięćDONEINPROC (INSERT statement)
, a potemRETURNVALUE(@@ROWCOUNT)
,RETURNSTATUS 0
dla sp i na końcuDONPROC
. Wystąpił błąd, ponieważ w drugim sp nie ma SET NOCOUNT OFF w ciele!Gdy SET NOCOUNT jest WŁĄCZONE, licznik (wskazujący liczbę wierszy, na które wpływa instrukcja Transact-SQL) nie jest zwracany. Gdy USTAW NOCOUNT jest WYŁĄCZONY, licznik jest zwracany. Jest używany z dowolną instrukcją SELECT, INSERT, UPDATE, DELETE.
Ustawienie SET NOCOUNT jest ustawiane w czasie wykonywania lub wykonywania, a nie w czasie analizy.
SET NOCOUNT ON poprawia wydajność procedury składowanej (SP).
Składnia: SET NOCOUNT {ON | WYŁ.}
Przykład ustawienia NOCOUNT NA:
Przykład ustawienia NOCOUNT OFF:
źródło
Myślę, że w pewnym stopniu jest to problem DBA vs. deweloper.
Jako deweloper powiedziałbym, że nie używaj go, chyba że absolutnie pozytywnie musisz - ponieważ użycie go może uszkodzić kod ADO.NET (jak udokumentował Microsoft).
I wydaje mi się, że jako DBA będziesz bardziej po drugiej stronie - używaj go, gdy tylko jest to możliwe, chyba że naprawdę musisz zapobiec jego użyciu.
Ponadto, jeśli Twoi deweloperzy kiedykolwiek używają „RecordsAffected” zwracanego przez
ExecuteNonQuery
wywołanie metody ADO.NET , masz kłopoty, jeśli wszyscy używają,SET NOCOUNT ON
ponieważ w tym przypadku ExecuteNonQuery zawsze zwróci 0.Zobacz także post na blogu Petera Bromberga i sprawdź jego pozycję.
Tak naprawdę sprowadza się to do tego, kto może ustanowić standardy :-)
Marc
źródło
Jeśli mówisz, że możesz mieć również różnych klientów, występują problemy z klasycznym ADO, jeśli SET NOCOUNT nie jest ustawiony na ON.
Jeden z nich pojawia się regularnie: jeśli procedura przechowywana wykonuje wiele instrukcji (i w ten sposób zwracanych jest wiele komunikatów „xxx wpływających na wiersze”), ADO wydaje się nie obsługiwać tego i zgłasza błąd „Nie można zmienić właściwości ActiveConnection obiektu Recordset który ma obiekt Command jako źródło. ”
Dlatego generalnie zalecam włączenie go, chyba że istnieje naprawdę dobry powód, aby tego nie robić. być może znalazłeś naprawdę dobry powód, dla którego muszę przejść i przeczytać więcej.
źródło
Ryzykując, że wszystko się skomplikuje, zachęcam nieco inną zasadę niż wszystkie powyższe:
NOCOUNT ON
na początku proc, przed wykonaniem jakiejkolwiek pracy w proc, ale także zawszeSET NOCOUNT OFF
ponownie, przed zwróceniem jakichkolwiek zestawów rekordów z zapisanego proc.Więc „ogólnie nie wyłączaj nocount, z wyjątkiem sytuacji, gdy zwracasz zestaw wyników”. Nie wiem, w jaki sposób może to złamać dowolny kod klienta, oznacza to, że kod klienta nigdy nie musi nic wiedzieć o procesach wewnętrznych i nie jest to szczególnie uciążliwe.
źródło
Jeśli chodzi o wyzwalacze przełamujące NHibernate, miałem to doświadczenie z pierwszej ręki. Zasadniczo, gdy NH wykonuje AKTUALIZACJĘ, oczekuje pewnej liczby wierszy, których to dotyczy. Dodając SET NOCOUNT ON do wyzwalaczy, otrzymujesz liczbę wierszy z powrotem do tego, czego oczekiwał NH, tym samym rozwiązując problem. Więc tak, zdecydowanie polecam wyłączenie go dla wyzwalaczy, jeśli używasz NH.
Jeśli chodzi o użycie w SP, jest to kwestia osobistych preferencji. Zawsze wyłączałem liczenie wierszy, ale z drugiej strony nie ma żadnych silnych argumentów.
Z drugiej strony, naprawdę powinieneś rozważyć odejście od architektury opartej na SP, wtedy nawet nie będziesz mieć tego pytania.
źródło
Chciałem sprawdzić, czy „USTAW NOCOUNT” nie zapisuje pakietu sieciowego ani obchodu
Użyłem testowego SQLServer 2017 na innym hoście (użyłem maszyny wirtualnej).
create table ttable1 (n int); insert into ttable1 values (1),(2),(3),(4),(5),(6),(7) go
create procedure procNoCount as begin set nocount on update ttable1 set n=10-n end
create procedure procNormal as begin update ttable1 set n=10-n end
Następnie przeszukałem pakiety na porcie 1433 za pomocą narzędzia „Wireshark”: przycisk „przechwyć filtr” -> „port 1433”exec procNoCount
to jest pakiet odpowiedzi:
0000 00 50 56 c0 00 08 00 0c 29 31 3f 75 08 00 45 00 0010 00 42 d0 ce 40 00 40 06 84 0d c0 a8 32 88 c0 a8 0020 32 01 05 99 fe a5 91 49 e5 9c be fb 85 01 50 18 0030 02 b4 e6 0e 00 00 04 01 00 1a 00 35 01 00 79 00 0040 00 00 00 fe 00 00 e0 00 00 00 00 00 00 00 00 00
exec procNormal
to jest pakiet odpowiedzi:
0000 00 50 56 c0 00 08 00 0c 29 31 3f 75 08 00 45 00 0010 00 4f d0 ea 40 00 40 06 83 e4 c0 a8 32 88 c0 a8 0020 32 01 05 99 fe a5 91 49 e8 b1 be fb 8a 35 50 18 0030 03 02 e6 1b 00 00 04 01 00 27 00 35 01 00 ff 11 0040 00 c5 00 07 00 00 00 00 00 00 00 79 00 00 00 00 0050 fe 00 00 e0 00 00 00 00 00 00 00 00 00
W linii 40 widzę „07”, czyli liczbę „wpływających wierszy”. Jest on zawarty w pakiecie odpowiedzi. Bez dodatkowego pakietu.
Ma jednak 13 dodatkowych bajtów, które można zapisać, ale prawdopodobnie nie jest to bardziej warte niż redukcja nazw kolumn (np. „ManagingDepartment” do „MD”)
Więc nie widzę powodu, aby używać go do wydajności
ALE, jak wspomnieli inni, może złamać ADO.NET i natknąłem się również na problem przy użyciu Pythona: MSSQL2008 - Pyodbc - Poprzedni SQL nie był zapytaniem
Więc prawdopodobnie dobry nawyk wciąż ...
źródło
Ten wiersz kodu jest używany w języku SQL, aby nie zwracać liczby wierszy, których dotyczy wykonanie zapytania. Jeśli nie wymagamy liczby wierszy, których dotyczy problem, możemy to wykorzystać, ponieważ pomogłoby to zaoszczędzić pamięć i zwiększyć szybkość wykonywania zapytania.
źródło
USTAW NOCOUNT ON; Powyższy kod zatrzyma komunikat generowany przez silnik serwera SQL do okna wyników z przodu po wykonaniu polecenia DML / DDL.
Dlaczego to robimy? Ponieważ silnik serwera SQL potrzebuje pewnego zasobu, aby uzyskać status i wygenerować komunikat, uważa się to za przeciążenie silnika serwera Sql, więc włączamy komunikat niezliczony.
źródło
Jednym z miejsc, które
SET NOCOUNT ON
naprawdę mogą pomóc, jest zapytania w pętli lub kursorze. Może to zsumować duży ruch sieciowy.Włączenie statystyki klienta w SSMS, seria
EXEC NoCountOn
iEXEC NoCountOff
pokazuje, że na NoCountOff był dodatkowy ruch 390 KB:Prawdopodobnie nie jest to idealne do robienia zapytań w pętli lub kursorze, ale my też nie żyjemy w idealnym świecie :)
źródło
Wiem, że to dość stare pytanie. ale tylko do aktualizacji.
Najlepszym sposobem na użycie „SET NOCOUNT ON” jest umieszczenie go jako pierwszej instrukcji w SP i ponowne ustawienie OFF tuż przed ostatnią instrukcją SELECT.
źródło
SET NOCOUNT ON pozwala nawet na dostęp do dotkniętych wierszy w następujący sposób:
Wyniki
Wiadomości
źródło
Nie wiem, jak przetestować SET NOCOUNT ON między klientem a SQL, więc przetestowałem podobne zachowanie dla innej komendy SET „USTAW POZIOM IZOLACJI ODCZYTAJ NIEOGRANICZONE”
Wysłałem polecenie z mojego połączenia, zmieniając domyślne zachowanie SQL (CZYTAJ ZAKOŃCZONO) i zostało ono zmienione dla następnych poleceń. Kiedy zmieniłem poziom ISOLATION w procedurze przechowywanej, nie zmieniło to zachowania połączenia dla następnego polecenia.
Aktualny wniosek,
Myślę, że dotyczy to innych poleceń SET, takich jak „SET NOCOUNT ON”
źródło
NOCOUNT
if (ustaw bez liczenia == wyłącz)
{wtedy będzie przechowywać dane o tym, ile rekordów wpłynęło, więc zmniejszy wydajność} else {nie będzie śledził rejestru zmian, a tym samym ulepszy perfomace}}
źródło
Czasami nawet najprostsze rzeczy mogą coś zmienić. Jednym z tych prostych elementów, które powinny być częścią każdej procedury składowanej, jest
SET NOCOUNT ON
. Ten jeden wiersz kodu umieszczony na górze procedury przechowywanej wyłącza komunikaty, które SQL Server wysyła z powrotem do klienta po wykonaniu każdej instrukcji T-SQL. Jest to wykonywane dla wszystkichSELECT
,INSERT
,UPDATE
, iDELETE
sprawozdania. Posiadanie tych informacji jest przydatne podczas uruchamiania instrukcji T-SQL w oknie zapytania, ale podczas uruchamiania procedur przechowywanych nie ma potrzeby przekazywania tych informacji z powrotem do klienta.Usunięcie tego dodatkowego obciążenia z sieci może znacznie poprawić ogólną wydajność bazy danych i aplikacji.
Jeśli nadal potrzebujesz uzyskać liczbę wierszy, na które wpływa wykonywana instrukcja T-SQL, nadal możesz użyć
@@ROWCOUNT
opcji. WydanieSET NOCOUNT ON
tej funkcji (@@ROWCOUNT
) nadal działa i może być nadal używane w procedurach przechowywanych w celu określenia, ile wierszy dotyczy instrukcja.źródło