Zastanawiam się tylko, czy ktoś z was używa Count(1)
więcej Count(*)
i czy istnieje zauważalna różnica w wydajności, czy też jest to zwyczajny nawyk, który pojawił się w przeszłości?
Konkretna baza danych to SQL Server 2005
.
sql
sql-server
performance
super9
źródło
źródło
COUNT(*)
vsCOUNT(1)
vsCOUNT(pk)
- co jest lepsze? . Jest teżCOUNT(*)
vsCOUNT(column-name)
- co jest bardziej poprawne? . Mogą istnieć inne duplikaty.Odpowiedzi:
Nie ma różnicy.
Powód:
„1” jest wyrażeniem innym niż null: więc jest takie samo jak
COUNT(*)
. Optymalizator rozpoznaje, czym jest: trywialny.To samo co
EXISTS (SELECT * ...
lubEXISTS (SELECT 1 ...
Przykład:
To samo IO, ten sam plan, działa
Edytuj, sierpień 2011 r
Podobne pytanie na DBA.SE .
Edycja, grudzień 2011 r
COUNT(*)
jest wymieniony szczególnie w ANSI-92 (poszukaj „Scalar expressions 125
”)Oznacza to, że standard ANSI rozpoznaje to jako krwawienie oczywiste, co masz na myśli.
COUNT(1)
został zoptymalizowany przez dostawców RDBMS z powodu tego przesądu. W przeciwnym razie byłby oceniany zgodnie z ANSIźródło
W SQL Server instrukcje te dają te same plany.
Wbrew powszechnej opinii, w Oracle też tak robią.
SYS_GUID()
w Oracle jest dość intensywną funkcją obliczeniową.W mojej testowej bazie danych
t_even
znajduje się tabela z1,000,000
wierszamiTo zapytanie:
działa przez
48
kilka sekund, ponieważ funkcja musi ocenić każdeSYS_GUID()
zwrócone, aby upewnić się, że nie jest toNULL
.Jednak to zapytanie:
działa przez
2
kilka sekund, ponieważ nawet nie próbuje ocenićSYS_GUID()
(pomimo*
tego, że jest argumentemCOUNT(*)
)źródło
SYS_GUID()
przynajmniej (dokładnie dokładnie) raz, aby zapytanie podrzędne zwróciło wynik, prawda?COUNT(*)
zależy od wartościSYS_GUID
?COUNT(*)
aby uruchomić, potrzebuje tabeli, więc pod-zapytanie powinno działać jak jeden. W przeciwnym razie nie widzę sposobu naCOUNT(*)
zwrócenie znaczącej wartościmap
metoda, czy widzisz, jak te dwa wyrażenia:t_even.map(() => sys_guid()).length
it_even.length
zawsze zwraca tę samą wartość? Optymalizator Oracle jest wystarczająco inteligentny, aby go zobaczyć i zoptymalizowaćmap
część.length
nie zależy od tego, z czego składa się kolekcja, tylko od liczby jej elementów. Jeśli ta liczba jest przechowywana w metadanych kolekcji (nie dotyczy to Oracle ani większości innych współczesnych RDBMS, ale jest tak w przypadku starego silnika pamięci MySQL, MyISAM),COUNT(*)
wystarczy pobrać wartość z metadanych.Oczywiste jest,
COUNT(*)
iCOUNT(1)
będzie zawsze zwraca ten sam wynik. Dlatego, jeśli jeden byłby wolniejszy od drugiego, byłoby to skutecznie spowodowane błędem optymalizatora. Ponieważ obie formy są bardzo często używane w zapytaniach, nie ma sensu, aby DBMS pozwalał na usunięcie takiego błędu. Stąd przekonasz się, że wydajność obu formularzy jest (prawdopodobnie) identyczna we wszystkich głównych SQL DBMS.źródło
Pracuję w zespole SQL Server i mam nadzieję, że wyjaśnię kilka punktów w tym wątku (nie widziałem tego wcześniej, więc przepraszam, że zespół inżynierów nie zrobił tego wcześniej).
Po pierwsze, nie ma różnicy między semantyczne
select count(1) from table
vs.select count(*) from table
. Zwracają te same wyniki we wszystkich przypadkach (i jest to błąd, jeśli nie). Jak zauważono w innych odpowiedziach,select count(column) from table
jest semantycznie inny i nie zawsze zwraca takie same wyniki jakcount(*)
.Po drugie, w odniesieniu do wydajności, w SQL Server (i SQL Azure) ważne są dwa aspekty: praca w czasie kompilacji i praca w czasie wykonywania. Czas pracy kompilacji to trywialnie niewielka ilość dodatkowej pracy w bieżącej implementacji. W niektórych przypadkach występuje rozszerzenie * do wszystkich kolumn, po czym następuje redukcja z powrotem do 1 kolumny wynikającej z tego, jak niektóre operacje wewnętrzne działają w wiązaniu i optymalizacji. Wątpię, aby pojawił się w jakimkolwiek mierzalnym teście i prawdopodobnie zgubiłby się w hałasie wszystkich innych rzeczy, które dzieją się pod przykryciem (takich jak automatyczne statystyki, xevent sesje, koszty magazynu zapytań, wyzwalacze itp.). To może kilka tysięcy dodatkowych instrukcji procesora. Więc, count (1) wykonuje odrobinę mniej pracy podczas kompilacji (co zwykle dzieje się raz, a plan jest buforowany w wielu kolejnych wykonaniach). Jeśli chodzi o czas realizacji, przy założeniu, że plany są takie same, nie powinno być żadnej mierzalnej różnicy. (Jeden z wcześniejszych przykładów pokazuje różnicę - najprawdopodobniej wynika to z innych czynników na komputerze, jeśli plan jest taki sam).
Co do tego, jak plan może potencjalnie być inny. Jest to bardzo mało prawdopodobne, ale jest to potencjalnie możliwe w architekturze obecnego optymalizatora. Optymalizator programu SQL Server działa jako program wyszukiwania (pomyśl: program komputerowy grający w szachy, przeszukujący różne alternatywy dla różnych części zapytania i szukający alternatywnych sposobów znalezienia najtańszego planu w rozsądnym czasie). To wyszukiwanie ma kilka ograniczeń dotyczących działania, dzięki czemu kompilacja zapytań kończy się w rozsądnym czasie. W przypadku zapytań wykraczających poza najbardziej trywialne są etapy wyszukiwania i dotyczą one transz zapytań w oparciu o koszt, jaki optymalizator uważa, że zapytanie może zostać wykonane. Istnieją 3 główne fazy wyszukiwania, a każda faza może przebiegać bardziej agresywnie (kosztownie) heurystycznie, próbując znaleźć tańszy plan niż jakiekolwiek poprzednie rozwiązanie. Ostatecznie na końcu każdej fazy podejmowany jest proces decyzyjny, który ma na celu ustalenie, czy powinien zwrócić znaleziony dotąd plan, czy też powinien kontynuować wyszukiwanie. W tym procesie wykorzystano całkowity czas do tej pory w porównaniu z szacowanym kosztem najlepszego znalezionego planu. Tak więc na różnych komputerach z różnymi prędkościami procesorów możliwe (choć rzadkie) jest uzyskanie różnych planów z powodu przekroczenia limitu czasu we wcześniejszej fazie z planem w porównaniu z przejściem do następnej fazy wyszukiwania. Istnieje również kilka podobnych scenariuszy związanych z przekroczeniem limitu czasu w ostatniej fazie i potencjalnie brakiem pamięci w bardzo, bardzo drogich zapytaniach, które zajmują całą pamięć na komputerze (zwykle nie jest to problem w 64-bitach, ale był to większy problem z powrotem na serwerach 32-bitowych). Ostatecznie, jeśli otrzymasz inny plan, wydajność w czasie wykonywania może się różnić. Ja nie
Net-net: Proszę użyć dowolnej z dwóch opcji, ponieważ nic z tego nie ma znaczenia w żadnej praktycznej formie. (Szczerze mówiąc, istnieją znacznie większe czynniki, które wpływają na wydajność SQL poza tym tematem).
Mam nadzieję, że to pomoże. Napisałem rozdział w książce o tym, jak działa optymalizator, ale nie wiem, czy jest to właściwe, aby opublikować go tutaj (ponieważ wciąż otrzymuję niewielkie opłaty licencyjne). Zamiast więc zamieszczać link do wykładu, który wygłosiłem na SQLBits w Wielkiej Brytanii na temat tego, jak optymalizator działa na wysokim poziomie, aby można było zobaczyć bardziej szczegółowo różne główne fazy wyszukiwania, jeśli chcesz aby się o tym dowiedzieć. Oto link do filmu: https://sqlbits.com/Sessions/Event6/inside_the_sql_server_query_optimizer
źródło
1
również podlega tej samej ekspansji. Opieram to na testach perf tutaj tutaj stackoverflow.com/questions/1597442/... patrz także przykład w tej odpowiedzi na zapytanie, który1
nieoczekiwanie kończy się niepowodzeniem, gdy w grę wchodzą uprawnienia na poziomie kolumnyW standardzie SQL-92 w
COUNT(*)
szczególności oznacza „liczność wyrażenia tabelowego” (może to być tabela podstawowa, „WIDOK, tabela pochodna, CTE itp.).Myślę, że pomysł był taki, że
COUNT(*)
łatwo go przeanalizować. Użycie dowolnego innego wyrażenia wymaga, aby parser upewnił się, że nie odwołuje się do żadnych kolumn (COUNT('a')
gdziea
jest literał, aCOUNT(a)
gdziea
kolumna może dawać różne wyniki).Podobnie,
COUNT(*)
może być łatwo wybrany przez kodera znającego standardy SQL, co jest przydatną umiejętnością podczas pracy z ofertą SQL więcej niż jednego dostawcy.Ponadto, w szczególnym przypadku
SELECT COUNT(*) FROM MyPersistedTable;
, myślenie jest takie, że DBMS może przechowywać statystyki dotyczące liczności tabeli.Dlatego, ponieważ
COUNT(1)
iCOUNT(*)
są semantycznie równoważne, używamCOUNT(*)
.źródło
COUNT(*)
iCOUNT(1)
są takie same w przypadku wyniku i wydajności.źródło
Oczekiwałbym, że optymalizator upewni się, że nie ma prawdziwej różnicy poza dziwnymi przypadkami krawędzi.
Jak ze wszystkim, jedynym prawdziwym sposobem na stwierdzenie jest zmierzenie konkretnych przypadków.
To powiedziawszy, zawsze używałem
COUNT(*)
.źródło
Gdy to pytanie wciąż się pojawia, oto jeszcze jedna odpowiedź. Mam nadzieję dodać tutaj coś dla początkujących, którzy zastanawiają się nad „najlepszą praktyką” tutaj.
SELECT COUNT(*) FROM something
liczy rekordy, co jest łatwym zadaniem.SELECT COUNT(1) FROM something
pobiera 1 na rekord i zlicza te, które nie są zerowe, co w zasadzie zlicza rekordy, tylko bardziej skomplikowane.Powiedziawszy to: Dobra dbms zauważa, że druga instrukcja spowoduje taką samą liczbę jak pierwsza instrukcja i odpowiednio ją ponownie zinterpretuje, aby nie wykonywać niepotrzebnej pracy. Tak więc zwykle oba wyciągi skutkują tym samym planem wykonania i zajmują tyle samo czasu.
Jednak z punktu widzenia czytelności powinieneś użyć pierwszej instrukcji. Chcesz policzyć rekordy, więc policz rekordy, a nie wyrażenia. Użyj COUNT (wyrażenie) tylko wtedy, gdy chcesz policzyć niepuste wystąpienia czegoś.
źródło
Uruchomiłem szybki test na SQL Server 2012 na 8 GB pamięci RAM hyper-v. Możesz zobaczyć wyniki dla siebie. Podczas uruchamiania tych testów nie uruchomiłem żadnej innej aplikacji okienkowej oprócz SQL Server Management Studio.
Mój schemat tabeli:
Całkowita liczba rekordów w
Employee
tabeli: 178090131 (~ 178 milionów wierszy)Pierwsze zapytanie:
Wynik pierwszego zapytania:
Drugie zapytanie:
Wynik drugiego zapytania:
Można zauważyć, że istnieje różnica 83 (= 70265 - 70182) milisekund, którą można łatwo przypisać dokładnemu stanowi systemu w czasie uruchamiania zapytań. Zrobiłem również jeden bieg, więc różnica ta stanie się bardziej dokładna, jeśli wykonam kilka biegów i wykonam uśrednianie. Jeśli dla tak ogromnego zestawu danych różnica będzie mniejsza niż 100 milisekund, wówczas możemy łatwo stwierdzić, że te dwa zapytania nie mają żadnej różnicy w wydajności wykazywanej przez silnik SQL Server.
Uwaga : RAM osiąga prawie 100% zużycie w obu biegach. Zrestartowałem usługę SQL Server przed uruchomieniem obu uruchomień.
źródło
Uruchomiłem to setki razy, za każdym razem czyszcząc pamięć podręczną. Rezultaty zmieniają się od czasu do czasu, gdy obciążenie serwera jest różne, ale prawie zawsze
count(*)
ma wyższy czas procesora.źródło
count(*)
icount(1)
zwracam wyniki w ciągu kilku ms od siebie, nawet licząc tabelę z 4,5 milionami wierszy, w mojej instancji SQL 2008.Jest artykuł pokazujący, że
COUNT(1)
na Oracle jest tylko pseudonimCOUNT(*)
, z dowodem na to.Zacytuję niektóre części:
Z użytkownik z
ALTER SESSION
uprawnieniami, można umieścićtracefile_identifier
, umożliwiają śledzenie Optimizer i uruchomićCOUNT(1)
wybierz, jak:SELECT /* test-1 */ COUNT(1) FROM employees;
.Następnie musisz zlokalizować pliki śledzenia, co można zrobić
SELECT VALUE FROM V$DIAG_INFO WHERE NAME = 'Diag Trace';
. Później w pliku znajdziesz:Jak widać, jest to tylko alias
COUNT(*)
.Kolejny ważny komentarz:
COUNT(*)
było naprawdę szybciej dwie dekady temu na Oracle, przed Oracle 7.3:W przypadku innych baz danych, takich jak Sql Server, należy je zbadać indywidualnie dla każdej z nich.
Wiem, że to pytanie jest specyficzne dla Sql Server, ale inne pytania dotyczące SO na ten sam temat, bez wzmianki o bazie danych, zostały zamknięte i oznaczone jako duplikaty tej odpowiedzi.
źródło
We wszystkich RDBMS dwa sposoby liczenia są równoważne pod względem wyników, jakie dają. Jeśli chodzi o wydajność, nie zauważyłem żadnej różnicy wydajności w SQL Server, ale warto zauważyć, że niektóre RDBMS, np. PostgreSQL 11, mają mniej optymalne implementacje,
COUNT(1)
ponieważ sprawdzają nullability wyrażenia argumentu, co można zobaczyć w tym poście .Znalazłem 10% różnicy wydajności dla 1M wierszy podczas działania:
źródło
COUNT (1) nie różni się zasadniczo od COUNT (*), jeśli w ogóle. Jeśli chodzi o COUNTING NULLable COLUMN, może to być proste, aby pokazać różnice między COUNT (*) i COUNT (<some col>) -
źródło