Monitorings

pg_stat_statements: kā atrast vaicājumus, kas patiešām noslogo PostgreSQL

Lēnākais vaicājums žurnālā reti ir tas, kas izmaksā visvairāk. pg_stat_statements parāda, kur patiesībā aiziet datubāzes laiks, ja to pareizi iestata un uzmanīgi lasa skaitļus.

· 12 min lasīšanai · AG Data komanda

pg_stat_statements ir PostgreSQL paplašinājums, kas uzkrāj plānošanas un izpildes statistiku par katru atšķirīgo SQL izteikumu, ko izpilda serveris. Kad datubāze ir lēna un neviens nezina kāpēc, tā ir pirmā vieta, kur skatāmies, jo tas atbild uz jautājumu, uz ko lēno vaicājumu žurnāls neatbild: kuri izteikumi kopā patērē visvairāk datubāzes laika.

Vaicājums, kas reizi naktī ilgst 40 sekundes, žurnālā izskatās biedējoši. Vaicājums, kas ilgst 3 ms, bet izpildās 2000 reižu sekundē, izmaksā daudz vairāk. pg_stat_statements grupē izteikumus pēc to normalizētās formas (konstantes kļūst par $1, $2), tāpēc šie 2000 izsaukumi sekundē parādās kā viena rinda ar reālām summām. Oficiālajā dokumentācijā aprakstīta katra kolonna. Zemāk ir tas, kā mēs to lietojam praksē.

pg_stat_statements ieslēgšana

Modulim vajadzīga koplietojamā atmiņa, tāpēc tam jābūt norādītam shared_preload_libraries, un tā pievienošanai vai noņemšanai nepieciešams servera restarts. Plānojiet šo restartu apkopes logā. Pats skats tiek izveidots katrā datubāzē ar CREATE EXTENSION.

# postgresql.conf (nepieciešams restarts)
shared_preload_libraries = 'pg_stat_statements'
compute_query_id = auto          # noklusējums; nedrīkst būt off
pg_stat_statements.max = 10000   # noklusējums 5000, tikai servera startā

-- pēc tam katrā datubāzē, kur vajadzīgs skats
CREATE EXTENSION pg_stat_statements;

Lai modulis strādātu, jāaprēķina vaicājumu identifikatori. Noklusējuma compute_query_id = auto to ieslēdz automātiski, kad pg_stat_statements ir ielādēts, tāpēc pārbaudiet to tikai tad, ja kāds to iestatījis uz off. Pārvaldītajos servisos, piemēram, RDS vai Cloud SQL, tos pašus iestatījumus maina caur parametru vai karogu konfigurāciju, nevis postgresql.conf.

Smagākie vaicājumi pēc kopējā laika

Šo vaicājumu palaižam vispirms. Tas sarindo izteikumus pēc kopējā izpildes laika un parāda katra daļu no kopsummas:

SELECT queryid,
       calls,
       round(total_exec_time::numeric)    AS total_ms,
       round(mean_exec_time::numeric, 2)  AS mean_ms,
       rows / nullif(calls, 0)            AS rows_per_call,
       round((100 * total_exec_time
              / sum(total_exec_time) OVER ())::numeric, 1) AS pct,
       left(query, 80)                    AS query
FROM pg_stat_statements
WHERE toplevel
ORDER BY total_exec_time DESC
LIMIT 20;

Kolonnu nosaukumi ir svarīgi. Kopš PostgreSQL 13 izpildes laiks ir total_exec_time un mean_exec_time; PostgreSQL 12 un vecākās versijās tie bija total_time un mean_time, tāpēc daudzi nokopēti skripti neizdodas. Laiki ir milisekundēs. Filtrs toplevel (PostgreSQL 14+) atstāj lietotnes izsauktos izteikumus un paslēpj funkciju iekšienē izpildītos, kurus uzskaita tikai tad, ja pg_stat_statements.track = all; noklusējums ir top.

Kā lasīt skaitļus

Sarindošana pēc I/O, pagaidu failiem un WAL

Laiks nav vienīgās izmaksas. Datubāzē, kas ir lielāka par RAM, izteikumi, kas nolasa visvairāk bloku ārpus shared buffers, parasti ir tie, kas izspiež visu pārējo no kešatmiņas:

SELECT queryid,
       calls,
       shared_blks_read,
       round(100.0 * shared_blks_hit
             / nullif(shared_blks_hit + shared_blks_read, 0), 1) AS hit_pct,
       temp_blks_written,
       pg_size_pretty(wal_bytes)          AS wal,
       left(query, 60)                    AS query
FROM pg_stat_statements
ORDER BY shared_blks_read DESC
LIMIT 20;

Sakārtojiet to pašu vaicājumu pēc temp_blks_written, lai atrastu kārtošanas un hash operācijas, kas izlīst uz diska, vai pēc wal_bytes, lai atrastu rakstīšanu, kas rada replikācijas aizkavi un WAL arhīva apjomu. Kolonna shared_blk_read_time (pirms PostgreSQL 17 blk_read_time) tiek aizpildīta tikai tad, ja ieslēgts track_io_timing. Pēc noklusējuma tas ir izslēgts, jo laika mērīšanas izsaukumi dažās platformās var būt dārgi; dokumentācija iesaka vispirms izmērīt ar pg_test_timing.

Neatiestatiet statistiku, lai incidenta laikā "sāktu no jauna". pg_stat_statements_reset() bez argumentiem izmet visu, arī vēsturi, kas parāda, kas mainījās. Tā vietā izveidojiet momentuzņēmumu un salīdziniet. PostgreSQL 17+ var atiestatīt tikai min/max laikus ar pg_stat_statements_reset(0, 0, 0, true).

Momentuzņēmumi ir labāki par atiestatīšanu

Skatā ir kumulatīvi skaitītāji kopš katra ieraksta izveides. Lai redzētu, kas notika no 14:00 līdz 14:15, saglabājiet momentuzņēmumus un atņemiet. Funkcijai nododot false, vaicājumu teksti netiek atgriezti, tāpēc bieži momentuzņēmumi paliek lēti:

-- momentuzņēmums bez vaicājumu tekstiem (lēti), piem., ik 5-15 minūtes
INSERT INTO pgss_snap
SELECT now(), userid, dbid, toplevel, queryid, stats_since,
       calls, total_exec_time, rows, shared_blks_read,
       temp_blks_written, wal_bytes
FROM pg_stat_statements(false);

-- cik pilna ir hash tabula un vai ieraksti tiek izmesti?
SELECT dealloc, stats_reset FROM pg_stat_statements_info;

Savienojiet momentuzņēmumus pēc userid, dbid, toplevel, queryid. Kopš PostgreSQL 17 katram ierakstam ir stats_since; ja tas starp diviem momentuzņēmumiem mainījies, ieraksts tika izmests un izveidots no jauna, un starpībai nav jēgas. Šīs starpības ir arī izejmateriāls brīdinājumiem par datubāzes metrikām, kas paredz incidentus.

Slazdi, par kuriem vērts zināt

Kas mainās lielās, noslogotās datubāzēs

Galvenās atziņas

PostgreSQL Veiktspēja Monitorings pg_stat_statements
Sadarbība ar mums

Jāsaprot, kas noslogo jūsu datubāzi?

Mēs analizējam pg_stat_statements, žurnālus un plānus produkcijas PostgreSQL, atrodam dārgākos izteikumus un tos salabojam bez minēšanas.

Sazināties Vairāk no emuāra