Zjistit, proč dotaz, který si vede dobře při vývoji a testování, vybuchne v produkci, může být někdy problém. Čtěte dále a zjistěte více o několika funkcích, které mohou poskytnout přehled o tom, jak si vaše dotazy vedou v produkci.
Aktuálně spuštěné dotazy
Když se klient připojí k serveru PostgreSQL, hlavní proces serveru Postgres (historicky nazývaný postmaster ) vytvoří nový proces (nazývanýbackend). ) pro obsluhu dotazů klienta. Každý backend proto buď čeká, až jeho klient odešle dotaz, nebo se pokusí nějaký provést.
Systémové zobrazení pg_stat_activity zobrazuje informace o každém aktuálně spuštěném backendu. Zejména zobrazuje dotaz, který backend aktuálně provádí, pokud je aktivní, nebo poslední dotaz, který provedl, pokud čeká, až klient odešle další dotaz.
Zde jsou dva backendy obsluhující klienty připojené k databázi testdb
, přičemž oba aktivně provádějí své dotazy:
testdb=# select usename,datname,state,query from pg_stat_activity where datname='testdb';
-[ RECORD 1 ]-----------------------------------------------------------------------------
usename | postgres
datname | testdb
state | active
query | SELECT pg_sleep(10);
-[ RECORD 2 ]-----------------------------------------------------------------------------
usename | postgres
datname | testdb
state | active
query | select usename,datname,state,query from pg_stat_activity where datname='testdb';
Někdy může dotaz čekat na zámek, a to také ukazuje inpg_stat_activity. Zde můžete vidět INSERT čekající na zámek vztahu:
testdb=# select wait_event_type, wait_event, left(query, 60) from pg_stat_activity where datname='testdb';
-[ RECORD 1 ]---+-------------------------------------------------------------
wait_event_type | Client
wait_event | ClientRead
left | lock table t in access exclusive mode;
-[ RECORD 2 ]---+-------------------------------------------------------------
wait_event_type |
wait_event |
left | select wait_event_type, wait_event, left(query, 60) from pg_
-[ RECORD 3 ]---+-------------------------------------------------------------
wait_event_type | Lock
wait_event | relation
left | insert into t values (1);
Další informace o pg_stat_activity naleznete v dokumentaci.
I když je toto zobrazení užitečné pro pochopení toho, co Postgres aktuálně dělá, neposkytuje informace o statistikách provádění dotazů ani informace o dotazech, které byly dokončeny.
Všechny dotazy spuštěné v minulosti
K tomu slouží rozšíření pg_stat_statements je neocenitelný. Toto rozšíření je součástí základní distribuce PostgreSQL a je také dostupné ve spravovaných službách, jako je AWS RDS a GCP SQL.
pg_stat_statements (PSS) je „rozšíření“ v podmínkách PostgreSQL a je třeba jej nejprve nainstalovat:
- Prostudujte si dokumentaci k distribuci Linuxu a zjistěte, zda je rozšíření předinstalováno nebo zda vyžaduje instalaci jiného balíčku. Například na Centos 7 budete muset
sudo yum install postgresql-contrib
. - Upravte hlavní konfigurační soubor postgresql.conf (obvykle pod
/etc
, jako je/etc/postgresql/10/main/postgresql.conf
v Debianu) a změňte hodnotushared_preload_libraries
na „pg_stat_statements“. Toto je čárkou oddělený seznam hodnot, takže pokud tam již něco je, připojte čárku a poté „pg_stat_statements“. - U AWS RDS budete muset upravit aktivní skupinu parametrů a nastavit hodnotu.
- Po úpravě „shared_preload_libraries“ budete muset restartovat démona PostgreSQL. Bohužel to nejde nijak obejít. Na AWS RDS budete muset restartovat instanci RDS.
- Po restartu by PostgreSQL server načetl sdílenou knihovnu a rozšíření můžeme nainstalovat spuštěním
CREATE EXTENSION pg_stat_statements
. Ke spuštění tohoto příkazu musíte být superuživatel. - Rozšíření můžete ve skutečnosti nainstalovat do jakékoli databáze a přesto uvidíte dotazy ve všech databázích.
Jakmile je rozšíření nainstalováno, můžete se dotazovat na zobrazení s názvem pg_stat_statements
získat informace o každém jednotlivém dotazu provedeném od instalace rozšíření.
Čísla, jako je doba potřebná k provedení dotazu, se kumulují jako součet. Pouze pro dobu provádění dotazu jsou uvedeny některé statistiky (průměr, min, max, směrodatná odchylka). Tyto hodnoty lze vymazat pomocí funkcepg_stat_statements_reset
.
Zde je návod na řádek z pg_stat_statements
vypadá takto:
testdb=# select * from pg_stat_statements where query like '%pg_sleep%' and dbid=42548;
-[ RECORD 1 ]-------+--------------------
userid | 10
dbid | 42548
queryid | 2649515222348904837
query | SELECT pg_sleep($1)
calls | 1
total_time | 10016.782625
min_time | 10016.782625
max_time | 10016.782625
mean_time | 10016.782625
stddev_time | 0
rows | 1
shared_blks_hit | 0
shared_blks_read | 0
shared_blks_dirtied | 0
shared_blks_written | 0
local_blks_hit | 0
local_blks_read | 0
local_blks_dirtied | 0
local_blks_written | 0
temp_blks_read | 0
temp_blks_written | 0
blk_read_time | 0
blk_write_time | 0
Kromě identifikačních parametrů (uživatel, databáze, dotaz) můžete o svém dotazu zjistit mnoho zajímavých věcí:
- Jak dlouho obvykle trvá spuštění (
mean_time
) - Kolik řádků v průměru vrátí (
rows
/calls
) - Množství dat načtených ze sdílené mezipaměti a množství dat načtených z disku (
shared_blks_read
zobrazuje celkové množství dat, která dotaz přečetl, z tohoshared_blks_hit
pochází z mezipaměti) - Množství dat, které bylo nutné zapsat na disk synchronně kvůli tlaku mezipaměti (
shared_blks_written
) - Množství zapsaných dat jako počet bloků, kterých se dotknete (
shared_blks_dirtied
) - Množství času stráveného čtením a zápisem na disku (
blk_{read,write}_time
) - Dočasné soubory zapisované do a čtené z (
temp_blks_{read,written}
) - Dočasné tabulky zapisované do a čtené z (
local_*
)
Časy čtení a zápisu disku jsou dostupné pouze v případě, že je konfigurační parametrtrack_io_timing
je zapnuto. Ve výchozím nastavení není. Na většině moderních linuxových systémů by mělo být v pořádku tento parametr zapnout. Přečtěte si více.
Vyplatí se pořídit snímek pg_stat_statements
data nepřetržitě v pravidelných intervalech, abyste viděli, jak se tyto parametry vyvíjejí na základě jednotlivých dotazů. Nástroj pgmetrics s otevřeným zdrojovým kódem dokáže extrahovat a odhalit pg_stat_statements
data jako JSON pro snazší automatizaci.
Dotazy spuštěné v určitém časovém rozsahu
Jakmile takový systém zavedete, bude snadné sledovat dotazy provedené v daném časovém rámci. To usnadňuje ladění problémů, jako je důvod, proč noční dávková úloha trvala déle, než se očekávalo.
Odečtením počítadel mezi dvěma danými časovými razítky můžete zjistit většinu čísel jako dříve, s výjimkou min, max a směrodatné odchylky. To stačí k identifikaci dotazů, které byly provedeny v daném časovém rozsahu, a zdrojů, které spotřebovaly.
Protokolování pomalých dotazů
Dalším způsobem, jak rychle identifikovat dotazy, které zabírají více času, než se očekávalo, je zapnout protokolování příkazů. Můžete zadat prahovou dobu trvání, a pokud dokončení dotazu trvá déle, bude protokolován. (V běžném souboru protokolu PostgreSQL není žádný samostatný soubor pro pomalé dotazy.)
Chcete-li tuto funkci zapnout, upravte konfiguraci následovně:
log_min_duration_statement = 1000 # in milliseconds
a znovu načíst Postgres. Můžete také použít ALTER SYSTEM
:
ALTER SYSTEM SET log_min_duration_statement = 1000; -- in milliseconds
Díky tomu se zaprotokoluje jakýkoli příkaz (včetně těch bez DML), jehož dokončení trvá déle než sekundu:
2019-12-02 16:57:05.727 UTC [8040] postgres@testdb LOG: duration: 10017.862 ms statement: SELECT pg_sleep(10);
Zaznamenává se skutečný čas dotazu i celý text SQL.
Pokud máte systém monitorování protokolů a můžete sledovat počet pomalých dotazů za hodinu / den, může to sloužit jako dobrý indikátor výkonu aplikace.
Plány provádění dotazů
Jakmile najdete dotaz, který by podle vás měl běžet rychleji, dalším krokem je podívat se na jeho plán dotazů. Obvykle potřebujete skutečný plán dotazů z produkčních serverů, se kterým budete pracovat. Pokud jste schopni spouštět EXPLAIN na produkčních serverech tak skvěle, jinak se musíte spolehnout na auto_explain
.
auto_explain
je další základní rozšíření PostgreSQL, buď již nainstalované, nebo dostupné jako balíček „contrib“ pro vaši distribuci. Je také k dispozici na AWSRDS. auto_explain
je o něco jednodušší na instalaci než pg_stat_statements
:
- Upravte konfiguraci postgres (nebo skupinu parametrů RDS)
shared_preload_libraries
zahrnoutauto_explain
. - Nemusíte však restartovat Postgres, můžete místo toho spustit:
LOAD 'auto_explain';
. - Budete chtít nakonfigurovat jeho nastavení, alespoň toto:
auto_explain.log_min_duration = 1000 # seconds
V podstatě vždy, když dotaz trvá déle než auto_explain.log_min_duration
počet sekund na dokončení, auto_explainlogs dotaz a jeho plán provádění dotazu v souboru protokolu, jako je tento:
2019-12-04 09:23:05.130 UTC [12823] postgres@testdb LOG: duration: 11025.765 ms plan:
Query Text: select pg_sleep(11);
Result (cost=0.00..0.01 rows=1 width=4) (actual time=11025.716..11025.718 rows=1 loops=1)
Output: pg_sleep('11'::double precision)
Pokud máte skripty, které jej dokážou zpracovat, může plán zaznamenat také ve formátu JSON:
2019-12-02 17:30:53.676 UTC [8040] postgres@testdb LOG: duration: 10000.230 ms plan:
{
"Query Text": "SELECT pg_sleep(10);",
"Plan": {
"Node Type": "Result",
"Parallel Aware": false,
"Startup Cost": 0.00,
"Total Cost": 0.01,
"Plan Rows": 1,
"Plan Width": 4,
"Actual Startup Time": 10000.205,
"Actual Total Time": 10000.206,
"Actual Rows": 1,
"Actual Loops": 1,
"Output": ["pg_sleep('10'::double precision)"],
"Shared Hit Blocks": 0,
"Shared Read Blocks": 0,
"Shared Dirtied Blocks": 0,
"Shared Written Blocks": 0,
"Local Hit Blocks": 0,
"Local Read Blocks": 0,
"Local Dirtied Blocks": 0,
"Local Written Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0,
"I/O Read Time": 0.000,
"I/O Write Time": 0.000
},
"Triggers": [
]
}
V Postgresu neexistuje jiný způsob než auto_explain, jak se podívat na plán provádění dotazu, který již byl proveden, díky čemuž je auto_explain důležitým nástrojem ve vaší sadě nástrojů.