Das Zählen von Zeilen in großen Tabellen ist in PostgreSQL bekanntermaßen langsam. Um eine genaue Zahl zu erhalten, muss aufgrund der Art von MVCC eine vollständige Anzahl von Zeilen durchgeführt werden . Es gibt einen Weg , um diese dramatisch zu beschleunigen , wenn die Zählung nicht nicht sein muß genau wie es in Ihrem Fall zu sein scheint.
Anstatt die genaue Anzahl zu erhalten ( langsam bei großen Tischen):
SELECT count(*) AS exact_count FROM myschema.mytable;
Sie erhalten eine genaue Schätzung wie diese ( extrem schnell ):
SELECT reltuples::bigint AS estimate FROM pg_class where relname='mytable';
Wie nah die Schätzung ist, hängt davon ab, ob Sie ANALYZE
genug laufen . Es ist normalerweise sehr nah.
Siehe die FAQ zum PostgreSQL-Wiki .
Oder die spezielle Wiki-Seite für die Leistung von count (*) .
Besser noch
Der Artikel in dem PostgreSQL - Wiki ist war ein bisschen schlampig . Die Möglichkeit, dass mehrere Tabellen mit demselben Namen in einer Datenbank vorhanden sein können, wurde ignoriert - in verschiedenen Schemata. Um das zu erklären:
SELECT c.reltuples::bigint AS estimate
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = 'mytable'
AND n.nspname = 'myschema'
Oder noch besser
SELECT reltuples::bigint AS estimate
FROM pg_class
WHERE oid = 'myschema.mytable'::regclass;
Schneller, einfacher, sicherer, eleganter. Siehe das Handbuch zu Objektkennungstypen .
Verwenden Sie diese to_regclass('myschema.mytable')
Option in Postgres 9.4+, um Ausnahmen für ungültige Tabellennamen zu vermeiden:
SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);
Wie @a_horse kommentiert , kann die neu hinzugefügte Klausel für den SELECT
Befehl nützlich sein, wenn die Statistiken in pg_class
aus irgendeinem Grund nicht aktuell genug sind. Beispielsweise:
- Kein
autovacuum
Laufen.
- Sofort nach einem großen
INSERT
oder DELETE
.
TEMPORARY
Tabellen (die nicht abgedeckt sind von autovacuum
).
Dies betrachtet nur eine zufällige Auswahl von n % ( 1
im Beispiel) von Blöcken und zählt die darin enthaltenen Zeilen. Eine größere Stichprobe erhöht die Kosten und reduziert den Fehler, Ihre Wahl. Die Genauigkeit hängt von weiteren Faktoren ab:
- Verteilung der Zeilengröße. Wenn ein bestimmter Block breitere Zeilen als üblich enthält, ist die Anzahl niedriger als üblich usw.
- Tote Tupel oder ein
FILLFACTOR
Platz pro Block belegen. Bei ungleichmäßiger Verteilung auf die Tabelle ist die Schätzung möglicherweise nicht korrekt.
- Allgemeine Rundungsfehler.
In den meisten Fällen ist die Schätzung von pg_class
schneller und genauer.
Antwort auf die eigentliche Frage
Zuerst muss ich die Anzahl der Zeilen in dieser Tabelle kennen, wenn die Gesamtzahl größer als eine vordefinierte Konstante ist.
Und ob es ...
... ist in dem Moment möglich, in dem die Zählung meinen konstanten Wert überschreitet, stoppt sie die Zählung (und wartet nicht, bis die Zählung beendet ist, um mitzuteilen, dass die Zeilenanzahl größer ist).
Ja. Sie können eine Unterabfrage verwenden mitLIMIT
:
SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;
Postgres hört tatsächlich auf, über den angegebenen Grenzwert hinaus zu zählen. Sie erhalten eine genaue und aktuelle Zählung für bis zu n Zeilen (im Beispiel 500000) und ansonsten n . Nicht annähernd so schnell wie die Schätzung in pg_class
.