Postgres: count (*) vs count (id)

11

Ich habe in der Dokumentation den Unterschied zwischen count(*)und gesehen count(pk). Ich hatte count(pk)(wo pkist a SERIAL PRIMARY KEY) verwendet, ohne über die Existenz von zu wissen count(*).

Meine Frage betrifft die internen Optimierungen von Postgres. Ist es klug genug zu erkennen, dass a SERIAL PRIMARY KEYin jeder Zeile existieren wird und niemals falsch ist und nur Zeilen zählt, oder wird es redundante Prädikatprüfungen für jede Zeile durchführen? Ich stimme zu, dass dies wahrscheinlich eine zu sinnlose Optimierung ist, aber ich bin nur neugierig.

Ich nahm einen Blick auf die Ausgabe von EXPLAINund EXPLAIN VERBOSEfür count(*), count(id)und count(id > 50)zu sehen , ob EXPLAINerwähnt die Prädikate in seiner Ausgabe zu überprüfen. Das tut es nicht.

ldrg
quelle

Antworten:

15

Ich habe in meinen wiederholten Tests mit verschiedenen Versionen in den letzten Jahren konsistente Ergebnisse erzielt:
count(*)ist etwas schneller als count(pk). Es ist auch kürzer und passt meistens besser zu dem, was getestet wird: der Existenz einer Reihe.

Über:

Ist Postgres klug genug, um zu erkennen, dass SERIAL PRIMARY KEYin jeder Zeile ein a existieren wird und niemals falsch sein wird?

Das einzig Relevante ist die NOT NULLEinschränkung. Das PRIMARY KEYist NOT NULLautomatisch serialoder never falseorthogonal zur Frage.

Mit count(col) , wenn PostgreSQL , intelligent zu sein versucht , und den Systemkatalog überprüfen , ob eine Spalte war NOT NULLund fällt zurück in einem äquivalenten count(*), würden Sie noch eine weitere Nachschau haben auf einer Systemtabelle als mit count(*).

Bezüglich der EXPLAINAusgabe gibt es einen Hinweis:

EXPLAIN SELECT count(*) FROM ...

Aggregate  (cost=4963.38..4963.43 rows=1 width=0) ...


EXPLAIN SELECT count(pk) FROM ...

Aggregate  (cost=4963.38..4963.43 rows=1 width=4) ...

Das heißt, count(col)wird nicht konvertiert count(*), auch wenn es definiert ist NOT NULL.

Erwin Brandstetter
quelle
Ist dies bei den neuen Versionen immer noch der Fall? Ich denke, es würde nicht wirklich eine Suche für jede Abfrage brauchen - es könnte zwischengespeichert werden.
Ondra Žižka
1
Übrigens, mit einer NOT NULLSpalte ist der Unterschied groß, wenn Sie viele Zeilen haben. In unserem Fall mit Millionen von Zeilen COUNT(*)ist das dreimal schneller. (Postgres 9.4)
Ondra Žižka