Leistungsprobleme mit geerbten Tabellen und Indizes

7

Ich habe eine PostgreSQL-Datenbank mit einer Mastertabelle und 2 untergeordneten Tabellen. Mein Mastertisch:

CREATE TABLE test (
    id serial PRIMARY KEY, 
    date timestamp without time zone
);
CREATE INDEX ON test(date);

Meine Kindertische:

CREATE TABLE test_20150812 (
    CHECK ( date >= DATE '2015-08-12' AND date < DATE '2015-08-13' )
) INHERITS (test);

CREATE TABLE test_20150811 (
    CHECK ( date >= DATE '2015-08-11' AND date < DATE '2015-08-12' )
) INHERITS (test);

CREATE INDEX ON test_20150812(date);
CREATE INDEX ON test_20150811(date);

Wenn ich eine Abfrage wie folgt ausführe:

select * from test_20150812 where date > '2015-08-12' order by date desc;

Es kehrt sehr schnell zurück (20-30 Millisekunden). EXPLAINAusgabe:

 Limit  (cost=0.00..2.69 rows=50 width=212)
   ->  Index Scan Backward using test_20150812_date_idx on test_20150812  (cost=0.00..149538.92 rows=2782286 width=212)
         Index Cond: (date > '2015-08-12 00:00:00'::timestamp without time zone)

Wenn ich jedoch eine Abfrage wie folgt ausführe:

select * from test where date > '2015-08-12' order by date desc;

Es dauert lange (10-15 Sekunden). EXPLAINAusgabe:

 Limit  (cost=196687.06..196687.19 rows=50 width=212)
   ->  Sort  (cost=196687.06..203617.51 rows=2772180 width=212)
         Sort Key: public.test.date
         ->  Result  (cost=0.00..104597.24 rows=2772180 width=212)
               ->  Append  (cost=0.00..104597.24 rows=2772180 width=212)
                     ->  Seq Scan on test  (cost=0.00..0.00 rows=1 width=1857)
                           Filter: (date > '2015-08-12 00:00:00'::timestamp without time zone)
                     ->  Seq Scan on test_20150812 test  (cost=0.00..104597.24 rows=2772179 width=212)
                           Filter: (date > '2015-08-12 00:00:00'::timestamp without time zone)

constraint_exclusionist ONin meinem eingestellt postgresql.conf. Daher sollte es nur am ausgeführt werden test_20150812.

Ich sehe, dass, wenn eine Abfrage für die Mastertabelle ausgeführt wird, niemals Indizes verwendet werden. Wie kann ich es verbessern? Ich möchte alle meine Abfragen in meiner Haupttabelle stellen. Bei der Abfrage nach einem bestimmten Datum erwarte ich keinen Leistungsunterschied zwischen der Abfrage in der Mastertabelle oder der untergeordneten Tabelle.

umut
quelle
@ypercube ja. Ich versuchte es. Das Ergebnis war das gleiche.
Umut
@ypercube Ergebnis war leider gleich. Es dauert immer noch 10-15 Sekunden.
Umut
1
Ich habe mir erlaubt, inkonsistente Tabellennamen ( test_20150812vs. test_table_20150812) zugunsten von Kurznamen aufzulösen . Sie haben vergessen, Ihre Version von Postgres anzugeben, und geben Sie EXPLAIN (ANALYZE, BUFFERS)nicht nur die Ausgabe von an EXPLAIN. Auch seltsam: Seq Scan on test_table_20150812 test_table(jetzt vereinfacht test_20150812 test) ist nicht gültig erklären Ausgabe ...
Erwin Brandstetter
1
pg 9.0 ist mittlerweile sehr alt und erreicht nächsten Monat (Sept. 2015) EOL . Erwägen Sie ernsthaft ein Upgrade auf eine aktuelle Version. Aktuelle Versionen haben viele Leistungsverbesserungen gegenüber dieser alten Version. Während Sie mit Ihrer veralteten Version nicht weiterkommen, sollten Sie mindestens auf die neueste Version (derzeit 9.0.22) aktualisieren, um Fehler zu beheben.
Erwin Brandstetter
1
Ich habe spätere Änderungen rückgängig gemacht
Erwin Brandstetter

Antworten:

12

"Datum"

Nennen Sie Ihre timestampSpalte nicht "Datum" , das ist sehr irreführend. Besser noch, verwenden Sie den Basistypnamen "Datum" überhaupt nicht als Bezeichner. Dies ist fehleranfällig, führt zu verwirrenden Fehlermeldungen und ist ein reserviertes Wort in Standard-SQL . Sollte so etwas sein wie:

