Ich muss die Anzahl der Zeilen in einer Tabelle kennen, um einen Prozentsatz zu berechnen. Wenn die Gesamtzahl größer als eine vordefinierte Konstante ist, verwende ich den Konstantenwert. Ansonsten werde ich die tatsächliche Anzahl der Zeilen verwenden.
Ich kann verwenden SELECT count(*) FROM table
. Wenn mein konstanter Wert jedoch 500.000 beträgt und ich 5.000.000.000 Zeilen in meiner Tabelle habe, wird das Zählen aller Zeilen viel Zeit verschwenden.
Kann ich aufhören zu zählen, sobald mein konstanter Wert überschritten wird?
Ich brauche die genaue Anzahl der Zeilen nur, solange sie unter dem angegebenen Grenzwert liegt. Andernfalls, wenn die Anzahl über dem Grenzwert liegt, verwende ich stattdessen den Grenzwert und möchte die Antwort so schnell wie möglich.
Etwas wie das:
SELECT text,count(*), percentual_calculus()
FROM token
GROUP BY text
ORDER BY count DESC;
quelle
Antworten:
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):
Sie erhalten eine genaue Schätzung wie diese ( extrem schnell ):
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
istwar 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:Oder noch besser
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:TABLESAMPLE SYSTEM (n)
in Postgres 9.5+Wie @a_horse kommentiert , kann die neu hinzugefügte Klausel für den
SELECT
Befehl nützlich sein, wenn die Statistiken inpg_class
aus irgendeinem Grund nicht aktuell genug sind. Beispielsweise:autovacuum
Laufen.INSERT
oderDELETE
.TEMPORARY
Tabellen (die nicht abgedeckt sind vonautovacuum
).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:FILLFACTOR
Platz pro Block belegen. Bei ungleichmäßiger Verteilung auf die Tabelle ist die Schätzung möglicherweise nicht korrekt.In den meisten Fällen ist die Schätzung von
pg_class
schneller und genauer.Antwort auf die eigentliche Frage
Und ob es ...
Ja. Sie können eine Unterabfrage verwenden mit
LIMIT
: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
.quelle
tablesample
Klausel verwendet wird: zBselect count(*) * 100 as cnt from mytable tablesample system (1);
SELECT count(*) FROM (Select * from (SELECT 1 FROM token) query) LIMIT 500000) limited_query;
(Ich frage, weil ich versuche, eine Zählung von einer willkürlichen Abfrage zu erhalten, die möglicherweise bereits eine Limit-Klausel enthält)ORDER BY something
wenn kein Index verwendet werden kann oder wenn Aggregatfunktionen verwendet werden). Abgesehen davon wird nur die begrenzte Anzahl von Zeilen aus der Unterabfrage verarbeitet.Ich habe dies einmal in einer Postgres-App gemacht, indem ich Folgendes ausgeführt habe:
Untersuchen Sie dann die Ausgabe mit einem regulären Ausdruck oder einer ähnlichen Logik. Für ein einfaches SELECT * sollte die erste Ausgabezeile ungefähr so aussehen:
Sie können den
rows=(\d+)
Wert als grobe Schätzung der Anzahl der zurückgegebenen Zeilen verwenden und dann nur dann die tatsächlicheSELECT COUNT(*)
Schätzung vornehmen, wenn die Schätzung beispielsweise weniger als das 1,5-fache Ihres Schwellenwerts beträgt (oder die Anzahl, die Sie für Ihre Anwendung für sinnvoll halten).Abhängig von der Komplexität Ihrer Abfrage wird diese Zahl möglicherweise immer ungenauer. Tatsächlich wurde es in meiner Anwendung, als wir Verknüpfungen und komplexe Bedingungen hinzufügten, so ungenau, dass es völlig wertlos war, selbst zu wissen, wie viele Zeilen wir innerhalb einer Potenz von 100 zurückgegeben hätten, sodass wir diese Strategie aufgeben mussten.
Wenn Ihre Abfrage jedoch so einfach ist, dass Pg innerhalb eines angemessenen Fehlerbereichs vorhersagen kann, wie viele Zeilen zurückgegeben werden, funktioniert sie möglicherweise für Sie.
quelle
Referenz aus diesem Blog.
Sie können unten nachfragen, um die Zeilenanzahl zu ermitteln.
Verwenden von pg_class:
Verwenden von pg_stat_user_tables:
quelle
In Oracle können Sie
rownum
die Anzahl der zurückgegebenen Zeilen begrenzen. Ich vermute, dass ein ähnliches Konstrukt auch in anderen SQLs existiert. In dem von Ihnen angegebenen Beispiel können Sie die Anzahl der zurückgegebenen Zeilen auf 500001 begrenzen undcount(*)
dann ein:quelle
count(*)
mit Rownum, 1 s ohne Rownum). Ja, esSELECT count(*) cnt FROM table
wird immer 1 Zeile zurückgegeben, aber mit der LIMIT-Bedingung wird "500001" zurückgegeben, wenn die Tabellengröße über 500000 liegt, und <Größe>, wenn die Tabellengröße <= 500000 ist.Wie breit ist die Textspalte?
Mit einem GROUP BY können Sie nicht viel tun, um einen Datenscan (zumindest einen Index-Scan) zu vermeiden.
Ich würde empfehlen:
Ändern Sie nach Möglichkeit das Schema, um doppelte Textdaten zu entfernen. Auf diese Weise erfolgt die Zählung in einem engen Fremdschlüsselfeld in der Tabelle "Viele".
Alternativ können Sie eine generierte Spalte mit einem HASH des Texts und dann GROUP BY mit der Hash-Spalte erstellen. Dies dient wiederum dazu, die Arbeitslast zu verringern (Durchsuchen eines engen Spaltenindex).
Bearbeiten:
Ihre ursprüngliche Frage stimmte nicht ganz mit Ihrer Bearbeitung überein. Ich bin mir nicht sicher, ob Sie wissen, dass COUNT bei Verwendung mit GROUP BY die Anzahl der Elemente pro Gruppe und nicht die Anzahl der Elemente in der gesamten Tabelle zurückgibt.
quelle
Sie können die Anzahl durch die folgende Abfrage erhalten (ohne * oder Spaltennamen).
quelle
count(*)
.Für SQL Server (2005 oder höher) ist eine schnelle und zuverlässige Methode:
Details zu sys.dm_db_partition_stats werden in MSDN erläutert
Die Abfrage fügt Zeilen aus allen Teilen einer (möglicherweise) partitionierten Tabelle hinzu.
index_id = 0 ist eine ungeordnete Tabelle (Heap) und index_id = 1 ist eine geordnete Tabelle (Clustered Index)
Hier werden noch schnellere (aber unzuverlässige) Methoden beschrieben .
quelle