Wie halte ich eine hohe INSERT-Leistung unter PostgreSQL aufrecht?


9

Ich arbeite an einem Projekt, bei dem Daten aus Messdateien in eine Posgres 9.3.5-Datenbank analysiert werden.

Im Kern befindet sich eine Tabelle (unterteilt nach Monat), die für jeden Messpunkt eine Zeile enthält:

CREATE TABLE "tblReadings2013-10-01"
(
-- Inherited from table "tblReadings_master":  "sessionID" integer NOT NULL,
-- Inherited from table "tblReadings_master":  "fieldSerialID" integer NOT NULL,
-- Inherited from table "tblReadings_master":  "timeStamp" timestamp without time zone NOT NULL,
-- Inherited from table "tblReadings_master":  value double precision NOT NULL,
  CONSTRAINT "tblReadings2013-10-01_readingPK" PRIMARY KEY ("sessionID", "fieldSerialID", "timeStamp"),
  CONSTRAINT "tblReadings2013-10-01_fieldSerialFK" FOREIGN KEY ("fieldSerialID")
      REFERENCES "tblFields" ("fieldSerial") MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE RESTRICT,
  CONSTRAINT "tblReadings2013-10-01_sessionFK" FOREIGN KEY ("sessionID")
  REFERENCES "tblSessions" ("sessionID") MATCH SIMPLE
  ON UPDATE CASCADE ON DELETE RESTRICT,
  CONSTRAINT "tblReadings2013-10-01_timeStamp_check" CHECK ("timeStamp" >= '2013-10-01 00:00:00'::timestamp without time zone AND "timeStamp" < '2013-11-01 00:00:00'::timestamp without time zone)
)

Wir sind dabei, die Tabelle mit Daten zu füllen, die bereits gesammelt wurden. Jede Datei repräsentiert eine Transaktion von rund 48.000 Punkten und es gibt mehrere tausend Dateien. Sie werden mit einem importiertINSERT INTO "tblReadings_master" VALUES (?,?,?,?);

Anfänglich werden die Dateien mit einer Geschwindigkeit von mehr als 1000 Einfügungen / Sek. Importiert, aber nach einer Weile (eine inkonsistente Menge, aber niemals länger als 30 Minuten oder so) sinkt diese Rate auf 10-40 Einfügungen / Sek. Und der Postgres-Prozess schaltet eine CPU. Die einzige Möglichkeit, die ursprünglichen Raten wiederherzustellen, besteht darin, ein vollständiges Vakuum durchzuführen und zu analysieren. Dadurch werden letztendlich etwa 1.000.000.000 Zeilen pro Monatstabelle gespeichert, sodass das Vakuum einige Zeit in Anspruch nimmt.

BEARBEITEN: Hier ist ein Beispiel, in dem es einige Zeit für kleinere Dateien ausgeführt wurde und nach dem Start größerer Dateien fehlgeschlagen ist. Die größeren Dateien sehen unberechenbarer aus, aber ich denke, das liegt daran, dass die Transaktion erst am Ende einer Datei festgeschrieben wird, etwa 40 Sekunden. CPU und Insert Trace des Problems

Es wird ein Web-Frontend geben, das einige Elemente auswählt, aber keine Aktualisierungen oder Löschungen vornimmt. Dies wird ohne andere aktive Verbindungen angezeigt.

Meine Fragen sind:

  1. Wie können wir feststellen, was die Verlangsamung / Schiene der CPU verursacht (dies ist unter Windows)?
  2. Was können wir tun, um die ursprüngliche Leistung aufrechtzuerhalten?

Die Transaktions- / Dateigröße kann wichtig sein. Es durchläuft derzeit eine Reihe von Dateien mit rund 4000 INSERT's und importiert diese bisher erfolgreich für 1 Stunde 30 Minuten.
Jamesmc86

Ich bin auch kein Postgres-Experte, aber wenn dies mit MySQL auftauchen würde, würde ich ein paar Dinge ausprobieren: Sehen Sie, ob es von Zeit zu Zeit hilfreich wäre, sich zu verpflichten. Überprüfen Sie, ob es eine bessere Möglichkeit gibt, Daten aus Dateien zu laden (in MySQL gibt es eine LOAD DATA INFILE). Möglicherweise wird die Verlangsamung durch die Indexpopulation / -organisation nach jeder Einfügung verursacht. Überprüfen Sie, ob Sie mit Ihren Daten einige (oder alle) Indizes und INSERTalles deaktivieren und dann die Indizes reaktivieren können. Ich denke nicht, dass es wirklich helfen könnte, aber das Sperren des Tisches könnte eine andere Option sein.
wässrig