CREATE TABLE test (
  id serial PRIMARY KEY
, ts timestamp NOT NULL  -- also adding NOT NULL constraint
);
CREATE INDEX ON test(ts);

Vorsichtsmaßnahmen

Beachten Sie diese Einschränkung mit Ausschluss von Einschränkungen :

Der Ausschluss von Einschränkungen funktioniert nur, wenn die WHEREKlausel der Abfrage Konstanten (oder extern bereitgestellte Parameter) enthält . Beispielsweise kann ein Vergleich mit einer nicht unveränderlichen Funktion, wie CURRENT_TIMESTAMP sie nicht optimiert werden kann, da der Planer nicht wissen kann, in welche Partition der Funktionswert zur Laufzeit fallen könnte.

Mutige Epmhasis Mine. Sie sind diesem ausgewichen , aber mit Ihrem verwirrenden Setup könnten Sie früh genug darüber stolpern.

Da Sie tägliche Partitionen haben:

Alle Einschränkungen für alle Partitionen der Mastertabelle werden beim Ausschluss von Einschränkungen untersucht, sodass eine große Anzahl von Partitionen die Planungszeit für Abfragen wahrscheinlich erheblich verlängert. Das Partitionieren mit diesen Techniken funktioniert gut mit bis zu hundert Partitionen. Versuchen Sie nicht, viele tausend Partitionen zu verwenden.

Meine kühne Betonung. Wenn Sie mehr als ein paar Monate umfassen, versuchen Sie stattdessen wöchentliche oder monatliche Partitionen.

Nichtübereinstimmung in Prädikaten

Ihre Prüfbedingung:

CHECK ( date >= DATE '2015-08-12' AND date < DATE '2015-08-13' )

Aber Ihre Anfrage hat die Bedingung:

where date > '2015-08-12' order by date desc;  -- should be: >=

Dies führt zu einer leichten Nichtübereinstimmung (wahrscheinlich falsch !) Und zwingt Postgres, den Zustand erneut zu überprüfen. Nicht gut, kann aber auch Ihre Frage nicht beantworten.

Verwenden Sie >=und machen Sie entweder die Spalte NOT NULLoder hängen Sie NULLS LASTan die Anweisung:

WHERE ts >= '2015-08-12' ORDER BY ts DESC;

... und den Index übereinstimmen lassen.

Unreine CHECKEinschränkung

Die CHECKEinschränkungen werden mit dateKonstanten anstelle von timestampKonstanten gespeichert . Sollte so etwas sein wie:

CHECK (ts >= timestamp '2015-08-11' AND ts < timestamp '2015-08-12');

Ausschluss von Einschränkungen

Du schreibst:

constraint_exclusionist ONin meinem eingestellt postgresql.conf. Daher sollte es nur am ausgeführt werden test_20150812.

Wie Sie im Abfrageplan sehen können, werden nur testund test_20150812gescannt, aber nicht test_20150811. Ergo: Der Ausschluss von Einschränkungen funktioniert trotz aller Abweichungen einwandfrei. Das ist nur ein weiterer falscher Weg.

Gewann viele Schlachten, aber nicht den Krieg

Nachdem ich das alles bereinigt habe, sehe ich einen Bitmap-Index-Scan für die untergeordnete Tabelle anstelle Ihres seq-Scans. Immer noch langsamer als eine Abfrage nur für die untergeordnete Tabelle. Dies liegt offensichtlich daran, dass die übergeordnete Tabelle selbst auch übereinstimmende Zeilen enthalten kann, die mit dem Rest sortiert werden müssen, sodass das Ergebnis nicht einfach aus dem Index gelesen werden kann.

Erwin Brandstetter
quelle
Vielen Dank, dass Sie @Erwin geholfen haben. Ich wende diese Änderungen an und bearbeite meine Frage. Können Sie mir bei meinem neuen Problem helfen?
Umut
@umut: Bitte setzen Sie die neue Ausgabe in eine neue Frage . Dieser ist bereits überlastet. Sie können jederzeit einen Link zu diesem für den Kontext erstellen. (Vielleicht brauchen Sie nur VACUUM ANALYZEIhre Tische.)
Erwin Brandstetter
Ich schreibe eine neue Frage: dba.stackexchange.com/questions/111022/…
umut