2015-05-19 15 views
7

Ich habe eine einfache Tabelle mit einer einzelnen Spalte PRIMARY KEY namens ID, Typ serial. Dort sind genau 100.000.000 Zeilen drin. Tabelle benötigt 48 GB, PK-Index ca. 2,1 GB. Die Maschine läuft nur für Postgres "dediziert" und es ist so etwas wie Core i5, 500 GB HDD, 8 GB RAM. Pg config wurde vom Dienstprogramm pgtune erstellt (shared buffer ca 2GB, effektiver Cache ca 7GB). OS ist Ubuntu Server 14.04, Postgres 9.3.6.Warum sind SELECT Count (PK) und SELECT count (*) so langsam?

Warum sind SELECT count(id) und SELECT count(*) so langsam in diesem einfachen Fall (cca 11 Minuten)?

Warum wählt der PostgreSQL-Planer den vollständigen Tabellenscan statt des Index-Scans, der mindestens 25-mal schneller sein sollte (in dem Fall, in dem er den gesamten Index von der Festplatte lesen müsste). Oder wo liege ich falsch?

Btw, die mehrmals hintereinander die Abfrage ausführt, ändert nichts. immer noch ca. 11 Minuten.

Ausführungsplan hier:

Aggregate (cost=7500001.00..7500001.01 rows=1 width=0) (actual time=698316.978..698316.979 rows=1 loops=1) 
    Buffers: shared hit=192 read=6249809 
    -> Seq Scan on transaction (cost=0.00..7250001.00 rows=100000000 width=0) (actual time=0.009..680594.049 rows=100000001 loops=1) 
     Buffers: shared hit=192 read=6249809 
Total runtime: 698317.044 ms 
+0

Datenmenge ist 25x kleiner zu lesen und enthält alle Schlüssel, die zu zählen, genügt nicht/nicht wahr? Ich habe sowohl VACUUM FULL als auch ANALYZE laufen lassen (was übrigens mehr als 6 Stunden zusammen genommen hat). – Kousalik

+0

Haben Sie eine Menge gleichzeitige DML auf diesem Tisch passiert? Der Index kann (und wird) nur verwendet werden, wenn er zuverlässig ist. Wenn es viele gleichzeitige Transaktionen (oder nicht abgeschlossene Transaktionen) gibt, wählt Postgres möglicherweise nicht den Index. Haben Sie eine und "Leerlauf in Transaktion" Verbindungen, die diese Tabelle geändert haben? Auch was ist der Wert von 'random_page_cost' (http://www.postgresql.org/docs/current/static/runtime-config-query.html#GUC-RANDOM-PAGE-COST) diese Einstellung wird die Tendenz des Planers beeinflussen Verwende einen Index. –

+0

Sie könnten auch das lesen: https://wiki.postgresql.org/wiki/Index-only_scans –

Antwort

8

die Spezifikation eines HDD In Anbetracht ist in der Regel irgendwo zwischen 50 Mb/s und 100 Mbit/s dann für 48 GB würde ich erwarten, dass alles zwischen 500 und 1000 zu lesen.

Da Sie keine WHERE-Klausel haben, sieht der Planer, dass Sie an der großen Mehrheit der Datensätze interessiert sind. Daher wird der Index nicht verwendet, da dies zusätzliche Indizes erfordern würde. Der Grund, warum postgresql den Index nicht verwenden kann, liegt in der MVCC, die postgresql für die Transaktionskonsistenz verwendet. Dies erfordert, dass die Zeilen gezogen werden, um genaue Ergebnisse zu gewährleisten. (siehe https://wiki.postgresql.org/wiki/Slow_Counting)

Der Cache, die CPU usw. beeinflussen dies nicht, noch ändern sich die Caching-Einstellungen. Dies ist IO-gebunden und der Cache wird nach der Abfrage vollständig gelöscht.

Wenn Sie mit einer Annäherung leben können Sie das reltuples Feld in der Tabelle Metadaten verwenden können:

SELECT reltuples FROM pg_class WHERE relname = 'tbl'; 

Da dies nur eine einzige Reihe ist dies schnell bahnt.

Update: seit 9.2 eine neue Möglichkeit zum Speichern der Sichtbarkeitsinformationen erlaubt Index-Only zählt zu passieren. Es gibt jedoch einige Vorbehalte, insbesondere in dem Fall, in dem es kein Prädikat gibt, um die Zeilen zu begrenzen. Weitere Informationen finden Sie unter https://wiki.postgresql.org/wiki/Index-only_scans.

+0

Nun, wenn ich Zahlen IDs wollen, dann Scannen nur Index sollte ausreichen und wäre groß zu gewinnen, weil viel kleiner ist. Die durchschnittliche Lesegeschwindigkeit beträgt fast 100 MB/s beim sequentiellen Lesen. Die Sache, die ich nicht verstehe, ist, warum der Planer nicht herausfindet, dass ich nur indexierten Wert zählen möchte. Ich kann das gleiche jetzt nicht testen, aber ich bin mir ziemlich sicher, dass Oracle es herausfinden würde. Werde morgen mit Oracle versuchen. – Kousalik

+0

Sah hinein.Dies ist wegen des MVCC-Systems, das postgres verwendet, nicht möglich. Um genaue Zählungen zu erhalten, muss die Tabelle gescannt werden. Andere Datenbanken, die verschiedene Nebenläufigkeitskontrollen verwenden, können dies ermöglichen. Ich aktualisiere meine Antwort. –

+0

Bitte auch Quelle angeben. Danke. – Kousalik