
Dieses Tool wurde aus sportlichen Gründen geschrieben, als ich feststellte, dass die Ansicht pg_stat_activity in PostgreSQL 10 die Felder wait_event_type und wait_event enthält, die im Wesentlichen der wait_class und dem Ereignis aus v $ session sehr ähnlich sind.
Ich habe gerade aktiv mit
dem ASH-Viewer-Programm von
akardapolov gearbeitet und war gespannt, wie schwierig es ist, dieses Produkt unter Postgres neu zu schreiben. Da ich kein professioneller Entwickler bin, war es nicht einfach, aber sehr interessant. Dabei habe ich sogar einige signifikante Fehler gefunden, die sowohl im Originalprogramm für Oracle als auch für die Standard Edition auftreten.
Die Prinzipien von PASH-Viewer:
Keine Erweiterungen erforderlich. Wir beziehen Daten ausschließlich aus der integrierten Ansicht pg_stat_activity.
Einmal pro Sekunde wird eine Anfrage für aktive Sitzungen gestellt:
pg_stat_activity AnfragetextSELECT current_timestamp, datname, pid, usesysid, usename, application_name, backend_type, coalesce(client_hostname, client_addr::text, 'localhost') as client_hostname, wait_event_type, wait_event, query, query_start, 1000 * EXTRACT(EPOCH FROM (clock_timestamp()-query_start)) as duration from pg_stat_activity where state='active' and pid != pg_backend_pid();
Einmal alle 15 Sekunden werden die Daten für die letzten 15 Bilder gemittelt und in einem Diagramm angezeigt.
Die SQL-ID, die zum Gruppieren der Abfragen im Abschnitt Top SQL benötigt wird, die ich selbst generiere, hat nichts mit der Abfrage-ID von pg_stat_statements zu tun. Ich habe überlegt, wie ich queryid verwenden soll, aber leider habe ich keine Möglichkeit gefunden, Abfragen aus diesen beiden Ansichten abzugleichen. Es wäre großartig, wenn die Entwickler das Feld queryid zu pg_stat_activity hinzufügen würden.
SQL-ID = die ersten 13 Zeichen von md5 (normalisierter Abfragetext).
Ein normalisierter Abfragetext ist eine Abfrage, bei der Zeilenumbrüche und zusätzliche Leerzeichen entfernt und Literale durch $ 1, $ 2 usw. ersetzt werden. Es war schwierig für mich, eine gute Funktion zur Normalisierung von Abfragen zu schreiben. Ich habe einen schlechten geschrieben. Ich zitiere den Text, aber bitte schau ihn dir nicht an, sonst schäme ich mich. Schicken Sie besser einen guten.
NormalizeSQL public static String NormalizeSQL(String sql) { sql = sql.replaceAll("\\n", " "); sql = sql.replaceAll("\\(", " ( "); sql = sql.replaceAll("\\)", " ) "); sql = sql.replaceAll(",", " , "); sql = sql.replaceAll("'", " ' "); sql = sql.replaceAll("=", " = "); sql = sql.replaceAll("<", " < "); sql = sql.replaceAll(">", " > "); sql = sql.replaceAll(";", ""); sql = sql.replaceAll("[ ]+", " "); sql = sql.replaceAll("> =", ">="); sql = sql.replaceAll("< =", "<="); sql = sql.toLowerCase().trim(); String[] array = sql.split(" ", -1); int var_number = 0; String normalized_sql = ""; Boolean quote_flag = false; for (int i = 0; i < array.length; i++) { if (array[i].equals("'")) { if (!quote_flag) { quote_flag = true; var_number++; normalized_sql += "$" + var_number + " "; } else { quote_flag = false; } } else if (quote_flag) { continue; } else if (array[i].matches("-?\\d+(\\.\\d+)?")) { var_number++; normalized_sql += "$" + var_number + " "; } else if (array[i].equals("order")) { for (int j = i; j < array.length; j++) { normalized_sql += array[j] + " "; } return normalized_sql.trim(); } else { normalized_sql += array[i] + " "; } } return normalized_sql.trim(); }
Es war schwierig, den Abfrageausführungsplan zu vervollständigen. Zu Oracle kommen Sie und sagen: "Geben Sie mir einen Plan für sqlid = ...", und er antwortet Ihnen: "Haben Sie den neuesten oder den letzten oder zeigen Sie alles für den letzten Monat mit Ausführungsstatistiken für jeden?" Und PostgreSQL antwortet Ihnen: "Was ist sqlid?".
Daher senden wir für Abfragen der Form SELECT / UPDATE / INSERT / DELETE den Befehl EXPLAIN an die Datenbank und speichern das Ergebnis lokal. Wir machen das nicht mehr als 1 Mal pro Stunde. Während des Debuggens wurde festgestellt, dass EXPLAIN auf dieselbe Weise an der Sperre hängt, wie die Anforderung selbst hängen würde, für die wir den Plan wissen möchten. Daher musste ich setQueryTimeout (1) hinzufügen.
Dies funktioniert nur, wenn die Anforderung in derselben Datenbank ausgeführt wurde, mit der Sie eine Verbindung hergestellt haben (angegeben bei der Konfiguration der Verbindung). Und nur, wenn Sie unter dem Superuser (postgres) eine Verbindung zur Datenbank hergestellt haben, vor der einige möglicherweise Angst haben. Daher können Sie einen speziellen Benutzer für die Überwachung erstellen. Alles außer der Anzeige von Plänen wird funktionieren.
CREATE USER pgmonuser WITH password 'pgmonuser'; GRANT pg_monitor TO pgmonuser;
Download von GitHub:
https://github.com/dbacvetkov/PASH-Viewer/releasesUPD:In Version 0.3 wurde die Unterstützung für PostgreSQL 9.6 (es gibt nur zwei wartende Klassen - Lock und LWLock, alles andere wie "CPU") und PostgreSQL 9.4 - 9.5 (es wartet entweder eine CPU oder Lock im Allgemeinen) hinzugefügt.
In Version 0.3.1 wurde das Feld Backend-Typ in Top-Sitzungen hinzugefügt und die weißen Balken im Diagramm wurden entfernt.
In Version 0.3.2 wurden die Arbeit mit Plänen verbessert, einige Statistiken zu Anforderungen (AVG-Dauer, Anzahl der Anrufe) und die Möglichkeit zum Anzeigen historischer Daten hinzugefügt:
How-to-create-pg_stat_activity-history-table .
Danke und Grüße:
Alexander Kardapolov für ASH-Viewer.
Anton Glushakov zur Beratung und Prüfung.
Dmitry Rudopysov für die Erklärung, wie das von github heruntergeladene Projekt kompiliert und ausgeführt wird.
Weitere Folien:


