pg_stat_statements je rozšíření PostgreSQL, které si pro každý odlišný dotaz, jejž tvoje databáze vykonala, vede jeden řádek s průběžnými součty: kolikrát proběhl, jak dlouho trval celkem, kolik řádků vrátil a kolik bufferů se dotkl. Pohled seřadíš podle celkového času, vezmeš prvních pět a máš seznam dotazů, které stojí za pozornost. Je to nejužitečnější pohled pro ladění výkonu, protože odpovídá na otázku, na kterou hádání nestačí: které dotazy tenhle server opravdu stojí nejvíc. K zapnutí potřebuješ knihovnu načtenou při startu serveru, jeden příkaz CREATE EXTENSION a zhruba megabajt sdílené paměti. Tento návod pokrývá nastavení, všechny sloupce, které stojí za čtení, dotazy, které máš spouštět, a jak to, co najdeš, předat do EXPLAIN.
Co pg_stat_statements zaznamenává a co ne#
Pokaždé, když příkaz skončí, PostgreSQL z něj odstraní konkrétní hodnoty, to, co zbude, zahashuje do queryid a k tomuto záznamu přičte údaje o čase a I/O. Dva požadavky, které se liší jen parametry, sdílejí jeden řádek:
SELECT * FROM orders WHERE customer_id = 42;SELECT * FROM orders WHERE customer_id = 9001;Oba se stanou jedním záznamem uloženým jako SELECT * FROM orders WHERE customer_id = $1. Tomu se říká normalizace dotazů a je to důvod, proč je pohled užitečný: tisíc variant z aplikace se sloučí do hrstky tvarů dotazů, které tvůj kód skutečně obsahuje.
Dostaneš kumulativní obraz, ne historii. Čítače začínají na nule, když se rozšíření poprvé načte, a rostou, dokud je neresetuješ. Z toho poznáš, které dotazy dlouhodobě převažují, ale ne kdy se dotaz zpomalil ani v kolik hodin. Pokud to potřebuješ, pořizuj z pohledu snímky podle plánu (viz níže) nebo použij nástroje založené na logu z části o doplňcích.
Než se na něj spolehneš, vyplatí se znát tři omezení:
- Neukládá parametry. Vidíš
$1, nikdy hodnotu, která byla pomalá. Konkrétní hodnotu zjistíš z logu (log_min_duration_statement) nebo přesauto_explain. - Počítá dobu provádění, ne čekání v tvé aplikaci. Dotaz, který běží 3 ms, ale 400 ms stojí ve frontě poolu spojení, tady vypadá rychle. K té stránce věci viz pooly spojení a limity.
- Drží omezený počet záznamů. Výchozí hodnota je 5 000 různých příkazů; když je tabulka plná, nejméně používané záznamy se vyřadí. Většina malých aplikací se k tomu nedostane, ale taková, která skládá SQL v proměnlivých tvarech, ano.
Zjisti, jestli už není nainstalované#
Udělej to dřív, než cokoli změníš. U mnoha poskytovatelů jsou soubory rozšíření přítomné, ale nezapnuté, nebo je už zapnuté a nikdo ti to neřekl. Připoj se přes psql a spusť:
SELECT name, default_version, installed_versionFROM pg_available_extensionsWHERE name = 'pg_stat_statements';SELECT extname, extversion FROM pg_extension;SHOW shared_preload_libraries;Přečti si všechny tři výsledky dohromady:
| Co vidíš | Co to znamená |
|---|---|
Žádný řádek v pg_available_extensions | Balíček na serveru není nainstalovaný |
Řádek existuje, installed_version je prázdná | Soubory existují, ale CREATE EXTENSION se v této databázi nespustilo |
pg_stat_statements v pg_extension | Nainstalováno v této databázi a pravděpodobně sbírá data |
Knihovna chybí v shared_preload_libraries | Rozšíření existuje, ale nic nesbírá; pohled skončí chybou |
Poslední řádek lidi překvapuje. CREATE EXTENSION může projít i bez načtené knihovny a pak SELECT z pohledu selže s chybou pg_stat_statements must be loaded via "shared_preload_libraries". Rozšíření se zapíná pro každou databázi zvlášť, ale jakmile sbírá data, pohled v kterékoli databázi ukazuje příkazy ze všech databází instance a sloupec dbid je od sebe odlišuje.
Jestli můžeš měnit shared_preload_libraries, závisí úplně na tom, kde databáze běží. Na serveru, který spravuješ sám, můžeš. U hostované databáze to může být nastavené za tebe, měnit to může jen poskytovatel, nebo to nemusí být vystavené vůbec. Nikde netvrdíme, že to PostgreSQL plány RE:NODE umožňují, takže bezpečná cesta je kontrola výše: pokud rozšíření chybí, otevři z panelu ticket a zeptej se podpory, jestli jde na tvé instanci zapnout. Nepředpokládej ani jednu odpověď. Vše po části o nastavení funguje na jakémkoli hostingu, kde pohled existuje.
Zapnutí na serveru, který ovládáš#
Pokud PostgreSQL provozuješ sám nebo ti poskytovatel dovolí upravit konfiguraci, jsou to tři kroky. Knihovna se musí načíst při startu serveru, protože si alokuje sdílenou paměť pro svou tabulku.
Nejdřív ji přidej do postgresql.conf:
shared_preload_libraries = 'pg_stat_statements'pg_stat_statements.max = 5000pg_stat_statements.track = topcompute_query_id = autotrack_io_timing = onPokud řádek už jiné knihovny uvádí, ponech je a odděl čárkami. Přepsání existujícího shared_preload_libraries je klasický způsob, jak vypnout něco jiného, co jsi potřeboval. Ekvivalent bez ruční úpravy souboru je ALTER SYSTEM SET shared_preload_libraries = 'pg_stat_statements';, který zapisuje do postgresql.auto.conf.
Za druhé restartuj server. Pro toto nastavení nestačí reload (SELECT pg_reload_conf();). Naplánuj to na klidnou chvíli; restart zahodí všechna spojení a ladění PostgreSQL pro malé servery uvádí, která další nastavení mají stejný požadavek, takže je můžeš sloučit do jednoho restartu.
Za třetí vytvoř rozšíření v databázi, ze které budeš dotazovat:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;K tomu potřebuješ roli, která smí vytvářet rozšíření; na samostatně spravovaném serveru je to superuživatel. Ověř, že to funguje:
SELECT count(*) FROM pg_stat_statements;Číslo, i malé, znamená, že se data sbírají. Pokud dostaneš chybu „must be loaded“, restart nastavení nepřevzal, takže spusť SHOW shared_preload_libraries; a podívej se, co server skutečně načetl.
Po upgradu na novou hlavní verzi spusť ALTER EXTENSION pg_stat_statements UPDATE; v každé databázi, která ho má. Sloupce pohledu se mezi verzemi mění a stará definice si staré sloupce drží, dokud to neuděláš.
Nastavení, na kterém záleží#
Rozšíření řídí čtyři parametry. Restart potřebuje jen max.
| Nastavení | Výchozí | Co dělá |
|---|---|---|
pg_stat_statements.max | 5000 | Počet sledovaných různých příkazů; ke změně je potřeba restart |
pg_stat_statements.track | top | top počítá příkazy od klientů, all přidává ty vnořené ve funkcích, none sledování vypne |
pg_stat_statements.track_utility | on | Sleduje také COPY, CREATE INDEX, VACUUM a další příkazy, které nejsou dotazy |
pg_stat_statements.save | on | Zachová čítače přes řádný restart |
top je správně téměř pro každého. Na all přepni, jen když podezříváš pomalou uloženou funkci a chceš vidět, který příkaz uvnitř za to může; cenou je více záznamů a více šumu. Existuje také pg_stat_statements.track_planning, které je ve výchozím stavu off, protože měření času plánování přidává režii na vytížených serverech. Zapni ho nakrátko, pokud podezříváš, že problém je v plánování, například u velmi širokých dělených tabulek.
O užitečnosti čísel rozhodují dvě nastavení mimo samotné rozšíření:
- `compute_query_id` (PostgreSQL 14 a novější) má výchozí hodnotu
auto, která zapne identifikátory dotazů, když je načtenopg_stat_statements. Nech to tak. Stejný identifikátor se pak objeví vpg_stat_activity.query_ida vEXPLAIN (VERBOSE), takže můžeš spojit živý dotaz s jeho historií. - `track_io_timing` má výchozí hodnotu
off. Když je vypnuté, sloupce s časem čtení a zápisu bloků zůstávají na nule a nepoznáš, jestli je dotaz pomalý kvůli disku. Na moderním hardwaru je režie malá;pg_test_timingji pro tvůj stroj změří. Pokud můžeš, zapni to.
Poznámka k paměti: tabulka je malá. Pět tisíc záznamů jsou nejvýše několik megabajtů a texty dotazů leží v souboru na disku. Na serveru s 1 GB si toho nevšimneš.
Sloupce a past s verzemi#
Spusť v psql příkaz \d pg_stat_statements a uvidíš přesný seznam pro svou verzi. Ty, které budeš používat denně:
| Sloupec | Význam |
|---|---|
queryid | Hash normalizovaného dotazu; stabilní do upgradu hlavní verze nebo změny schématu |
query | Normalizovaný text se zástupnými znaky $1, $2 |
calls | Kolikrát byl vykonán |
total_exec_time | Celkem milisekund strávených prováděním, přes všechna volání |
mean_exec_time | total_exec_time / calls, v milisekundách |
stddev_exec_time | Jak moc se doba běhu mezi voláními liší |
rows | Celkem vrácených nebo ovlivněných řádků, přes všechna volání |
A sloupce I/O, které říkají, jestli čas padl na paměť, nebo na disk:
| Sloupec | Význam |
|---|---|
shared_blks_hit | Bloky po 8 kB nalezené v bufferové cache PostgreSQL |
shared_blks_read | Bloky načtené zvenčí cache |
shared_blks_dirtied | Bloky, které dotaz změnil |
temp_blks_written | Bloky přelité do dočasných souborů |
Několik sloupců si zaslouží výklad. shared_blks_read nemusí být nutně disk: jsou to bloky, které nebyly ve vlastních bufferech PostgreSQL, a mohla je přesto obsloužit cache operačního systému. Vysoké číslo ale pořád znamená, že dotaz sahá na víc dat, než se vejde do shared_buffers, a to je signál, že se máš podívat na plán. temp_blks_written nad nulou znamená, že řazení nebo hash přesáhl work_mem a zapisoval na disk, což je jiná oprava než chybějící index. Od PostgreSQL 17 byly sloupce s časy I/O přejmenovány s předponou shared_, například shared_blk_read_time; stejná kontrola přes \d ti řekne, kterou variantu máš.
Tři dotazy na nejhorších N#
Vše výše existuje kvůli těmto dotazům. Stejný pohled seřazený třemi způsoby odpovídá na tři různé otázky.
Podle celkového času: kam server utrácí den
SELECT queryid, calls, round(total_exec_time::numeric, 1) AS total_ms, round(mean_exec_time::numeric, 2) AS mean_ms, round((100 * total_exec_time / sum(total_exec_time) OVER ())::numeric, 1) AS pct, rows, left(query, 80) AS queryFROM pg_stat_statementsORDER BY total_exec_time DESCLIMIT 10;Tohle je dotaz, který spustíš jako první a nejčastěji. Sloupec pct ukazuje podíl každého příkazu na celkovém času provádění; v typické aplikaci tři nebo čtyři záznamy tvoří většinu. Dotaz, který trvá 4 ms, ale běží dva miliony krát denně, tedy dohromady 8 000 sekund, stojí víc než devítivteřinový report, který běží jednou za noc. Často se také opravuje snáz, protože obvykle chce jeden index nebo o jeden dotaz do databáze méně.
Podle průměrného času: jednotlivě pomalé dotazy
SELECT queryid, calls, round(mean_exec_time::numeric, 2) AS mean_ms, round(stddev_exec_time::numeric, 2) AS stddev_ms, left(query, 80) AS queryFROM pg_stat_statementsWHERE calls >= 20ORDER BY mean_exec_time DESCLIMIT 10;Filtr calls >= 20 má smysl. Bez něj by seznam vedl jednorázový CREATE INDEX nebo ruční VACUUM a nic by ti neřekl. Toto řazení najde dotazy, které uživatel pocítí: stránku s reportem, export, vyhledávání s wildcardem na začátku. Dívej se na stddev_ms vedle průměru. Průměr 50 ms se směrodatnou odchylkou 400 ms není pomalý dotaz, je to dotaz se dvěma chováními, často proto, že plánovač volí různé plány podle parametru. Na to je určený auto_explain, viz níže.
Podle počtu volání: upovídané dotazy
SELECT queryid, calls, round(mean_exec_time::numeric, 3) AS mean_ms, rows / calls AS rows_per_call, left(query, 80) AS queryFROM pg_stat_statementsORDER BY calls DESCLIMIT 10;Dotaz s miliony volání a drobným průměrem je typický podpis vzoru N+1: aplikace načte seznam a pak pro každou položku spustí jeden dotaz. Žádný index to neopraví; pomůže join nebo dávkové WHERE id = ANY($1). Sloupec rows_per_call pomáhá: příkaz, který vrací přesně jeden řádek a volá se milionkrát, hledá věci po jedné.
Podle cache miss a dočasných souborů
Dvě další řazení stojí za to mít uložená jako snippety. První najde dotazy, které čtou nejvíc dat, bez ohledu na to, jak rychle se vrátily:
SELECT queryid, shared_blks_hit, shared_blks_read, round(100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0), 1) AS hit_pct, left(query, 70) AS queryFROM pg_stat_statementsORDER BY shared_blks_read DESCLIMIT 10;Druhé, ORDER BY temp_blks_written DESC, vypíše dotazy, které přelévají řazení na disk. Ani jedno samo o sobě není naléhavé. Hit procento v horních devadesátkách je normální; často volaný příkaz na 70 procentech ti přetáčí cache a vytlačuje data, která potřebují jiné dotazy.
Měření okna a resetování#
Protože jsou čísla kumulativní, chování z minulého měsíce je smíchané s dnešním. Chceš-li změřit konkrétní období, například hodinu po deployi, vynuluj čítače, počkej a pak čti:
SELECT pg_stat_statements_reset();Na PostgreSQL 12 a novějším funkce přijímá i argumenty userid, dbid a queryid, takže po opravě můžeš vynulovat jediný příkaz a sledovat, jak se chová. Ve výchozím stavu ji smí volat jen superuživatel a nejde vrátit zpět, takže si nejdřív zapiš, co potřebuješ. Levný způsob, jak si uchovat historii bez dalších nástrojů, je tabulka se snímky:
CREATE TABLE stmt_snapshot ASSELECT now() AS taken_at, queryid, calls, total_exec_time, rows, queryFROM pg_stat_statements;-- later: INSERT INTO stmt_snapshot SELECT now(), queryid, calls, ... FROM pg_stat_statements;Odečti calls a total_exec_time jednoho snímku od dalšího a dostaneš cenu mezi nimi. Spouštěj to hodinově ze schedulerů jako cron nebo pg_cron a máš týden trendových dat. Tabulku udržuj malou mazáním starých řádků a text dotazu stačí uložit jednou, pokud ho držíš v samostatné tabulce podle queryid.
Pokud server spadne nebo je proces zabit, pg_stat_statements.save nepomůže: čítače jsou ztracené, protože se zapisují jen při řádném vypnutí. Pohled ber jako okno nedávné aktivity, ne trvalý záznam.
Od queryid k opravě: EXPLAIN (ANALYZE, BUFFERS)#
Pohled ti řekne, na který dotaz se podívat. Neřekne ti, proč je pomalý. Zkopíruj normalizovaný text, za každé $1 dosaď realistickou hodnotu a spusť ho pod EXPLAIN s volbami, které odhalí I/O:
EXPLAIN (ANALYZE, BUFFERS, SETTINGS)SELECT * FROM ordersWHERE customer_id = 42 AND status = 'open'ORDER BY created_at DESCLIMIT 20;ANALYZE příkaz opravdu spustí, takže cokoli, co zapisuje, zabal do transakce, kterou vrátíš: BEGIN; EXPLAIN (ANALYZE, BUFFERS) UPDATE ...; ROLLBACK;. BUFFERS přidá řádky Buffers: shared hit=... read=..., které můžeš porovnat se sloupci shared_blks_hit a shared_blks_read z pohledu. Pokud pohled říká, že tento dotaz čte 40 000 bloků na volání, plán by měl ukazovat uzel, který to vysvětluje, obvykle sekvenční sken nebo řazení. Celé názvosloví je v článku EXPLAIN ANALYZE: jak číst plány dotazů v Postgres; tento příspěvek tě jen dovede ke správnému dotazu.
Používej hodnoty, které odpovídají produkci. Plán pro customer_id = 1 se může lišit od plánu pro zákazníka se dvěma miliony řádků a plánovač řízený statistikami zvolí jinak. Obvyklé opravy vyplývají z toho, co plán ukazuje:
- Sekvenční sken velké tabulky se selektivním filtrem ukazuje na chybějící index; indexy v PostgreSQL: typy, pořadí a cena se věnuje pořadí sloupců a částečným indexům.
- Velmi vysoké
Rows Removed by Filterznamená, že index existuje, ale filtru neodpovídá. - Odhad daleko od skutečného počtu řádků znamená zastaralé statistiky: spusť
ANALYZE tablename;. - Tabulka, která vyrostla na mnohonásobek potřebné velikosti, když vacuum zaostává, zpomaluje každý sken; viz vacuum, bloat a autovacuum v Postgres.
Po změně resetuj ten jeden queryid (nebo si nejdřív pořiď snímek), nech běžet provoz a porovnej mean_exec_time. Oprava, kterou jsi potom neověřil v pg_stat_statements, je jen domněnka.
Živé dotazy: pg_stat_activity#
pg_stat_statements je historie. Na to, co se děje právě teď, třeba zaseknutá stránka nebo skokový počet spojení, použij pg_stat_activity:
SELECT pid, usename, state, wait_event_type, wait_event, now() - query_start AS runtime, left(query, 80) AS queryFROM pg_stat_activityWHERE state <> 'idle' AND pid <> pg_backend_pid()ORDER BY runtime DESC;První, co čti, je sloupec state. active běží právě teď; idle in transaction znamená, že klient otevřel transakci a nic nedělá, což drží zámky a brání vacuum v úklidu. Dlouhý seznam relací idle in transaction je chyba aplikace, ne databáze. wait_event_type s hodnotou Lock znamená, že dotaz čeká ve frontě za jiným, a pg_blocking_pids(pid) vrátí, kdo ho drží.
K zastavení uprchlého dotazu SELECT pg_cancel_backend(pid); zruší aktuální dotaz a ponechá spojení; pg_terminate_backend(pid) ukončí celou relaci. Nejdřív zkus první z nich. Od PostgreSQL 14 odpovídá pg_stat_activity.query_id hodnotě pg_stat_statements.queryid, takže vidíš, jak se dotaz běžící právě teď choval v minulosti:
SELECT a.pid, now() - a.query_start AS runtime, s.calls, s.mean_exec_timeFROM pg_stat_activity aJOIN pg_stat_statements s ON s.queryid = a.query_idWHERE a.state = 'active';Pozor, pg_stat_activity.query se ořezává na track_activity_query_size, ve výchozím stavu 1024 bajtů. Generovaný dotaz s obřím seznamem v IN se tam usekne a ke zvýšení limitu je potřeba restart.
Doplňky: log_min_duration_statement a auto_explain#
Statistický pohled je agregovaný, takže skrývá jednotlivé události. Mezeru vyplňují dva nástroje, které se navzájem doplňují.
`log_min_duration_statement` zapisuje do logu serveru každý příkaz pomalejší než práh, včetně skutečných hodnot parametrů:
ALTER SYSTEM SET log_min_duration_statement = '500ms';SELECT pg_reload_conf();Stačí reload, ne restart. Nic nestojí, dokud nic není pomalé, a odpovídá na otázku, kterou pohled nezodpoví: která přesná hodnota to zpomalila a kdy. Hodnotu 0 použij jen nakrátko, protože loguje všechno. Pokud je log na hostingu, který zvládneš číst jen přes konzoli, mírný práh jako 500 ms nebo 1 s ho udrží čitelný.
`auto_explain` jde o krok dál a loguje samotný plán pomalých příkazů, čímž zachytí plán, který se pokazí jen občas. Načítá se stejně jako pg_stat_statements, v shared_preload_libraries (nebo session_preload_libraries), a nastavuje se takto:
shared_preload_libraries = 'pg_stat_statements,auto_explain'auto_explain.log_min_duration = '1s'auto_explain.log_analyze = offauto_explain.log_buffers = offauto_explain.log_nested_statements = offlog_analyze nech vypnuté, dokud nepotřebuješ skutečné časy: zapnutí instrumentuje každý příkaz, i rychlý, a může citelně zpomalit vytíženou databázi. Superuživatel může také spustit LOAD 'auto_explain'; a nastavit parametry pro jednu relaci, aby to vyzkoušel bez restartu. Pravidlo pro rozhodování: pg_stat_statements říká, na co se podívat, log_min_duration_statement říká, kdy a s jakými hodnotami, auto_explain říká, jaký plán byl zvolen. Uživatelé MySQL prostřední z nich poznají z slow query logu v MySQL.
Poznámka k tomu, jak to udržet jako zdravý zvyk: jednou týdně vyber pětici nejhorších podle celkového času a pětici nejhorších podle průměrného času s calls >= 20. Pokud se stejná jména objeví i za měsíc, oprava nedopadla. O tom, jak z takových čísel udělat něco, na co se opravdu díváš, je monitoring, který ti něco řekne.
Oprávnění: kdo co vidí#
Ve výchozím stavu role vidí plný text a statistiky jen u vlastních příkazů. U řádků jiných uživatelů ukáže pg_stat_statements statistiky, ale text nahradí hodnotou <insufficient privilege> a skryje sloupec queryid. Superuživatelé vidí všechno. Pro ostatní je čisté řešení vestavěná role pg_read_all_stats, dostupná od PostgreSQL 10:
GRANT pg_read_all_stats TO monitoring_user;Dává právo čtení statistických pohledů, včetně pg_stat_statements a dotazů ostatních relací v pg_stat_activity, bez přístupu k datům, takže je to správné oprávnění pro dashboard nebo inženýra, který nemá číst obsah tabulek. Resetování je samostatné: pg_stat_statements_reset() smí spustit jen superuživatel, dokud nedáš GRANT EXECUTE, a CREATE EXTENSION také vyžaduje dostatečná práva. Jak takovou roli sestavit správně, popisuje role a oprávnění v PostgreSQL.
Text dotazu prozrazuje tvé schéma a zátěž i bez konstant, takže s přístupem k pohledu podle toho zacházej a rozmysli se, než ho dáš nástrojům třetích stran.
Použití na hostované databázi#
Na spravované nebo hostované službě PostgreSQL se část o nastavení na tebe nemusí vztahovat. Časté jsou tři situace: rozšíření je už zapnuté a stačí ti dotazy výše; rozšíření je k dispozici a chybí jen CREATE EXTENSION, které běžný vlastník databáze smět spustit může, ale nemusí; nebo je konfigurace na úrovni serveru věcí poskytovatele a nemůžeš na ni sáhnout.
U PostgreSQL řady RE:NODE, která začíná na $6 měsíčně, je zdokumentováno, že přihlašovací údaje se generují pro každý server a připojuješ se na hostitele a port svého plánu. Nic z toho neuvádí, jestli je shared_preload_libraries upravitelné ani která rozšíření jsou k dispozici. Praktický postup je tedy tento:
- Připoj se přes
psqla spusť tři kontroly z dřívější části. - Pokud je
pg_stat_statementsnainstalované a pohled odpovídá, použij ho podle návodu. - Pokud není, zeptej se podpory přes ticket z panelu, uveď rozšíření a k čemu ho chceš. Jestli jde na tvé instanci zapnout, je na nich.
- Zatím fungují bez jakéhokoli nastavení
pg_stat_activitya kumulativní pohledy jakopg_stat_user_tablesaEXPLAIN (ANALYZE, BUFFERS)nepotřebuje vůbec nic.
Pokud se ti podaří získat log, další nejužitečnější věcí je práh na log_min_duration_statement. Pokud nezískáš ani jedno, spouštěj podezřele pomalé dotazy z vlastního kódu pod EXPLAIN v transakci, kterou vrátíš, a přidej kolem nich měření času v aplikaci. Je to pomalejší než pohled, ale najde stejné dotazy.
FAQ#
Zpomaluje pg_stat_statements databázi?
Mírně. Cenou je malá, pevná režie na příkaz za hashování a aktualizaci sdílených čítačů, kterou je u většiny zátěží těžké změřit. Těžší jsou nastavení track_planning a auto_explain.log_analyze, takže je nech vypnutá, dokud je nepotřebuješ. Provozovat pg_stat_statements v produkci trvale je běžná praxe.
Proč se v textu dotazu místo hodnoty zobrazuje $1?
Protože rozšíření normalizuje příkazy tak, aby varianty stejného dotazu sdílely jeden řádek. Hodnoty se záměrně neuchovávají. Chceš-li najít hodnotu, která byla pomalá, nastav log_min_duration_statement nebo použij auto_explain. Aplikace, které posílají hodnoty přímo v textu místo bind parametrů, se normalizují také; odstranění probíhá uvnitř serveru.
Proč je pohled po CREATE EXTENSION prázdný nebo hlásí chybu?
Buď knihovna není v shared_preload_libraries, nebo se server po jejím přidání nerestartoval. SHOW shared_preload_libraries; ukáže, co je teď načteno. Chybová zpráva pg_stat_statements must be loaded via "shared_preload_libraries" znamená přesně tohle. Prázdný pohled u načteného rozšíření jen znamená, že od posledního resetu nic neproběhlo.
Mám řadit podle celkového, nebo průměrného času?
Začni celkovým časem, protože ukazuje, co server stojí nejvíc celkově a kde se oprava vyplatí. Průměrný čas, filtrovaný přes calls >= 20, použij, když si někdo stěžuje, že jedna konkrétní stránka je pomalá. Odpovídají na různé otázky a budeš se dívat na obě.
Funguje to na MySQL, MongoDB nebo SQL Serveru?
Ne, je to jen pro PostgreSQL. MySQL má slow query log a digest tabulky v performance_schema; SQL Server má Query Store, popsaný v článku SQL Server Query Store a pomalé dotazy. Myšlenka je všude stejná: agreguj podle normalizovaného příkazu, řaď podle celkové ceny a opravuj vrchol seznamu.
Jak poznám, který queryid patří ke které tabulce?
Hledej v textu: WHERE query ILIKE '%orders%'. queryid je hash zpracovaného příkazu a sám o sobě žádnou informaci o tabulce nenese. Pro všechny příkazy nad jednou tabulkou za určité období filtruj podle textu, sečti total_exec_time a porovnej s čítači skenů tabulky v pg_stat_user_tables.


