PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Identifizieren von PostgreSQL-Leistungsproblemen mit langsamen Abfragen

Bei der Arbeit mit OLTP-Datenbanken (OnLine Transaction Processing) ist die Abfrageleistung von größter Bedeutung, da sie sich direkt auf die Benutzererfahrung auswirkt. Langsame Abfragen bedeuten, dass die Anwendung nicht reagiert und langsam wirkt, was zu schlechten Konversionsraten, unzufriedenen Benutzern und allen Arten von Problemen führt.

OLTP ist einer der häufigsten Anwendungsfälle für PostgreSQL, daher möchten Sie, dass Ihre Abfragen so reibungslos wie möglich ausgeführt werden. In diesem Blog möchten wir darüber sprechen, wie Sie Probleme mit langsamen Abfragen in PostgreSQL identifizieren können.

Das langsame Protokoll verstehen

Im Allgemeinen besteht die typischste Methode zum Identifizieren von Leistungsproblemen mit PostgreSQL darin, langsame Abfragen zu sammeln. Es gibt ein paar Möglichkeiten, wie Sie dies tun können. Erstens können Sie es für eine einzelne Datenbank aktivieren:

pgbench=# ALTER DATABASE pgbench SET log_min_duration_statement=0;

ALTER DATABASE

Danach werden alle neuen Verbindungen zur ‚pgbench‘-Datenbank im PostgreSQL-Protokoll protokolliert.

Es ist auch möglich, dies global zu aktivieren, indem Sie Folgendes hinzufügen:

log_min_duration_statement = 0

zur PostgreSQL-Konfiguration und dann Konfiguration neu laden:

pgbench=# SELECT pg_reload_conf();

 pg_reload_conf

----------------

 t

(1 row)

Dies ermöglicht die Protokollierung aller Abfragen über alle Datenbanken in Ihrem PostgreSQL. Wenn Sie keine Protokolle sehen, sollten Sie möglicherweise auch logging_collector =on aktivieren. Die Protokolle enthalten den gesamten Datenverkehr, der zu PostgreSQL-Systemtabellen kommt, was ihn lauter macht. Bleiben wir für unsere Zwecke bei der Protokollierung auf Datenbankebene.

Was Sie im Protokoll sehen werden, sind Einträge wie unten:

2020-02-21 09:45:39.022 UTC [13542] LOG:  duration: 0.145 ms statement: SELECT abalance FROM pgbench_accounts WHERE aid = 29817899;

2020-02-21 09:45:39.022 UTC [13544] LOG:  duration: 0.107 ms statement: SELECT abalance FROM pgbench_accounts WHERE aid = 11782597;

2020-02-21 09:45:39.022 UTC [13529] LOG:  duration: 0.065 ms statement: SELECT abalance FROM pgbench_accounts WHERE aid = 16318529;

2020-02-21 09:45:39.022 UTC [13529] LOG:  duration: 0.082 ms statement: UPDATE pgbench_tellers SET tbalance = tbalance + 3063 WHERE tid = 3244;

2020-02-21 09:45:39.022 UTC [13526] LOG:  duration: 16.450 ms statement: UPDATE pgbench_branches SET bbalance = bbalance + 1359 WHERE bid = 195;

2020-02-21 09:45:39.023 UTC [13523] LOG:  duration: 15.824 ms statement: UPDATE pgbench_accounts SET abalance = abalance + -3726 WHERE aid = 5290358;

2020-02-21 09:45:39.023 UTC [13542] LOG:  duration: 0.107 ms statement: UPDATE pgbench_tellers SET tbalance = tbalance + -2716 WHERE tid = 1794;

2020-02-21 09:45:39.024 UTC [13544] LOG:  duration: 0.112 ms statement: UPDATE pgbench_tellers SET tbalance = tbalance + -3814 WHERE tid = 278;

2020-02-21 09:45:39.024 UTC [13526] LOG:  duration: 0.060 ms statement: INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (4876, 195, 39955137, 1359, CURRENT_TIMESTAMP);

2020-02-21 09:45:39.024 UTC [13529] LOG:  duration: 0.081 ms statement: UPDATE pgbench_branches SET bbalance = bbalance + 3063 WHERE bid = 369;

2020-02-21 09:45:39.024 UTC [13523] LOG:  duration: 0.063 ms statement: SELECT abalance FROM pgbench_accounts WHERE aid = 5290358;

