COUNT ( * ) vs. COUNT(1) vs. COUNT (pk): która jest lepsza? [duplikat]
To pytanie ma już odpowiedź tutaj:
- Count ( * ) vs Count (1) - SQL Server 11 odpowiedzi
Często znajduję te trzy warianty:
SELECT COUNT(*) FROM Foo;
SELECT COUNT(1) FROM Foo;
SELECT COUNT(PrimaryKey) FROM Foo;
Z tego co widzę, wszystkie robią to samo, a ja używam tych trzech w mojej bazie kodowej. Jednak nie lubię robić tego samego na różne sposoby. Do którego mam się przyczepić? Czy każdy z nich lepszych od dwóch pozostałych?
6 answers
Bottom Line
Użyj COUNT(field)
lub COUNT(*)
i trzymaj się tego konsekwentnie, a jeśli twoja baza danych pozwala COUNT(tableHere)
lub COUNT(tableHere.*)
, użyj tego.
Krótko mówiąc, nie używaj COUNT(1)
do niczego. Jest to kucyk jednokierunkowy, który rzadko robi to, co chcesz, a w rzadkich przypadkach jest odpowiednikiem count(*)
{51]}
Użyj count(*)
do liczenia
Użyj *
dla wszystkich zapytań, które muszą liczyć wszystko, nawet dla łączy, użyj *
SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
Ale nie używaj COUNT(*)
dla LEFT joins, ponieważ zwróci 1, nawet jeśli tabela podrzędna nie pasuje do niczego z tabeli nadrzędnej
SELECT boss.boss_id, COUNT(*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
Nie daj się zwieść tym, którzy doradzają, że gdy używasz *
w liczeniu, pobiera cały wiersz z Twojej tabeli, mówiąc, że *
jest powolny. *
na SELECT COUNT(*)
i SELECT *
nie mają ze sobą żadnego związku, są zupełnie inną rzeczą, po prostu dzielą wspólny znak, tj. *
.
Składnia alternatywna
W rzeczywistości, jeśli nie jest dozwolone nazwanie pola jako podobnie jak nazwa tabeli, projektant języka RDBMS może nadać COUNT(tableNameHere)
taką samą semantykę jak COUNT(*)
. Przykład:
Do liczenia wierszy możemy mieć to:
SELECT COUNT(emp) FROM emp
I mogliby to uprościć:
SELECT COUNT() FROM emp
/ Align = "LEFT" / ]}
SELECT boss.boss_id, COUNT(subordinate)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
Ale nie mogą tego zrobić (COUNT(tableNameHere)
), ponieważ standard SQL pozwala na nazwanie pola o tej samej nazwie, co nazwa tabeli:
CREATE TABLE fruit -- ORM-friendly name
(
fruit_id int NOT NULL,
fruit varchar(50), /* same name as table name,
and let's say, someone forgot to put NOT NULL */
shape varchar(50) NOT NULL,
color varchar(50) NOT NULL
)
Liczenie przez null
[50]} a także, nie jest dobrą praktyką, aby pole nullable, jeśli jego nazwa odpowiada nazwie tabeli. Powiedzmy, że masz wartości 'Banana', 'Apple', NULL, 'Pears' w polufruit
. To nie zliczy wszystkich wierszy, da tylko 3, a nie 4
SELECT count(fruit) FROM fruit
Chociaż niektóre RDBM stosują taką zasadę (do zliczania wierszy tabeli przyjmuje nazwę tabeli jako parametr COUNT), będzie to działać w Postgresql (jeśli nie ma pola subordinate
w żadnej z dwóch poniższych tabel, tzn. tak długo, jak nie ma konfliktu nazw między nazwą pola a tabelą "nazwa": {]}
SELECT boss.boss_id, COUNT(subordinate)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
Ale może to spowodować zamieszanie później, jeśli dodamy pole subordinate
w tabeli, ponieważ będzie liczyć pole (które może być nullable), a nie wiersze tabeli.
Aby być po bezpiecznej stronie, użyj:
SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
count(1)
: the one-trick pony
W szczególności do COUNT(1)
, jest to kucyk jednokierunkowy , działa dobrze tylko na jednym zapytaniu tabeli:
SELECT COUNT(1) FROM tbl
Ale kiedy używasz joins, ta sztuczka nie będzie działać na zapytaniach wielostolikowych bez jej semantyki jest zdezorientowany, a w szczególności nie można napisać:
-- count the subordinates that belongs to boss
SELECT boss.boss_id, COUNT(subordinate.1)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
Więc jakie jest znaczenie COUNT (1) tutaj?
SELECT boss.boss_id, COUNT(1)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
To jest to...?
-- counting all the subordinates only
SELECT boss.boss_id, COUNT(subordinate.boss_id)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
Albo to...?
-- or is that COUNT(1) will also count 1 for boss regardless if boss has a subordinate
SELECT boss.boss_id, COUNT(*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
Poprzez uważne przemyślenie można wywnioskować, że COUNT(1)
jest tym samym co COUNT(*)
, niezależnie od rodzaju połączenia. / Align = "LEFT" / : COUNT(subordinate.boss_id)
, COUNT(subordinate.*)
Więc po prostu użyj jednej z następujących opcji:
-- count the subordinates that belongs to boss
SELECT boss.boss_id, COUNT(subordinate.boss_id)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
Działa na Postgresql, to jasne, że chcesz policz Kardynalność zestawu
-- count the subordinates that belongs to boss
SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
Inny sposób liczenia kardynalności zbioru, bardzo angielski-podobny (tylko nie rób kolumny o nazwie takiej samej jak nazwa tabeli) : http://www.sqlfiddle.com/#!1/98515/7
select boss.boss_name, count(subordinate)
from boss
left join subordinate on subordinate.boss_code = boss.boss_code
group by boss.boss_name
Nie możesz tego zrobić: http://www.sqlfiddle.com/#!1/98515/8
select boss.boss_name, count(subordinate.1)
from boss
left join subordinate on subordinate.boss_code = boss.boss_code
group by boss.boss_name
Możesz to zrobić, ale to daje zły wynik: http://www.sqlfiddle.com/#!1/98515/9
select boss.boss_name, count(1)
from boss
left join subordinate on subordinate.boss_code = boss.boss_code
group by boss.boss_name
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-06-06 14:34:01
Dwa z nich zawsze dają tę samą odpowiedź:
- COUNT (*) zlicza liczbę wierszy
- COUNT (1) zlicza również liczbę wierszy
Zakładając, że' pk
' jest kluczem podstawowym i że żadne NULL nie są dozwolone w wartościach, to
- COUNT (pk) zlicza również liczbę wierszy
Jeśli jednak 'pk
' nie jest ograniczone do nie null, to daje inną odpowiedź:
COUNT (possibly_null) liczy liczbę wiersze z wartościami innymi niż null w kolumnie
possibly_null
.COUNT (DISTINCT pk) zlicza również liczbę wierszy(ponieważ klucz podstawowy nie pozwala na duplikaty).
COUNT (DISTINCT possibly_null_or_dup) zlicza liczbę różnych wartości innych niż null w kolumnie
possibly_null_or_dup
.COUNT (DISTINCT possibly_duplicated) zlicza liczbę odrębnych (koniecznie nie-null) wartości w kolumnie
possibly_duplicated
, Gdy ta ma klauzulę NOT NULL na to.
Zwykle piszę COUNT(*)
; jest to oryginalna zalecana notacja dla SQL. Podobnie, z klauzulą EXISTS, Zwykle piszę WHERE EXISTS(SELECT * FROM ...)
, ponieważ była to oryginalna notacja polecająca. Nie powinno być żadnych korzyści dla alternatyw; optymalizator powinien przejrzeć bardziej niejasne notacje.
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
2010-04-26 01:30:15
Zależy to od typu bazy danych, z której korzystasz, a także od typu tabeli w niektórych przypadkach.
Na przykład, używając MySQL, count(*)
będzie szybko pod tabelą MyISAM, ale wolno pod InnoDB. Pod InnoDB należy stosować count(1)
lub count(pk)
.
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
2010-04-26 01:14:44
Zapytany I odpowiedział wcześniej...
Książki on line mówi "COUNT ( { [ [ ALL | DISTINCT ] expression ] | * } )
"
" 1 " jest wyrażeniem nie-null, więc jest takie samo jak COUNT(*)
.
Optymalizator rozpoznaje go jako trywialne więc daje ten sam plan. PK jest unikalne i nie-null (przynajmniej w SQL serverze) więc COUNT(PK)
= COUNT (*)
Jest to podobny Mit do EXISTS (SELECT * ...
lub EXISTS (SELECT 1 ...
I patrz ANSI 92 spec , sekcja 6.5, Zasady ogólne, przypadek 1
a) If COUNT(*) is specified, then the result is the cardinality
of T.
b) Otherwise, let TX be the single-column table that is the
result of applying the <value expression> to each row of T
and eliminating null values. If one or more null values are
eliminated, then a completion condition is raised: warning-
null value eliminated in set function.
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-05-23 12:18:26
Przynajmniej na Oracle wszystkie są takie same: http://www.oracledba.co.uk/tips/count_speed.htm
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
2010-04-26 01:15:08
Czuję, że wydajność charecteristics zmienia się z DBMS na DBMS. Wszystko zależy od sposobu, w jaki zdecydują się go wszczepić. Ponieważ pracowałem intensywnie na oracle, powiem z tej perspektywy.
COUNT (*) - pobiera cały wiersz do zestawu wyników przed przekazaniem do funkcji count, funkcja count zagreguje 1, jeśli wiersz nie jest null
COUNT (1) - nie pobierze żadnego wiersza, zamiast tego count jest wywoływany ze stałą wartością 1 dla każdego wiersza w tabeli, gdy where zapałki.
Count (PK) - PK w oracle jest indeksowane. Oznacza to, że Oracle musi odczytywać tylko indeks. Zwykle jeden wiersz w drzewie indeksu B+ jest wiele razy mniejszy niż rzeczywisty wiersz. Biorąc więc pod uwagę szybkość operacji IOPS na dysku, Oracle może pobrać wiele razy więcej wierszy z indeksu za pomocą pojedynczego transferu bloków w porównaniu do całego wiersza. Prowadzi to do większej przepustowości zapytania.
Z tego widać, że pierwsza liczba jest najwolniejsza, a ostatnia jest najszybsza w Oracle.
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
2010-04-26 03:45:36