Count ( * ) vs Count (1) - SQL Server

Zastanawiam się tylko, czy ktoś z was używa Count(1) ponad Count(*) i czy jest zauważalna różnica w wydajności, czy jest to tylko dziedzictwo nawyku, który został przeniesiony z dni minionych?

(konkretna baza danych to SQL Server 2005.)

Author: DineshDB, 2009-08-03

11 answers

Nie ma żadnej różnicy.

Powód:

Książki on-line mówi "COUNT ( { [ [ ALL | DISTINCT ] expression ] | * } )"

" 1 " jest wyrażeniem non-null: więc jest to to samo co COUNT(*). Optymalizator rozpoznaje to, co jest: trywialne.

To samo co EXISTS (SELECT * ... lub EXISTS (SELECT 1 ...

Przykład:

SELECT COUNT(1) FROM dbo.tab800krows
SELECT COUNT(1),FKID FROM dbo.tab800krows GROUP BY FKID

SELECT COUNT(*) FROM dbo.tab800krows
SELECT COUNT(*),FKID FROM dbo.tab800krows GROUP BY FKID

Te same IO, ten sam plan, dzieła

Edycja, Sierpień 2011

Podobne pytanie na DBA.SE .

Edycja, Grudzień 2011

COUNT(*) jest wymieniony w szczególności w ANSI-92 (poszukaj "Scalar expressions 125")

Case:

A) jeśli podano COUNT (*), to wynikiem jest Kardynalność T.

Oznacza to, że standard ANSI rozpoznaje to jako krwawienie oczywiste, co masz na myśli. COUNT(1) został zoptymalizowany przez dostawców RDBMSponieważ tego przesądu. W przeciwnym razie zostanie on oceniony zgodnie z ANSI

B) w przeciwnym razie niech TX będzie tabelą jednokolumnową, która jest wynik zastosowania do każdego wiersza T i eliminując wartości null. Jeśli jedna lub więcej wartości null jest wyeliminowane, następnie podnoszony jest warunek zakończenia: warning -

 531
Author: gbn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-13 12:42:40

W SQL serverze te wyrażenia dają te same plany.

Wbrew powszechnej opinii, w wyroczni też tak robią.

SYS_GUID() w Oracle jest to funkcja dość intensywna obliczeniowo.

W mojej testowej bazie danych, t_even jest tabela z 1,000,000 wierszy

To zapytanie:

SELECT  COUNT(SYS_GUID())
FROM    t_even

Działa przez 48 sekund, ponieważ funkcja musi ocenić każdy SYS_GUID() zwrócony, aby upewnić się, że nie jest NULL.

Jednak to zapytanie:

SELECT  COUNT(*)
FROM    (
        SELECT  SYS_GUID()
        FROM    t_even
        )

Runs for but 2 sekund, ponieważ nawet nie próbuje ocenić SYS_GUID() (mimo, że * jest argumentem do COUNT(*))

 68
Author: Quassnoi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-03 05:20:08

Oczywiście, COUNT ( * ) I COUNT(1) będą Zawsze zwracać ten sam wynik. Dlatego, gdyby jeden był wolniejszy od drugiego, spowodowałby błąd optymalizatora. Ponieważ oba formularze są bardzo często używane w zapytaniach, nie ma sensu, aby DBMS pozwalał, aby taki błąd pozostał Nie Naprawiony. W związku z tym przekonasz się, że wydajność obu form jest (prawdopodobnie) identyczna we wszystkich głównych DBMSs SQL.

 52
Author: Tony Andrews,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-31 08:54:03