2020-02-21 09:45:39.024 UTC [13542] LOG:  duration: 0.100 ms statement: UPDATE pgbench_branches SET bbalance = bbalance + -2716 WHERE bid = 210;

2020-02-21 09:45:39.026 UTC [13523] LOG:  duration: 0.092 ms statement: UPDATE pgbench_tellers SET tbalance = tbalance + -3726 WHERE tid = 67;

2020-02-21 09:45:39.026 UTC [13529] LOG:  duration: 0.090 ms statement: INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (3244, 369, 16318529, 3063, CURRENT_TIMESTAMP);

Sie können Informationen über die Abfrage und ihre Dauer sehen. Nicht viel mehr, aber es ist definitiv ein guter Anfang. Die Hauptsache, die Sie beachten sollten, ist, dass nicht jede langsame Abfrage ein Problem darstellt. Manchmal müssen Abfragen auf eine beträchtliche Datenmenge zugreifen, und es wird erwartet, dass sie länger brauchen, um auf alle vom Benutzer angeforderten Informationen zuzugreifen und diese zu analysieren. Eine andere Frage ist, was "langsam" bedeutet? Dies hängt vor allem von der Anwendung ab. Wenn wir über interaktive Anwendungen sprechen, ist höchstwahrscheinlich alles langsamer als eine Sekunde wahrnehmbar. Idealerweise wird alles innerhalb von 100 - 200 Millisekunden ausgeführt.

Entwicklung eines Abfrageausführungsplans

Sobald wir festgestellt haben, dass eine bestimmte Abfrage tatsächlich etwas ist, das wir verbessern möchten, sollten wir uns den Abfrageausführungsplan ansehen. Zunächst einmal kann es passieren, dass wir nichts dagegen tun können und wir akzeptieren müssen, dass die angegebene Abfrage nur langsam ist. Zweitens können sich Abfrageausführungspläne ändern. Optimierer versuchen immer, den optimalsten Ausführungsplan auszuwählen, treffen ihre Entscheidungen jedoch nur auf der Grundlage einer Stichprobe von Daten. Daher kann es vorkommen, dass sich der Ausführungsplan der Abfrage im Laufe der Zeit ändert. In PostgreSQL können Sie den Ausführungsplan auf zwei Arten überprüfen. Zuerst der geschätzte Ausführungsplan mit EXPLAIN:

pgbench=# EXPLAIN SELECT abalance FROM pgbench_accounts WHERE aid = 5290358;

                                          QUERY PLAN

----------------------------------------------------------------------------------------------

 Index Scan using pgbench_accounts_pkey on pgbench_accounts  (cost=0.56..8.58 rows=1 width=4)

   Index Cond: (aid = 5290358)

Wie Sie sehen können, wird von uns erwartet, dass wir mit der Primärschlüsselsuche auf Daten zugreifen. Wenn wir überprüfen möchten, wie genau die Abfrage ausgeführt wird, können wir EXPLAIN ANALYZE:

verwenden
pgbench=# EXPLAIN ANALYZE SELECT abalance FROM pgbench_accounts WHERE aid = 5290358;

                                                               QUERY PLAN

----------------------------------------------------------------------------------------------------------------------------------------

 Index Scan using pgbench_accounts_pkey on pgbench_accounts  (cost=0.56..8.58 rows=1 width=4) (actual time=0.046..0.065 rows=1 loops=1)

   Index Cond: (aid = 5290358)

 Planning time: 0.053 ms

 Execution time: 0.084 ms

(4 rows)

Jetzt hat PostgreSQL diese Abfrage ausgeführt und kann uns nicht nur die Schätzungen, sondern auch genaue Zahlen in Bezug auf den Ausführungsplan, die Anzahl der aufgerufenen Zeilen usw. mitteilen. Bitte beachten Sie, dass das Protokollieren aller Abfragen zu einem erheblichen Overhead auf Ihrem System werden kann. Sie sollten auch die Protokolle im Auge behalten und sicherstellen, dass sie richtig gedreht sind.

Pg_stat_statements

Pg_stat_statements ist die Erweiterung, die Ausführungsstatistiken für verschiedene Abfragetypen sammelt.

