Postgresql 9.4 Query wird beim Verbinden von TSTZRANGE mit && progressiv langsamer

8

Ich führe eine Abfrage aus, die beim Hinzufügen von Datensätzen immer langsamer wird. Datensätze werden kontinuierlich über einen automatisierten Prozess hinzugefügt (bash ruft psql auf). Ich möchte diesen Flaschenhals korrigieren. Ich weiß jedoch nicht, was meine beste Option ist.

Dies ist die Ausgabe von pgBadger:

%Vor%

Die Tabellenstruktur sieht folgendermaßen aus:

%Vor%

Die Tabelle "Parent" hat eine Eins-zu-viele-Beziehung mit der Tabelle "Foo" :

%Vor%

Die Tabelle "Foo" hat eine Eins-zu-viele-Beziehung mit der Tabelle "Bar" :

%Vor%

Außerdem darf die Tabelle "Bar" keine überlappenden "Timespan" -Werte für dieselbe "FooID" oder "ParentID" enthalten. Ich habe einen Trigger erstellt, der nach einem beliebigen INSERT ,% co_de ausgelöst wird %, oder UPDATE , die überlappende Bereiche verhindern.

Der Auslöser enthält einen Abschnitt , der ähnlich aussieht :

%Vor%

Die Ergebnisse von DELETE :

%Vor%

(**** Betonung meiner)

Dies scheint zu zeigen, dass 99% der Arbeit in der EXPLAIN ANALYSE von JOIN bis "cte" (via "Bar" ) ... gemacht wird, aber es verwendet bereits den entsprechenden Index ... es ist immer noch zu langsam.

So lief ich:

%Vor%

Ergebnisse:

%Vor%

Bietet ein Index dieser Größe (relativ zur Tabelle) viel Leseleistung? Ich dachte über eine sudo-Partition nach, bei der der Index durch mehrere Teilindizes ersetzt wird ... vielleicht hätten die Partialtöne weniger beizubehalten (und zu lesen) und die Leistung würde sich verbessern. Ich habe das noch nie gesehen, nur eine Idee. Wenn dies eine Option ist, kann ich mir keine gute Möglichkeit vorstellen, die Segmente zu begrenzen, da dies auf einem "Foo" -Wert liegen würde.

Ich denke auch, dass das Hinzufügen von TSTZRANGE zu "ParentID" die Dinge beschleunigen würde, aber ich möchte nicht denormalisieren.

Welche anderen Möglichkeiten habe ich?

Auswirkung der von Erwin Brandstetter empfohlenen Änderungen

Bei der Spitzenleistung (Stunde 18:00) fügte der Prozess 14,5 Datensätze pro Sekunde konsistent ... von 1,15 Datensätzen pro Sekunde hinzu.

Dies ist das Ergebnis von:

  1. Hinzufügen von "Bar" zur Tabelle "ParentID"
  2. Hinzufügen einer Fremdschlüsseleinschränkung zu "Bar"
  3. Hinzufügen von "Foo" ("ParentID", "FooID") (das Modul btree_gist ist bereits installiert)
losthorse 29.11.2015, 20:32
quelle

1 Antwort

2

Ausschlussbeschränkung

  

Außerdem darf die Tabelle "Bar" keine Überschneidung enthalten "Timespan"   Werte für den gleichen "FooID" oder "ParentID" . Ich habe einen Trigger erstellt   das nach jedem INSERT , UPDATE oder DELETE ausgelöst wird, das verhindert   überlappende Bereiche.

Ich schlage vor, dass Sie stattdessen eine Ausschlussbeschränkung verwenden, die viel einfacher, sicherer und schneller ist:

Sie müssen das zusätzliche Modul installieren btree_gist zuerst. Siehe Anweisungen und Erklärungen in dieser Antwort:

Und Sie müssen "ParentID" in die Tabelle "Bar" redundant einfügen, was ein kleiner Preis ist. Tabellendefinitionen könnten wie folgt aussehen:

