Výkon je jedním z nejdůležitějších a nejsložitějších úkolů při správě databáze. Může to být ovlivněno konfigurací, hardwarem nebo dokonce designem systému. Ve výchozím nastavení je PostgreSQL nakonfigurován s ohledem na kompatibilitu a stabilitu, protože výkon hodně závisí na hardwaru a na našem systému samotném. Můžeme mít systém s velkým množstvím dat, které se čte, ale informace se často nemění. Nebo můžeme mít systém, který zapisuje nepřetržitě. Z tohoto důvodu není možné definovat výchozí konfiguraci, která by fungovala pro všechny typy úloh.
V tomto blogu uvidíme, jak se postupuje při analýze pracovní zátěže nebo dotazů, které běží. Poté zkontrolujeme některé základní konfigurační parametry, abychom zlepšili výkon naší PostgreSQL databáze. Jak jsme zmínili, uvidíme jen některé parametry. Výčet parametrů PostgreSQL je obsáhlý, dotkli bychom se pouze některých klíčových. Vždy však lze nahlédnout do oficiální dokumentace a ponořit se do parametrů a konfigurací, které se v našem prostředí zdají nejdůležitější nebo nejužitečnější.
EXPLAIN
Jedním z prvních kroků, které můžeme udělat, abychom porozuměli tomu, jak zlepšit výkon naší databáze, je analyzovat dotazy, které jsou provedeny.
PostgreSQL navrhuje plán dotazů pro každý dotaz, který obdrží. K zobrazení tohoto plánu použijeme EXPLAIN.
Struktura plánu dotazů je strom uzlů plánu. Uzly v nižší úrovni stromu jsou uzly skenování. Vracejí nezpracované řádky z tabulky. Existují různé typy skenovacích uzlů pro různé způsoby přístupu k tabulce. Výstup EXPLAIN má řádek pro každý uzel ve stromu plánu.
world=# EXPLAIN SELECT * FROM city t1,country t2 WHERE id>100 AND t1.population>700000 AND t2.population<7000000;
QUERY PLAN
--------------------------------------------------------------------------
Nested Loop (cost=0.00..734.81 rows=50662 width=144)
-> Seq Scan on city t1 (cost=0.00..93.19 rows=347 width=31)
Filter: ((id > 100) AND (population > 700000))
-> Materialize (cost=0.00..8.72 rows=146 width=113)
-> Seq Scan on country t2 (cost=0.00..7.99 rows=146 width=113)
Filter: (population < 7000000)
(6 rows)
Tento příkaz ukazuje, jak budou skenovány tabulky v našem dotazu. Podívejme se, čemu odpovídají tyto hodnoty, které můžeme pozorovat v našem EXPLAIN.
- První parametr ukazuje operaci, kterou motor provádí s daty v tomto kroku.
- Odhadované počáteční náklady. Toto je čas strávený před zahájením výstupní fáze.
- Odhadované celkové náklady. To je uvedeno za předpokladu, že uzel plánu je dokončen. V praxi se může stát, že nadřazený uzel uzlu přestane číst všechny dostupné řádky.
- Odhadovaný počet výstupů řádků tímto uzlem plánu. Opět se předpokládá, že uzel je spuštěn až do konce.
- Odhadovaná průměrná šířka výstupů řádků tímto uzlem plánu.
Nejkritičtější částí zobrazení jsou odhadované náklady na provedení příkazu, což je odhad plánovače, jak dlouho bude trvat spuštění příkazu. Při porovnávání toho, jak efektivní je jeden dotaz proti druhému, budeme v praxi porovnávat jejich nákladové hodnoty.
Je důležité pochopit, že náklady na uzel vyšší úrovně zahrnují náklady na všechny jeho podřízené uzly. Je také důležité si uvědomit, že náklady odrážejí pouze věci, na kterých plánovači záleží. Zejména náklady nezohledňují čas strávený předáváním řádků výsledků klientovi, což může být důležitým faktorem v reálném uplynulém čase; ale plánovač to ignoruje, protože to nemůže změnit změnou plánu.
Náklady jsou měřeny v libovolných jednotkách určených nákladovými parametry plánovače. Tradiční praxí je měřit náklady v jednotkách načtení stránky na disku; to znamená, že seq_page_cost je konvenčně nastavena na 1.0 a ostatní parametry nákladů jsou nastaveny relativně k této hodnotě.
EXPLAIN ANALYZE
S touto volbou EXPLAIN provede dotaz a poté zobrazí skutečné počty řádků a skutečnou dobu běhu nashromážděnou v každém uzlu plánu spolu se stejnými odhady, které zobrazuje prostý EXPLAIN.
Podívejme se na příklad použití tohoto nástroje.
world=# EXPLAIN ANALYZE SELECT * FROM city t1,country t2 WHERE id>100 AND t1.population>700000 AND t2.population<7000000;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------
Nested Loop (cost=0.00..734.81 rows=50662 width=144) (actual time=0.081..22.066 rows=51100 loops=1)
-> Seq Scan on city t1 (cost=0.00..93.19 rows=347 width=31) (actual time=0.069..0.618 rows=350 loops=1)
Filter: ((id > 100) AND (population > 700000))
Rows Removed by Filter: 3729
-> Materialize (cost=0.00..8.72 rows=146 width=113) (actual time=0.000..0.011 rows=146 loops=350)
-> Seq Scan on country t2 (cost=0.00..7.99 rows=146 width=113) (actual time=0.007..0.058 rows=146 loops=1)
Filter: (population < 7000000)
Rows Removed by Filter: 93
Planning time: 0.136 ms
Execution time: 24.627 ms
(10 rows)
Pokud nenajdeme důvod, proč naše dotazy trvají déle, než by měly, můžeme se podívat na tento blog, kde najdete další informace.
VAKUUM
Proces VACUUM je zodpovědný za několik úkolů údržby v rámci databáze, jeden z nich obnovuje úložiště obsazené mrtvými n-ticemi. Při normálním provozu PostgreSQL nejsou n-tice, které jsou odstraněny nebo zastaralé aktualizací, fyzicky odstraněny z jejich tabulky; zůstávají přítomny, dokud není provedeno VAKUUM. Proto je nutné provádět VAKUUM pravidelně, zejména v často aktualizovaných tabulkách.
Pokud VYSÁVÁNÍ zabírá příliš mnoho času nebo zdrojů, znamená to, že to musíme dělat častěji, aby každá operace měla méně úklidu.
V každém případě může být nutné vypnout VACUUM, například při načítání dat ve velkém množství.
VACUUM jednoduše obnoví prostor a zpřístupní jej pro opětovné použití. Tato forma příkazu může fungovat paralelně s normálním čtením a zápisem do tabulky, protože není získán výhradní zámek. Dodatečné místo však není vráceno operačnímu systému (ve většině případů); je k dispozici pouze pro opětovné použití v rámci stejné tabulky.
VACUUM FULL přepíše veškerý obsah tabulky na nový diskový soubor bez dalšího místa, což umožňuje návrat nevyužitého místa do operačního systému. Tento formulář je mnohem pomalejší a vyžaduje při zpracování exkluzivní zámek na každé tabulce.
VACUUM ANALYZE provede VACUUM a poté ANALYZE pro každý vybraný stůl. Toto je praktický způsob, jak kombinovat skripty běžné údržby.
ANALYZE shromažďuje statistické údaje o obsahu tabulek v databázi a ukládá výsledky do pg_statistic. Následně plánovač dotazů použije tyto statistiky k určení nejúčinnějších plánů provádění pro dotazy.
Stáhněte si Whitepaper Today Správa a automatizace PostgreSQL s ClusterControlZjistěte, co potřebujete vědět k nasazení, monitorování, správě a škálování PostgreSQLStáhněte si WhitepaperKonfigurační parametry
Pro úpravu těchto parametrů musíme upravit soubor $ PGDATA / postgresql.conf. Musíme mít na paměti, že některé z nich vyžadují restart naší databáze.
max_connections
Určuje maximální počet současných připojení k naší databázi. Existují paměťové zdroje, které lze konfigurovat na klienta, takže maximální počet klientů může navrhnout maximální množství použité paměti.
superuser_reserved_connections
V případě dosažení limitu max_connection jsou tato připojení rezervována pro superuživatele.
shared_buffers
Nastavuje množství paměti, kterou databázový server používá pro vyrovnávací paměti sdílené paměti. Pokud máte vyhrazený databázový server s 1 GB nebo více paměti RAM, rozumná počáteční hodnota pro shared_buffers je 25 % paměti vašeho systému. Větší konfigurace pro shared_buffers obecně vyžadují odpovídající zvýšení max_wal_size, aby se prodloužil proces zápisu velkého množství nových nebo upravených dat po delší časové období.
temp_buffers
Nastavuje maximální počet dočasných vyrovnávacích pamětí použitých pro každou relaci. Jedná se o místní vyrovnávací paměti relací používané pouze pro přístup k dočasným tabulkám. Relace přiřadí dočasné buffery podle potřeby až do limitu daného temp_buffers.
work_mem
Určuje množství paměti, které bude využito vnitřními operacemi tabulek ORDER BY, DISTINCT, JOIN a hash před zápisem do dočasných souborů na disk. Při konfiguraci této hodnoty musíme vzít v úvahu, že tyto operace provádí několik relací současně a každá operace bude mít povoleno použít tolik paměti, kolik určuje tato hodnota, než začne zapisovat data do dočasných souborů.
Tato možnost se ve starších verzích PostgreSQL nazývala sort_mem.
maintenance_work_mem
Určuje maximální množství paměti, kterou budou používat operace údržby, jako je VACUUM, CREATE INDEX a ALTER TABLE ADD FOREIGN KEY. Vzhledem k tomu, že v relaci může být současně provedena pouze jedna z těchto operací a instalace obvykle nemá mnoho spuštěných současně, může být větší než work_mem. Větší konfigurace mohou zlepšit výkon pro VACUUM a obnovu databáze.
Když je autovacuum spuštěno, lze této paměti přiřadit, kolikrát je nakonfigurován parametr autovacuum_max_workers, takže to musíme vzít v úvahu, nebo jinak nakonfigurovat parametr autovacuum_work_mem, aby to spravoval samostatně.
fsync
Pokud je fsync povoleno, PostgreSQL se pokusí zajistit, aby byly aktualizace fyzicky zapsány na disk. To zajišťuje, že databázový klastr lze obnovit do konzistentního stavu po zhroucení operačního systému nebo hardwaru.
I když deaktivace fsync obecně zlepšuje výkon, může způsobit ztrátu dat v případě výpadku napájení nebo zhroucení systému. Proto je vhodné deaktivovat fsync pouze tehdy, pokud můžete snadno znovu vytvořit celou databázi z externích dat.
segmenty kontrolních bodů (PostgreSQL <9.5)
Maximální počet segmentů souboru záznamu mezi automatickými kontrolními body WAL (každý segment je normálně 16 megabajtů). Zvýšení tohoto parametru může prodloužit dobu potřebnou k obnově chyb. V systému s velkým provozem může mít vliv na výkon, pokud je nastavena na velmi nízkou hodnotu. Doporučuje se zvýšit hodnotu checkpoint_segments na systémech s mnoha úpravami dat.
Osvědčeným postupem je také uložit soubory WAL na jiný disk než PGDATA. To je užitečné jak pro vyvážení zápisu, tak pro zabezpečení v případě selhání hardwaru.
Od PostgreSQL 9.5 byla konfigurační proměnná "checkpoint_segments" odstraněna a byla nahrazena "max_wal_size" a "min_wal_size"
max_wal_size (PostgreSQL>=9.5)
Maximální velikost, kterou může WAL narůst mezi kontrolními body. Velikost WAL může za zvláštních okolností překročit max_wal_size. Zvýšení tohoto parametru může prodloužit dobu potřebnou k obnově chyb.
min_wal_size (PostgreSQL>=9.5)
Když je soubor WAL udržován pod touto hodnotou, je místo odstranění recyklován pro budoucí použití v kontrolním bodě. Toho lze využít k zajištění toho, aby bylo vyhrazeno dostatek prostoru WAL pro zvládnutí špiček při používání WAL, například při provádění velkých dávkových úloh.
wal_sync_method
Metoda používaná k vynucení aktualizací WAL na disku. Pokud je fsync zakázáno, toto nastavení nemá žádný účinek.
wal_buffers
Množství sdílené paměti použité pro data WAL, která ještě nebyla zapsána na disk. Výchozí nastavení je asi 3 % sdílených_bufferů, ne méně než 64 kB nebo více než velikost segmentu WAL (obvykle 16 MB). Nastavení této hodnoty na alespoň několik MB může zlepšit výkon zápisu na serveru s mnoha souběžnými transakcemi.
effective_cache_size
Tuto hodnotu používá plánovač dotazů k zohlednění plánů, které se mohou nebo nemusí vejít do paměti. To je zohledněno v odhadech nákladů na použití indexu; vysoká hodnota zvyšuje pravděpodobnost použití indexových skenů a nízká hodnota zvyšuje pravděpodobnost, že budou použita sekvenční skenování. Rozumná hodnota by byla 50 % paměti RAM.
default_statistics_target
PostgreSQL shromažďuje statistiky z každé tabulky ve své databázi, aby rozhodl, jak se na ně budou provádět dotazy. Ve výchozím nastavení neshromažďuje příliš mnoho informací, a pokud nedostáváte dobré plány provádění, měli byste tuto hodnotu zvýšit a poté znovu spustit ANALYZE v databázi (nebo počkat na AUTOVACUUM).
synchronous_commit
Určuje, zda potvrzení transakce počká na zapsání záznamů WAL na disk, než příkaz vrátí klientovi indikaci „úspěchu“. Možné hodnoty jsou:"on", "remote_apply", "remote_write", "local" a "off". Výchozí nastavení je "zapnuto". Když je deaktivována, může dojít k prodlevě mezi okamžikem, kdy se klient vrátí, a okamžikem, kdy je zaručeno, že transakce bude zabezpečena proti uzamčení serveru. Na rozdíl od fsync nevytváří deaktivace tohoto parametru žádné riziko nekonzistence databáze:pád operačního systému nebo databáze může mít za následek ztrátu některých nedávných transakcí, které byly údajně provedeny, ale stav databáze bude úplně stejný, jako kdyby tyto transakce byla čistě zrušena. Proto může být deaktivace synchronous_commit užitečnou alternativou, když je výkon důležitější než přesná jistota trvanlivosti transakce.
Protokolování
Existuje několik typů dat k protokolování, která mohou být užitečná nebo ne. Podívejme se na některé z nich:
- log_min_error_statement:Nastavuje minimální úroveň protokolování.
- log_min_duration_statement:Používá se k záznamu pomalých dotazů v systému.
- log_line_prefix:Zachycuje informace na začátku každého řádku protokolu.
- log_statement:Můžete si vybrat mezi NONE, DDL, MOD, ALL. Použití „vše“ může způsobit problémy s výkonem.
Design
V mnoha případech může návrh naší databáze ovlivnit výkon. Při návrhu musíme být opatrní, normalizovat naše schéma a vyhýbat se nadbytečným datům. V mnoha případech je vhodné mít několik malých stolů místo jednoho velkého stolu. Ale jak jsme řekli dříve, vše závisí na našem systému a neexistuje jediné možné řešení.
Indexy musíme také používat zodpovědně. Neměli bychom vytvářet indexy pro každé pole nebo kombinaci polí, protože i když nemusíme procházet celou tabulku, využíváme místo na disku a přidáváme režii k operacím zápisu.
Dalším velmi užitečným nástrojem je správa fondu připojení. Pokud máme systém s velkým zatížením, můžeme toho využít, abychom se vyhnuli zahlcení spojení v databázi a mohli je znovu použít.
Hardware
Jak jsme již zmínili na začátku tohoto blogu, hardware je jedním z důležitých faktorů, které přímo ovlivňují výkon naší databáze. Podívejme se na několik bodů, které je třeba mít na paměti.
- Paměť:Čím více RAM máme, tím více paměťových dat dokážeme zpracovat, a to znamená lepší výkon. Rychlost zápisu a čtení na disku je mnohem nižší než v paměti, takže čím více informací můžeme mít v paměti, tím lepší výkon budeme mít.
- CPU:Možná to nedává moc smysl říkat, ale čím více CPU máme, tím lépe. V každém případě to není nejdůležitější z hlediska hardwaru, ale pokud budeme mít dobrý CPU, zlepší se naše kapacita zpracování a to přímo ovlivní naši databázi.
- Pevný disk:Máme několik typů disků, které můžeme použít, SCSI, SATA, SAS, IDE. Máme také SSD disky. Musíme porovnávat kvalita / cena, kterou bychom měli použít pro srovnání její rychlosti. Typ disku ale není jediná věc, kterou je třeba zvážit, musíme se také podívat, jak je nakonfigurovat. Pokud chceme dobrý výkon, můžeme použít RAID10 a ponechat WAL na jiném disku mimo RAID. Nedoporučuje se používat RAID5, protože výkon tohoto typu RAID pro databáze není dobrý.
Závěr
Po zohlednění bodů zmíněných v tomto blogu můžeme provést benchmark pro ověření chování databáze.
Je také důležité mít naši databázi monitorovanou, abychom zjistili, zda nečelíme problému s výkonem, a abychom jej mohli co nejdříve vyřešit. Pro tento úkol existuje několik nástrojů, jako jsou mimo jiné Nagios, ClusterControl nebo Zabbix, které nám umožňují nejen monitorovat, ale s některými z nich nám umožňují podniknout proaktivní akci dříve, než problém nastane. S ClusterControl můžeme kromě monitorování, správy a několika dalších utilit dostávat doporučení, jaká opatření můžeme podniknout, když dostáváme upozornění na výkon. To nám umožňuje mít představu o tom, jak řešit potenciální problémy.
Tento blog nemá být vyčerpávajícím průvodcem, jak zlepšit výkon databáze. Doufejme, že poskytuje jasnější obrázek o tom, jaké věci se mohou stát důležitými a některé základní parametry, které lze konfigurovat. Neváhejte a dejte nám vědět, pokud jsme nějaké důležité vynechali.