pgbench=# select query, calls, total_time, min_time, max_time, mean_time, stddev_time, rows from public.pg_stat_statements order by calls desc LIMIT 10;

                                                query                                                 | calls | total_time | min_time | max_time |     mean_time | stddev_time | rows

------------------------------------------------------------------------------------------------------+-------+------------------+----------+------------+---------------------+---------------------+-------

 UPDATE pgbench_branches SET bbalance = bbalance + $1 WHERE bid = $2                                  | 30437 | 6636.83641200002 | 0.006533 | 83.832148 | 0.218051595492329 | 1.84977058799388 | 30437

 BEGIN                                                                                                | 30437 | 231.095600000001 | 0.000205 | 20.260355 | 0.00759258796859083 | 0.26671126085716 | 0

 END                                                                                                  | 30437 | 229.483213999999 | 0.000211 | 16.980678 | 0.0075396134310215 | 0.223837608828596 | 0

 UPDATE pgbench_accounts SET abalance = abalance + $1 WHERE aid = $2                                  | 30437 | 290021.784321001 | 0.019568 | 805.171845 | 9.52859297305914 | 13.6632712046825 | 30437

 UPDATE pgbench_tellers SET tbalance = tbalance + $1 WHERE tid = $2                                   | 30437 | 6667.27243200002 | 0.00732 | 212.479269 | 0.219051563294674 | 2.13585110968012 | 30437

 SELECT abalance FROM pgbench_accounts WHERE aid = $1                                                 | 30437 | 3702.19730600006 | 0.00627 | 38.860846 | 0.121634763807208 | 1.07735927551245 | 30437

 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES ($1, $2, $3, $4, CURRENT_TIMESTAMP) | 30437 | 2349.22475800002 | 0.003218 |  61.372127 | 0.0771831901304325 | 0.971590327400244 | 30437

 SELECT $1                                                                                            | 6847 | 60.785467 | 0.002321 | 7.882384 | 0.00887767883744706 | 0.105198744982906 | 6847

 insert into pgbench_tellers(tid,bid,tbalance) values ($1,$2,$3)                                      | 5000 | 18.592042 | 0.001572 | 0.741427 | 0.0037184084 | 0.0137660355678027 | 5000

 insert into pgbench_tellers(tid,bid,tbalance) values ($1,$2,$3)                                      | 3000 | 7.323788 | 0.001598 | 0.40152 | 0.00244126266666667 | 0.00834442591085048 | 3000

(10 rows)

Wie Sie an den Daten oben sehen können, haben wir eine Liste mit verschiedenen Abfragen und Informationen über ihre Ausführungszeiten - dies ist nur ein Teil der Daten, die Sie in den pg_stat_statements sehen können, aber es reicht aus uns zu verstehen, dass unsere Suche nach Primärschlüsseln manchmal fast 39 Sekunden dauert - das sieht nicht gut aus und ist definitiv etwas, das wir untersuchen wollen.

Wenn Sie pg_stat_statements nicht aktiviert haben, können Sie dies auf eine standardmäßige Weise tun. Entweder über Konfigurationsdatei und

shared_preload_libraries = 'pg_stat_statements'

Oder Sie können es über die PostgreSQL-Befehlszeile aktivieren:

pgbench=# CREATE EXTENSION pg_stat_statements;

CREATE EXTENSION

ClusterControl verwenden, um langsame Abfragen zu eliminieren

Wenn Sie ClusterControl verwenden, um Ihre PostgreSQL-Datenbank zu verwalten, können Sie damit Daten über langsame Abfragen sammeln.

Wie Sie sehen, werden Daten zur Abfrageausführung gesammelt – gesendete Zeilen und untersucht, Ausführungszeitstatistiken und so weiter. Damit können Sie die teuersten Abfragen leicht lokalisieren und sehen, wie die durchschnittliche und maximale Ausführungszeit aussieht. Standardmäßig sammelt ClusterControl Abfragen, die länger als 0,5 Sekunden gedauert haben, Sie können dies in den Einstellungen ändern:

Fazit

Dieser kurze Blog deckt keineswegs alle Aspekte und Tools ab, die beim Identifizieren und Lösen von Abfrageleistungsproblemen in PostgreSQL hilfreich sind. Wir hoffen, dass es ein guter Anfang ist und dass es Ihnen hilft zu verstehen, was Sie tun können, um die Ursache der langsamen Abfragen zu lokalisieren.