Wie finde ich heraus, wie weit meine PostgreSQL-Abfrage entfernt ist?

35

Ich habe eine ziemlich gute Vorstellung davon, wie viele Zeilen meine SELECT ... INTO-Abfrage tatsächlich verarbeiten wird (z. B. weiß ich, wie viele auftreten werden).

Ich verstehe, dass Postgres mir keine prozentuale Vollständigkeit sagt. Gibt es eine Möglichkeit (tief in Protokollen, Systemtabellen oder auf andere Weise vergraben), mit der ich herausfinden kann, wie viele Zeilen in die Zieltabelle gepumpt oder von der SELECT-Abfrage gelesen wurden? ?

Mark Elliot
quelle

Antworten:

33

Wie Daniel Vérité sagte, scheint es keine generische Lösung zu geben. Beim Laden von Daten aus einer Datei in eine Tabelle kann die folgende Technik verwendet werden, um den Fortschritt des Ladens zu ermitteln.

Fortschrittsanzeige der COPY-Befehlskonsole

Erstellen Sie eine leere Tabelle.

CREATE TABLE mytest (n int);

Erstellen Sie eine Datendatei mit 10 Millionen Zeilen zum Laden in die Tabelle.

$ seq 10000000 > /tmp/data.txt

Laden Sie Daten aus einer Datei in die Tabelle und zeigen Sie einen Fortschrittsbalken an.

$ pv /tmp/data.txt | psql -c "COPY mytest FROM STDIN;"

Demo

Bildbeschreibung hier eingeben

Wie das geht

Mit dem Kopierbefehl STDIN können wir die Daten für den Kopiervorgang aus einem anderen Prozess einspeisen. Der Befehl pv gibt eine Datei aus und verfolgt deren Fortschritt. Er zeigt einen Fortschrittsbalken, die ETA, die verstrichene Gesamtzeit und die Datenübertragungsrate an.

Grafische Fortschrittsanzeige für den Befehl KOPIEREN

Mit derselben allgemeinen Technik könnten wir einen Fortschrittsbalken in einer grafischen Anwendung oder einer webbasierten Anwendung anzeigen. Wenn Sie beispielsweise Python verwenden, können Sie mit dem Modul psycopg2 den Befehl copy mit einem Dateiobjekt Ihrer Wahl aufrufen. Sie können dann verfolgen, wie viel von Ihrem Dateiobjekt gelesen wurde, und eine Fortschrittsanzeige anzeigen.

Marwan Alsabbagh
quelle
2
Ich bin noch nie auf den pvBefehl gestoßen und er war nicht standardmäßig auf meinem Debian-Server installiert, aber er befindet sich im Repo. In der Beschreibung heißt es: "pv (Pipe Viewer) kann in jede normale Pipeline zwischen zwei Prozessen eingefügt werden, um visuell anzuzeigen, wie schnell Daten übertragen werden." Ein sehr nützlicher Befehl!
Richard Turner
27

Es scheint keine generische, unterstützte Methode zu geben, aber es gibt einige Tricks, die in begrenzten Kontexten verwendet werden können, um den Fortschritt einer einzelnen Abfrage zu bewerten. Hier sind einige davon.

Sequenzen

Wenn eine SELECT- oder UPDATE-Abfrage eine beliebige enthält nextval(sequence_name)oder ein INSERT eine Zielspalte mit einem nextvalals Standard enthält, kann der aktuelle Sequenzwert in einer anderen Sitzung mit wiederholt abgefragt werden SELECT sequence_name.last_value. Das funktioniert, weil Sequenzen nicht an Transaktionen gebunden sind. Wenn der Ausführungsplan so ist, dass die Sequenz während der Abfrage linear inkrementiert wird, kann er als Fortschrittsanzeige verwendet werden.

pgstattuple

Das Modul pgstattuple contrib bietet Funktionen, die einen direkten Blick auf die Datenseiten werfen können. Es scheint, dass Tupel, die in eine leere Tabelle eingefügt und noch nicht festgeschrieben wurden, in dem dead_tuple_countFeld der pgstattupleFunktion gezählt werden.

Demo mit 9.1: Erstellen Sie eine leere Tabelle

CREATE TABLE tt AS (n numeric);

Fügen wir 10 Millionen Zeilen ein:

INSERT INTO tt SELECT * FROM random() from generate_series(1,10000000);

Überprüfen Sie in einer anderen Sitzung pgstattuple jede Sekunde während des Einfügens:

$ while true;
   do psql -Atc "select dead_tuple_count from pgstattuple('tt')";
   sleep 1;
  done

Ergebnisse:

0
69005
520035
1013430
1492210
1990415
2224625
2772040
3314460
3928660
4317345
4743770
5379430
6080950
6522915
7190395
7953705
8747725
9242045
0

Es fällt auf 0 zurück, wenn die Einfügung beendet ist (alle Tupel werden sichtbar und leben).

Dieser Trick kann auch verwendet werden, wenn die Tabelle nicht neu erstellt wurde, die Initiale dead_tuple_countjedoch wahrscheinlich einen Wert ungleich Null aufweist. Er kann sich auch gleichzeitig ändern, wenn andere Schreibaktivitäten wie z Nebenläufigkeit mit autovacuum zu erwarten).

Es kann jedoch nicht verwendet werden, wenn die Tabelle von der Anweisung selbst ( CREATE TABLE ... AS SELECToder SELECT * INTO newtable) erstellt wird, da die Erstellung transaktioniert wird. Die Problemumgehung besteht darin, die Tabelle ohne Zeilen zu erstellen (Hinzufügen LIMIT 0) und in der nächsten Transaktion mit Daten zu füllen.

