it-swarm.com.de

COUNT (*) vs. COUNT (1) vs. COUNT (pk): Was ist besser?

Ich finde oft diese drei Varianten:

SELECT COUNT(*) FROM Foo;
SELECT COUNT(1) FROM Foo;
SELECT COUNT(PrimaryKey) FROM Foo;

Soweit ich sehen kann, tun sie alle dasselbe und ich verwende die drei in meiner Codebasis. Ich mag es jedoch nicht, dasselbe auf unterschiedliche Weise zu tun. An welche soll ich mich halten? Ist einer von ihnen besser als die beiden anderen?

210
zneak

Endeffekt

Verwenden Sie entweder COUNT(field) oder COUNT(*) und bleiben Sie dabei. Wenn Ihre Datenbank COUNT(tableHere) oder COUNT(tableHere.*) zulässt, verwenden Sie diese Option.

Kurz gesagt, verwenden Sie COUNT(1) für nichts. Es ist ein One-Trick-Pony, das nur selten das tut, was Sie wollen, und in diesen seltenen Fällen entspricht es count(*)

Verwenden Sie count(*) zum Zählen

Verwenden Sie * Für alle Ihre Abfragen, die alles zählen müssen, auch für Joins. Verwenden Sie *

SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Verwenden Sie COUNT(*) jedoch nicht für LEFT-Joins, da dies 1 zurückgibt, selbst wenn die untergeordnete Tabelle nicht mit der übergeordneten Tabelle übereinstimmt

SELECT boss.boss_id, COUNT(*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Lassen Sie sich nicht von denjenigen täuschen, die darauf hinweisen, dass bei Verwendung von * In COUNT die gesamte Zeile von Ihrer Tabelle abgerufen wird und dass * Langsam ist. Das * In SELECT COUNT(*) und SELECT * Haben keine Bedeutung, sie sind völlig verschieden, sie teilen nur ein gemeinsames Token, d. H. *.

Eine alternative Syntax

Tatsächlich könnte der RDBMS-Sprachdesigner COUNT(tableNameHere) die gleiche Semantik wie COUNT(*) zuweisen, wenn es nicht zulässig ist, ein Feld so zu benennen, wie es dem Tabellennamen entspricht. Beispiel:

Zum Zählen von Zeilen könnten wir folgendes haben:

SELECT COUNT(emp) FROM emp

Und sie könnten es einfacher machen:

SELECT COUNT() FROM emp

Und für LEFT JOINs könnten wir Folgendes haben:

SELECT boss.boss_id, COUNT(subordinate)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Dies ist jedoch nicht möglich (COUNT(tableNameHere)), da der SQL-Standard die Benennung eines Felds mit demselben Namen wie der Tabellenname zulässt:

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
)

Mit null zählen

Außerdem ist es nicht ratsam, ein Feld auf null zu setzen, wenn sein Name mit dem Tabellennamen übereinstimmt. Angenommen, Sie haben die Werte 'Banane', 'Apfel', NULL, 'Birnen' im Feld fruit. Dies zählt nicht alle Zeilen, es ergibt nur 3, nicht 4

SELECT count(fruit) FROM fruit

Obwohl einige RDBMS nach diesem Prinzip arbeiten (um die Zeilen der Tabelle zu zählen, akzeptiert sie den Tabellennamen als COUNT-Parameter), funktioniert dies in Postgresql (wenn in keiner der beiden folgenden Tabellen ein subordinate -Feld vorhanden ist, d. H solange kein Namenskonflikt zwischen Feldname und Tabellenname besteht):

SELECT boss.boss_id, COUNT(subordinate)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Dies könnte jedoch später zu Verwirrung führen, wenn wir ein subordinate -Feld in die Tabelle einfügen, da es das Feld (das nullwertfähig sein kann) und nicht die Tabellenzeilen zählt.

Um auf der sicheren Seite zu sein, verwenden Sie:

SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

count(1): Das Ein-Trick-Pony

Insbesondere für COUNT(1) ist es ein One-Trick-Pony , das nur bei einer Tabellenabfrage funktioniert:

SELECT COUNT(1) FROM tbl