"Vollvakuum" ist nicht eindeutig. VACUUM FULLDies kann sich auf eine bestimmte Tabelle oder einfach VACUUMauf die gesamte Datenbank oder VACUUM FULLauf die gesamte Datenbank beziehen . Auf jeden Fall ist die Tatsache, dass es bei der Leistung hilft, verdächtig. VACUUM stellt tote Zeilen zurück, die sich aus UPDATEs und DELETEs ergeben. In einem Nur-INSERT-Szenario wird dies nicht benötigt.
Daniel Vérité

1
Es war ein VAKUUM VOLL, das wir machten. Mit Hilfe der Jungs auf dem IRC-Kanal ist es ziemlich wahrscheinlich, dass das Problem darin besteht, dass der Index fragmentiert wird
jamesmc86

Antworten:


6

Es gibt einige Dinge, die dieses Problem verursachen könnten, aber ich kann nicht sicher sein, ob eines davon das eigentliche Problem ist. Die Fehlerbehebung umfasst das Aktivieren der zusätzlichen Protokollierung in der Datenbank und das Überprüfen, ob die langsamen Teile mit den dortigen Nachrichten übereinstimmen. Stellen Sie sicher, dass Sie einen Zeitstempel in die Einstellung log_line_prefix einfügen, damit nützliche Protokolle angezeigt werden können. Weitere Informationen finden Sie in meinem Tuning-Intro: https://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server

Postgres schreibt alle Schreibvorgänge in den Betriebssystem-Cache und später auf die Festplatte. Sie können dies beobachten, indem Sie log_checkpoints aktivieren und die Nachrichten lesen. Wenn die Dinge langsamer werden, kann es einfach sein, dass alle Caches jetzt voll sind und alle Schreibvorgänge stecken bleiben und auf den langsamsten Teil der E / A warten. Sie können dies verbessern, indem Sie die Postgres-Prüfpunkteinstellungen ändern.

Es gibt ein internes Problem mit der Datenbank, auf das manchmal Leute stoßen, wenn schwere Einfügungen hängen bleiben und auf eine Sperre in der Datenbank warten. Aktivieren Sie log_lock_waits, um zu sehen, ob Sie diesen treffen.

Manchmal ist die Rate, mit der Sie Burst-Einfügungen ausführen können, höher als die, die Sie aufrechterhalten können, sobald der Autovakuum-Prozess des Systems beginnt. Aktivieren Sie log_autovacuum, um festzustellen, ob die Probleme gleichzeitig auftreten, wenn sie auftreten.

Wir wissen, dass eine große Menge an Speicher im privaten Cache für gemeinsam genutzte Puffer der Datenbank unter Windows nicht so gut funktioniert wie unter anderen Betriebssystemen. Es gibt auch nicht so viel Einblick in das, was schief geht, wenn es passiert. Ich würde nicht versuchen, etwas zu hosten, das 1000+ Einfügungen pro Sekunde in eine Windows PostgreSQL-Datenbank ausführt. Es ist einfach noch keine gute Plattform für wirklich schwere Schreibvorgänge.


0

Ich bin kein Postgres-Experte, daher könnte dies falsch sein! Ihr Primärschlüssel hat 3 Spalten, Sitzungs-ID als erstes Feld. Enthält die Datei eine anständige Verteilung von Zeitstempeln? Sie könnten in Betracht ziehen, das erste Feld im Primärschlüssel zu erstellen oder einen Ersatzschlüssel zu verwenden, da dieser derzeit ziemlich breit ist.

Nach Ihrem Skript glaube ich nicht, dass Sie einen Cluster haben. Anders als bei SQL Server, aber ich denke, Sie müssen die physische Reihenfolge der Tabelle in Postgres mit dem Befehl 'Cluster' angeben. Der Link spricht darüber:

/programming/4796548/about-clustered-index-in-postgres


Postgres hat keine Clustered-Indizes, daher ist die "ziemlich breite" für die PK kein wirkliches Problem, wie dies bei SQL Server der Fall wäre.
a_horse_with_no_name

Vielen Dank für Ihre Antwort, keine dieser Spalten ist einzeln einzigartig, weshalb wir es auf diese Weise gemacht haben
jamesmc86
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.