Beachten Sie, dass pgstattupledies nicht kostenlos ist: Bei jedem Aufruf wird die gesamte Tabelle durchsucht. Es ist auch auf Superuser beschränkt.

Benutzerdefinierter Zähler

In Pavel Stehules Blog stellt er eine in C implementierte Counter-Funktion bereit, die NOTICEs bei einer festgelegten Anzahl von Ausführungen auslöst. Sie müssen die Funktion irgendwie mit der Abfrage kombinieren, damit der Executor sie aufruft. Benachrichtigungen werden während der Abfrage gesendet und benötigen keine separate Sitzung, sondern nur einen SQL-Client, der sie anzeigt ( psqlder naheliegende Kandidat).

Beispiel für INSERT INTO überarbeitet, um Hinweise zu erhalten:

/* transformation */
INSERT INTO destination_table
   SELECT (r).*
  FROM (SELECT counter(to_destination_table(_source), 1000, true) r
           FROM source _source) x

Verwandte Frage zum Stackoverflow für Funktionen: Wie wird der Fortschritt der PostgreSQL-Funktion mit langer Laufzeit an den Client gemeldet?

Zukünftige Optionen?

Ab Mai 2017 wird der Entwickler-Community ein vielversprechender Patch zur Verfügung gestellt: [PATCH v2] Progress-Befehl zur Überwachung des Fortschritts lang laufender SQL-Abfragen

Dies könnte eine generische Lösung in PostgreSQL 11 oder höher sein. Benutzer, die an den in Arbeit befindlichen Funktionen teilnehmen möchten, wenden möglicherweise die neueste Version des Patches an und probieren den vorgeschlagenen PROGRESSBefehl aus.

Daniel Vérité
quelle
3

Bis die Funktionalität des Fortschrittsberichts nicht erweitert wird, wie @AmirAliAkbari in seiner Antwort erwähnt hat, gibt es hier eine Problemumgehung auf Betriebssystemebene.

Dies funktioniert nur unter Linux, aber wahrscheinlich gibt es ähnliche Lösungen für alle Betriebssysteme, die leicht zu finden sind.

Der größte Vorteil und auch Nachteil der PostgreSQL, dass alle seiner Backends einfache Single-Threaded - Prozesse sind, mit lseek(), read()und write()ihre Tabellendateien zu manipulieren, während sie auf gemeinsame mem und Schlössern interagieren.

Dies hat zur Folge, dass alle Backend-Prozesse immer an einer einzigen Abfrage arbeiten, die leicht gefunden werden kann, und straced.

Zuerst können Sie die Backend-PID von einem sehen SELECT * FROM pg_stat_activity;:

29805270 | dbname  | 20019 |    16384 | username  |                  |             |                 |          -1 | 2018-09-19 21:31:57.68234+02  | 2018-09-19 21:31:59.435376+02 | 2018-09-\
20 00:34:30.892382+02 | 2018-09-20 00:34:30.892386+02 | Client          | ClientRead | active              |       92778 |        92778 |  INSERT INTO ...something...

Die dritte Spalte ist die PID. In PostgreSQL ist es dasselbe wie die Linux-Prozess-PID des Backends.

Als nächstes können Sie es zum Beispiel durch ein strace -p 20019 -s 8192: ( -s 8192ist nützlich, weil postgresql mit 8192-Byte-langen Blöcken arbeitet).

sendto(10, "C\0\0\0\17INSERT 0 1\0Z\0\0\0\5T", 22, 0, NULL, 0) = 22
recvfrom(10, "Q\0\0\1\267 INSERT <removed by @peterh>", 8192, 0, NULL, NULL) = 440
sendto(10, "C\0\0\0\17INSERT 0 1\0Z\0\0\0\5T", 22, 0, NULL, 0) = 22
lseek(298, 343634345)...
read(298, "<block data which was read in>"....
write(298, "<block data which was written out>"...

Die Bedeutungen:

  • sendtopassiert, wenn das Backend einem Client etwas antwortet. Im Beispiel wird das Ergebnis einer INSERTAbfrage beantwortet.
  • recvfrompassiert, wenn das Backend etwas von einem Client bekommt. Es ist in der Regel eine neue Abfrage, im Beispiel noch eine andere INSERT.
  • lseek passiert, wenn das Backend in einer Tabellendatei die Position wechselt.
  • read passiert, wenn das Backend einen Block aus einer Tabellendatei einliest.
  • write passiert, wenn das Backend einen Block in eine Tabellendatei schreibt.

Im Fall von readund writekönnen Sie auch den Inhalt dieses Blocks in der Tabelle sehen. Es kann sehr hilfreich sein zu verstehen, was es tut und wo es ist.

Im Fall von sehen recvfromSie die aktuelle Abfrage, was das Backend hat.

sagt Peter, stell Monica wieder her
quelle
2

Wie bereits in anderen Antworten erwähnt, gibt es derzeit keinen direkten Weg für die allgemeine Fortschrittsberichterstattung.

PostgreSQL kann den Fortschritt bestimmter Befehle während der Befehlsausführung melden. Derzeit ist VACUUM der einzige Befehl, der Fortschrittsberichte unterstützt. Dies kann in Zukunft erweitert werden.

Ab Version 9.6 enthält VACUUMdie pg_stat_progress_vacuumAnsicht jedoch , wann immer sie ausgeführt wird, eine Zeile für jedes Backend (einschließlich Autovacuum-Worker-Prozessen), das gerade gesaugt wird. Weitere Details pg_stat_progress_vacuumfinden Sie in der Dokumentation: 27.4 Fortschrittsberichte .

Amir Ali Akbari
quelle