Wenn Sie jedoch Joins verwenden, funktioniert dieser Trick nicht bei Abfragen mit mehreren Tabellen, ohne dass die Semantik verwirrt ist. Insbesondere können Sie nicht schreiben:

-- 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

Was bedeutet COUNT (1) hier?

SELECT boss.boss_id, COUNT(1)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id

Ist es das...?

-- 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

Oder dieses...?

-- 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

Durch sorgfältiges Überlegen können Sie schließen, dass COUNT(1) dasselbe wie COUNT(*) ist, unabhängig von der Art der Verknüpfung. Aber für das Ergebnis von LEFT JOINs können wir COUNT(1) nicht formen, um zu funktionieren als: COUNT(subordinate.boss_id), COUNT(subordinate.*)

Verwenden Sie einfach eine der folgenden Optionen:

-- 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

Funktioniert Postgresql, ist es klar, dass Sie die Kardinalität des Satzes zählen möchten

-- 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

Eine andere Möglichkeit, die Kardinalität der Menge zu zählen, ist sehr englisch (machen Sie einfach keine Spalte mit dem gleichen Namen wie der Tabellenname): 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

Dies ist nicht möglich: 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

Sie können dies tun, aber dies führt zu einem falschen Ergebnis: 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
210
Michael Buen

Zwei von ihnen geben immer die gleiche Antwort:

  • COUNT(*) zählt die Anzahl der Zeilen
  • COUNT(1) zählt auch die Anzahl der Zeilen

Angenommen, der pk ist ein Primärschlüssel und die Werte dürfen keine Nullen enthalten

  • COUNT(pk) zählt auch die Anzahl der Zeilen

Wenn jedoch pk nicht auf null beschränkt ist, wird eine andere Antwort ausgegeben:

  • COUNT(possibly_null) zählt die Anzahl der Zeilen mit Nicht-Null-Werten in der Spalte possibly_null.

  • COUNT(DISTINCT pk) zählt auch die Anzahl der Zeilen (da ein Primärschlüssel keine Duplikate zulässt).

  • COUNT(DISTINCT possibly_null_or_dup) zählt die Anzahl der verschiedenen Nicht-Null-Werte in der Spalte possibly_null_or_dup.

  • COUNT(DISTINCT possibly_duplicated) zählt die Anzahl unterschiedlicher (notwendigerweise nicht null) Werte in der Spalte possibly_duplicated, wenn diese die Klausel NOT NULL enthält.

Normalerweise schreibe ich COUNT(*); Es ist die ursprünglich empfohlene Notation für SQL. In ähnlicher Weise schreibe ich mit der EXISTS -Klausel normalerweise WHERE EXISTS(SELECT * FROM ...), da dies die ursprüngliche empfohlene Notation war. Es sollte keinen Nutzen für die Alternativen geben; Der Optimierer sollte die undurchsichtigeren Notationen durchschauen.

49

Dies hängt vom verwendeten Datenbanktyp sowie in einigen Fällen vom Tabellentyp ab.

Wenn Sie beispielsweise MySQL verwenden, ist count(*) unter einer MyISAM-Tabelle schnell, unter einer InnoDB jedoch langsam. Unter InnoDB sollten Sie count(1) oder count(pk) verwenden.

9
Jarod Elliott

Gefragt und beantwortet vor ...

Bücher online sagt "COUNT ( { [ [ ALL | DISTINCT ] expression ] | * } )"

"1" ist ein Nicht-Null-Ausdruck und entspricht daher COUNT(*). Der Optimierer erkennt es als trivial und gibt den gleichen Plan vor. Ein PK ist eindeutig und nicht null (mindestens in SQL Server), also COUNT(PK) = COUNT (*)

Dies ist ein ähnlicher Mythos wie EXISTS (SELECT * ... oder EXISTS (SELECT 1 ...

Siehe auch ANSI 92 spec , Abschnitt 6.5, Allgemeine Regeln, Fall 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.
6
gbn

Zumindest bei Oracle sind sie alle gleich: http://www.oracledba.co.uk/tips/count_speed.htm

5
ZeissS