%Vor%

Ich habe auch den Datentyp für "Bar"."FooID" von int8 in int4 geändert. Er verweist auf "Foo"."FooID" , was ein serial ist, d.h. int4 . Verwenden Sie den passenden Typ int4 (oder nur integer ) aus verschiedenen Gründen, z. B. Performance.

Sie benötigen keinen Trigger mehr (zumindest nicht für diese Aufgabe), und Sie erstellen den Index "Bar_FooID_Timerange_idx" nicht mehr, da er implizit durch die Ausschlussbedingung erstellt wird .

Ein btree-Index auf ("ParentID", "FooID") wird jedoch höchstwahrscheinlich nützlich sein:

%Vor%

Verwandte:

Ich habe UNIQUE ("ParentID", "FooID") gewählt und nicht aus einem anderen Grund, da es in beiden Tabellen einen anderen Index mit dem führenden "FooID" gibt:

Beiseite: Ich verwende niemals doppelt zitierte CaMeL-Case-Bezeichner < in Postgres. Ich mache es nur hier, um Ihrem Layout zu entsprechen.

Vermeiden Sie die redundante Spalte

Wenn Sie "Bar"."ParentID" nicht redundant hinzufügen können oder wollen, gibt es einen anderen Rogue Weg - unter der Bedingung, dass "Foo"."ParentID" nie aktualisiert ist. Stellen Sie das sicher, zum Beispiel mit einem Trigger.

Sie können eine Funktion IMMUTABLE fälschen:

%Vor%

Ich habe das Schema für den Tabellennamen qualifiziert, um sicherzustellen, dass public vorausgesetzt wird. Passen Sie sich Ihrem Schema an.

Mehr:

Dann verwenden Sie es in der Ausschlussbedingung:

%Vor%

Beim Speichern einer redundanten Spalte int4 wird die Einschränkung teurer und die gesamte Lösung hängt von mehr Vorbedingungen ab.

Behandle Konflikte

Sie könnten INSERT und UPDATE in eine plpgsql-Funktion einschließen und mögliche Ausnahmen von der Ausschlussbeschränkung ( 23P01 exclusion_violation ) auffangen, um sie irgendwie zu handhaben.

%Vor%

Komplettes Codebeispiel:

Behandeln Konflikt in Postgres 9.5

In Postgres 9.5 können Sie INSERT direkt mit der neuen "UPSERT" -Implementierung verarbeiten. Die Dokumentation:

  

Die optionale ON CONFLICT -Klausel gibt eine alternative Aktion an   einen eindeutigen Verletzung- oder Ausschlussbedingungsverletzungsfehler auslösen.   Für jede einzelne Zeile zum Einfügen vorgeschlagen, entweder die Einfügung   oder, wenn ein Arbiter Constraint oder Index von angegeben wird    conflict_target ist verletzt, die Alternative conflict_action ist   genommen. ON CONFLICT DO NOTHING vermeidet einfach das Einfügen einer Zeile als deren   alternative Aktion. ON CONFLICT DO UPDATE aktualisiert die vorhandene Zeile   das steht im Widerspruch zu der Zeile, die als alternative Aktion eingefügt werden soll.

Allerdings:

  

Beachten Sie, dass Ausschlussbedingungen in ON CONFLICT DO UPDATE nicht unterstützt werden.

Sie können jedoch weiterhin ON CONFLICT DO NOTHING verwenden, wodurch mögliche exclusion_violation -Ausnahmen vermieden werden.Prüfen Sie, ob Zeilen tatsächlich aktualisiert wurden, was günstiger ist:

%Vor%

In diesem Beispiel wird die Überprüfung auf die angegebene Ausschlussbedingung beschränkt. (Ich habe die Einschränkung explizit für diesen Zweck in der obigen Tabellendefinition benannt.) Andere mögliche Ausnahmen werden nicht abgefangen.

    
Erwin Brandstetter 30.11.2015, 02:48
quelle