W standardzie SQL-92, COUNT(*) w szczególności oznacza "Kardynalność wyrażenia tabeli" (może to być tabela bazowa, `widok, tabela pochodna, CTE, itp.).

Myślę, że chodziło o to, że COUNT(*) jest łatwe do przeanalizowania. Użycie dowolnego innego wyrażenia wymaga, aby parser upewnił się, że nie odwołuje się do żadnych kolumn (COUNT('a') Gdzie a jest literałem, a COUNT(a) Gdzie a jest kolumną może dać różne wyniki).

W tym samym duchu, COUNT(*) może być łatwo wybrany przez ludzkiego kodera znanego z standardy SQL, przydatna umiejętność podczas pracy z ofertą SQL więcej niż jednego dostawcy.

Również, w szczególnym przypadku SELECT COUNT(*) FROM MyPersistedTable;, myślenie jest DBMS może przechowywać statystyki dla kardynalności tabeli.

Dlatego, ponieważ COUNT(1) i {[0] } są semantycznie równoważne, używam COUNT(*).

 20
Author: onedaywhen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-16 08:36:45

COUNT(*) i COUNT(1) są takie same w przypadku wyniku i wydajności.

 15
Author: Nakul Chaudhary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-05 09:47:21

Spodziewałbym się, że optimiser zapewni, że poza dziwnymi przypadkami edge nie ma realnej różnicy.

Jak w przypadku czegokolwiek, jedynym prawdziwym sposobem, aby powiedzieć, jest zmierzenie konkretnych przypadków.

To powiedziawszy, zawsze używałem COUNT(*).

 12
Author: Richard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-03 10:17:05

Gdy to pytanie pojawia się raz po raz, oto jeszcze jedna odpowiedź. Mam nadzieję dodać coś dla początkujących, którzy zastanawiają się nad "najlepszymi praktykami".

SELECT COUNT(*) FROM something liczy rekordy, co jest łatwym zadaniem.

SELECT COUNT(1) FROM something pobiera 1 na rekord, a następnie zlicza 1, które nie są null, co zasadniczo liczy rekordy, tylko bardziej skomplikowane.

Powiedziawszy to: dobry dbms zauważ, że drugie polecenie spowoduje taką samą liczbę jak pierwsze i ponownie ją zinterpretuje w związku z tym, aby nie wykonywać niepotrzebnej pracy. Tak więc zazwyczaj oba polecenia skutkują tym samym planem wykonania i zajmują taką samą ilość czasu.

Jednak z punktu czytelności należy użyć pierwszego stwierdzenia. Chcesz liczyć rekordy, więc licz rekordy, a nie wyrażenia. Użyj COUNT (wyrażenie) tylko wtedy, gdy chcesz policzyć inne niż null zdarzenia czegoś.

 7
Author: Thorsten Kettner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-05 10:43:08

Przeprowadziłem szybki test na SQL Server 2012 na 8 GB RAM Hyper-V box. Możesz zobaczyć wyniki na własne oczy. Podczas wykonywania tych testów nie uruchamiałem żadnej innej aplikacji okienkowej poza SQL Server Management Studio.

Mój schemat tabeli:

CREATE TABLE [dbo].[employee](
    [Id] [bigint] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NOT NULL,
 CONSTRAINT [PK_employee] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

Całkowita liczba rekordów w Employee tabeli: 178090131 (~178 milionów wierszy)

Pierwsze Zapytanie:

Set Statistics Time On
Go    
Select Count(*) From Employee
Go    
Set Statistics Time Off
Go

Wynik pierwszego zapytania:

 SQL Server parse and compile time: 
 CPU time = 0 ms, elapsed time = 35 ms.

 (1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 10766 ms,  elapsed time = 70265 ms.
 SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

Drugi Query:

    Set Statistics Time On
    Go    
    Select Count(1) From Employee
    Go    
    Set Statistics Time Off
    Go

Wynik drugiego zapytania:

 SQL Server parse and compile time: 
   CPU time = 14 ms, elapsed time = 14 ms.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 11031 ms,  elapsed time = 70182 ms.
 SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

Można zauważyć różnicę 83 (=70265 - 70182) milisekund, które można łatwo przypisać do dokładnego stanu systemu w momencie uruchamiania zapytań. Zrobiłem również jeden bieg, więc ta różnica stanie się dokładniejsza, jeśli wykonam kilka biegów i zrobię jakieś uśrednianie. Jeśli dla tak ogromnego zestawu danych różnica przychodzi mniej niż 100 milisekund, to możemy łatwo stwierdzić, że dwa zapytania Nie mieć jakąkolwiek różnicę w wydajności wyświetlaną przez silnik SQL Server.

Uwaga : PAMIĘĆ RAM jest prawie 100% używana w obu seriach. Ponownie uruchomiłem usługę SQL Server przed uruchomieniem obu uruchomień.

 7
Author: RBT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-20 03:54:41
SET STATISTICS TIME ON

select count(1) from MyTable (nolock) -- table containing 1 million records. 

Czas wykonania SQL Server:
Czas procesora = 31 ms, upłynął czas = 36 ms.

select count(*) from MyTable (nolock) -- table containing 1 million records. 

Czas wykonania SQL Server:
Czas procesora = 46 ms, upłynął czas = 37 ms.

Sprawdzałem to setki razy, za każdym razem czyściłem pamięć podręczną.. Wyniki różnią się od czasu do czasu, ponieważ obciążenie serwera zmienia się, ale prawie zawsze count (*) ma wyższy czas procesora.
 7
Author: Eyal Z.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-22 10:43:41

Istnieje Artykuł pokazujący, że COUNT(1) on Oracle jest tylko aliasem do COUNT(*), z dowodem na ten temat.

Zacytuję kilka części:

Istnieje część oprogramowania bazy danych, która nazywa się " The Optimizer", który jest zdefiniowany w oficjalnej dokumentacji jako "Wbudowane oprogramowanie bazodanowe, które określa najbardziej efektywny sposób na wykonaj polecenie SQL".

Jednym ze składników optymalizatora jest "transformator", którego zadaniem jest ustalenie, czy korzystne jest przepisanie oryginalne polecenie SQL do semantycznie równoważnego polecenia SQL to może być bardziej efektywne.

Czy chcesz zobaczyć, co robi optymalizator, gdy piszesz zapytanie używając COUNT (1)?

Z użytkownikiem z uprawnieniami ALTER SESSION, możesz umieścić tracefile_identifier, włączyć śledzenie optymalizatora i uruchomić COUNT(1) select, jak: SELECT /* test-1 */ COUNT(1) FROM employees;.

Następnie musisz zlokalizować pliki śledzenia, co można zrobić z SELECT VALUE FROM V$DIAG_INFO WHERE NAME = 'Diag Trace';. W dalszej części Pliku znajdziesz:

SELECT COUNT(*) “COUNT(1)” FROM “COURSE”.”EMPLOYEES” “EMPLOYEES”

Jak widzisz, to tylko pseudonim COUNT(*).

Kolejny ważny komentarz: {[2] } był naprawdę szybszy dwie dekady temu NA Oracle, przed Oracle 7.3:

Count(1) został przepisany w count (*) od 7.3 ponieważ Oracle jak aby automatycznie dostroić mityczne wypowiedzi. Wcześniej oracle7, oracle musiał Oceniać (1) dla każdego wiersza, jako funkcji, przed deterministycznym i Nie-deterministyczne istnieją.

Więc dwie dekady temu, count (*) był szybszy

Dla innych baz danych jako SQL Server, powinien być badany 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 zduplikowane z tej odpowiedzi.

 2
Author: Dherik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-26 11:50:14

Easy to demo COUNT(*) vs COUNT()--

USE tempdb;
GO

IF OBJECT_ID( N'dbo.Blitzen', N'U') IS NOT NULL DROP TABLE dbo.Blitzen;
GO

CREATE TABLE dbo.Blitzen (ID INT NULL, Somelala CHAR(1) NULL);

INSERT dbo.Blitzen SELECT 1, 'A';
INSERT dbo.Blitzen SELECT NULL, NULL;
INSERT dbo.Blitzen SELECT NULL, 'A';
INSERT dbo.Blitzen SELECT 1, NULL;

SELECT COUNT(*), COUNT(1), COUNT(ID), COUNT(Somelala) FROM dbo.Blitzen;
GO

DROP TABLE dbo.Blitzen;
GO
 -1
Author: Graeme,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-22 17:00:08