⚠️ UPOZORNENIE: Tento článok sa čiastočne zaoberá nastaveniami servera Postgres. Pri práci s nimi je potrebné pochopiť, že zmena takýchto nastavení môže viesť k zlepšeniu aj zhoršeniu výkonu servera.
PostgreSQL využíva na svoju prácu dve vyrovnávacie pamäte, prvou z nich je zdieľaná vyrovnávacia pamäť - natívna vyrovnávacia pamäť PSQL pracujúca na princípe Clock Sweeo Angry. Druhým je vyrovnávacia pamäť OS - vyrovnávacia pamäť operačného systému. OS cache väčšinou funguje na princípe algoritmu Least Recent.
Hlavnou výhodou zdieľanej vyrovnávacej pamäte je, že napriek vyrovnávacej pamäti OS dokáže definovať, ktoré dáta sa používajú najčastejšie a uchovávať ich v pamäti oveľa dlhšie, a má skóre obľúbenosti od 1 do 5. Ak je skóre vyššie, tak sa dáta rýchlejšie odstránia z vyrovnávacej pamäte. To je dôvod, prečo sú dotazy, ktoré prechádzajú cez zdieľanú vyrovnávaciu pamäť, vždy lepšie obsluhované.
Hlavným problémom zdieľanej vyrovnávacej pamäte je, že je optimalizovaná len na to, aby server mohol bootovať na systéme s nízkymi HW požiadavkami. Predvolená hodnota pre zdieľanú vyrovnávaciu pamäť v postgresql.conf je 128 MB (názov parametra je shared_buffer ) Predpokladá sa, že je to jeden z najťažších parametrov na predpovedanie dobrej hodnoty. Ak je server pomalý, podľa zásady je dobré dať databáze 25% RAM (po zmene hodnoty je potrebné reštartovať psql server - ~$ sudo služba postgresql restart ).
Aby sme lepšie vedeli predpovedať hodnoty pre tento parameter sa odporúča použiť pgbench - je to jednoduchý program na spúšťanie benchmarkových testov na PostgreSQL. Spúšťa rovnakú sekvenciu príkazov SQL znova a znova vo viacerých súbežných databázových reláciách, a potom vypočíta priemernú rýchlosť transakcie (transakcie za sekundu).
Najprv musíme vytvoriť databázu väčšiu ako je zdieľaná vyrovnávacia pamäť a spustiť určité množstvo transakcií (v našom prípade 8 používateľov vykoná 25 000 transakcií):
~$ sudo -i -u postgres
~$ createdb test_buffers;
~$ pgbench -i -s 50 testovacích_bufferov;
~$ pgbench -S -c 8 -t 25000 testovacích_bufferov;
Teraz pomocou buffercache môžeme získať najväčší vzťah a niektoré ďalšie údaje inštaláciou rozšírenia buffercahce a spustením nasledujúceho SELECT:
Na obrázku „a“ môžeme vidieť, že tabuľka accounts a tabuľka accounts_pkey celkovo zaberajú takmer celú veľkosť zdieľanej vyrovnávacej pamäte, 119 MB, čo je viac ako 92 % celej zdieľanej vyrovnávacej pamäte. V stĺpci percent_of_relation je možné vidieť, že je veľmi dôležité, aby server uchovával tabuľku accounts_pkey v pamäti, napriek tomu, že tabuľka s účtami je uložená vo vyrovnávacej pamäti na 10,4 %, táto je uložená na 49,5 %. Po zvýšení veľkosti zdieľanej vyrovnávacej pamäte na 256 MB je možné vo výsledku „b“ vidieť, že tabuľka accounts_pkey má vyrovnávaciu pamäť na 89,7 %.
Druhý dotaz zobrazuje počet použití podľa vzťahu:
Usage counter môže povedať veľa o zdieľanej vyrovnávacej pamäti. Ak má väčšina vzťahov malý usage caounter, napríklad 0 alebo 1, pravdepodobne bude dobré zväčšiť veľkosť zdieľanej vyrovnávacej pamäte. Po zväčšení veľkosti zdieľanej vyrovnávacej pamäte môžeme na obrázku „b“ vidieť, že sa objavilo viac populárnych stránok a je lepšia rovnováha medzi nízkou a vysokou využívanosťou. Ak vidíme vysokú akumuláciu vyrovnávacích pamätí s počtom využitia, znamená to, že shared_buffer je celkom dobre optimalizovaný a ďalej sa zväčšuje, ak jeho veľkosť nepovedie k lepšiemu výkonu.
Rovnaký súbor údajov bol testovaný pomocou nasledujúceho príkazu: ~$ pgbench -S -c 50 -t 25000 test_buffers; Výsledkom bolo:
WAL writer (Write Ahead Logging Write) je mechanizmus, ktorý ukladá neuložené údaje. Všetky segmenty, ktoré sa odohrávajú na serveri, sa aj tak zaznamenávajú do segmentov WAL. Je tiež zodpovedný za:
Vypnutie WAL writera (názov parametra: fsync ) zvyšuje výkon DB najmä pri hromadných operáciách, ale vedie k takým problémom, ako je nekonzistentnosť údajov v prípade výpadku napájania alebo zlyhania.
Najdôležitejšie premenné na nastavenie sú:
Kontrolné body sú body v sekvencii transakcií, pri ktorých je zaručené, že dátové súbory boli aktualizované so všetkými informáciami zapísanými pred týmto kontrolným bodom v sekvencii WAL. V čase kontrolného bodu sa všetky nečisté stránky s údajmi zdieľanej vyrovnávacej pamäte vyprázdnia na disk, označia sa ako čisté a do log súboru sa zapíše špeciálny záznam kontrolného bodu.
Zaručuje, že pri akomkoľvek korupcií dát/straty napájania sa uložia všetky údaje pred kontrolným bodom.
Existuje niekoľko premenných, ktorých použitie môže zlepšiť výkon:
Je veľmi jednoduché skontrolovať konfiguráciu WAL writera a kontrolných bodov:
Na zlepšenie výkonu hromadných dátových operácií je potrebné zväčšiť veľkosť max_wal_size, checkpoint_flush_after , checkpoint_completion_target a checkpoint_timeout .
Po zvýšení hodnoty takého parametra ako checkpoint_timeout z 5 min na 20 min sa počet diskových I/O operácií zníži, ale samotné operácie zaberú oveľa viac času. Zníženie hodnoty bude mať opačný efekt.
Zvýšenie času kontrolného bodu má ešte jeden vplyv. Ak má DB veľa DML (INSERT / UPDATE / DELETE) dotazov a kontrolné body sa vyskytujú veľmi zriedkavo, potom existuje riziko, že zdieľaná vyrovnávacia pamäť bude zaplnená údajmi, ktoré je potrebné zapísať alebo budú operácie zápisu veľkého množstva údajov ovplyvniť ďalšie otázky.
Vo väčšine prípadov nám postgres povie, kedy treba niektoré z týchto parametrov zmeniť. Bude potrebné zapnúť inštrukciu logovania.
Beží ako samostatný serverový proces, jeho funkciou je vydávať zápisy „špinavých“ (nových alebo upravených) zdieľaných vyrovnávacích pamätí. Keď je nedostatok čistých vyrovnávacích pamätí, vezme niekoľko špinavých a zapíše ich do súborov a označí ich ako čisté. Takýto prístup znižuje pravdepodobnosť, že serverové procesy spracovávajúce používateľské dopyty nebudú schopné nájsť čisté vyrovnávacie pamäte a budú samy musieť zapisovať špinavé vyrovnávacie pamäte. Hlavnou úlohou je teda nechať ostatné procesy, aby sa venovali svojej činnosti, namiesto vyčistenia vyrovnávacej pamäte, keď neexistujú žiadne čisté stránky.
Obrovskou nevýhodou je, že zapisovač na pozadí spôsobuje celkové čisté zvýšenie záťaže I/O. Napriek kontrolným bodom zapisovateľ na pozadí napíše všetky opakovane znečistené stránky.
Databáza v skutočnosti okamžite neodstráni ani neaktualizuje žiadne riadky pri operáciách UPDATE alebo DELETE. Tieto riadky sú označené iba ako odstránené. Hlavnou úlohou vákua je označiť takéto riadky ako riadky na opätovné použitie, výsledkom čoho je, že tabuľky zaberajú menej miesta na disku (voľné miesto sa väčšinou nevracia do operačného systému, ale bude znovu použité) a zrýchli sa dopytovanie.
Existujú dva typy vákua, prvý je autovakuum – robí všetko popísané vyššie a má nasledujúce nastavenia:
Príklady vacuum-u:
V dôsledku toho sa voľné miesto nevráti operačnému systému a server DB bude mať určité množstvo voľného miesta, takže v určitom množstve ďalších operácií nebude DB požadovať nový voľný priestor od OS.
Druhým typom vacuum cleaning je VACUUM FULL. Prepisuje údaje do nových súborov, štruktúruje a mení poradie údajov tabuľky a umožňuje vrátiť voľné miesto operačnému systému. Vyžaduje si to špeciálny zámok na prístup k tabulke, takže je lepšie nastaviť VACUUM FULL, keď sa server používa menej. Veľa času mu zaberie aj beh. Najdôležitejším bodom, prečo sa musí použiť tento druh vákua, je to, že aktualizuje štatistiky údajov, ktoré používa plánovač. Umožňuje plánovačubyť efektívnejší. Tiež je užitočné vyskúšať VACUUM FULL, keď je očakávaný čas vykonania veľmi odlišný od skutočného.
Paralelnosť umožňuje spúšťanie dotazov na niekoľkých CPU. Najužitočnejšie je použitie paralelizmu pre dotazy, ktoré zhromažďujú údaje z mnohých tabuliek, ale vracajú len niekoľko riadkov. Takéto dopyty môžu byť 2- alebo dokonca 4-krát rýchlejšie. Ktorý dotaz bude prebiehať paralelne, určuje plánovač.
Maximálny počet paralelných pracovníkov je obmedzený dvoma premennými:
Čas vykonania príkazu ako “ EXPLAIN ANALYZE SELECT count(*) FROM pgbench_accounts; ” s jedným paralelným pracovníkom je viac ako 320 ms, ale sedem, ako je možné vidieť na obrázku nižšie, sa dá skrátiť na 192 ms. Maximálny počet paralelných robotníkov pre druhý príklad je desať, ale používa sa ich len sedem, pretože veľkosť stola nie je dostatočná na použitie všetkých desiatich robotníkov.
Po prvé, všetky indexy musia byť použité iba pre stĺpce s vysokou mohutnosťou (percento jedinečných hodnôt), napríklad stĺpec id má 100 % mohutnosť, pretože každá hodnota je jedinečná. Postgresql štandardne pridáva index B-Stromu do stĺpca id každej tabuľky.
Indexy B-Stromu dokážu spracovať otázky rovnosti a rozsahu údajov, ktoré možno zoradiť do určitého usporiadania. Dobrý nápad je použiť B-Strom pre jedinečný stĺpec, napríklad s e-mailmi. Ale dopyty zahŕňajúce vzory, ako je tento " col LIKE '%bar' ." nebudú spustené pomocou indexov.
PostgreSQL obsahuje množstvo ďalších indexov z indexov HASH, ktoré ukladajú dáta ako 32-bitový hash a dajú sa použiť iba pri porovnávaní rovnosti s indexmi SP-GIST, ktoré podporujú rôzne druhy vyhľadávaní (napríklad „najbližší sused“) a umožňujú implementáciu rôznych dátové štruktúry.
PostgreSQL podporuje množstvo rôznych indexových skenov. Prvým z nich je bežné skenovanie indexu, ktoré vracia údaje podľa indexu. Ďalším je skenovanie iba indexu; to znamená, že potrebné údaje je možné vrátiť z indexového súboru aj bez otvorenia súboru údajov tabuľky.
V prípadoch, keď je počet vrátených riadkov príliš malý na sekvenčné skenovanie a príliš veľký na skenovanie indexu, postgresql používa skenovanie bitovej mapy. Ide o kombináciu sekvenčného skenovania a indexového skenovania.
Veľmi dobrou praxou je indexovanie cudzích kľúčov. Je to veľmi užitočné vo vzťahoch medzi rodičmi a deťmi, kde je podriadená tabuľka väčšia ako rodičovská. Vytvorme tabuľku objednávok s 1 000 000 riadkami, kde každá surovina bude mať 4 položky z tabuľky položiek:
Priemerný čas odozvy na DELL G15 so systémom Kubuntu 22.04 bol od 400 ms do 600 ms, ale po vytvorení indexu v stĺpci cudzieho kľúča sa znížil na 40-60 ms pre rovnaký dotaz:
Dokonca aj pri 25% mohutnosti je vykonávanie dotazu takmer 5-krát rýchlejšie. Rovnaký výsledok bol s 10% mohutnosťou. Indexovanie cudzích kľúčov je veľmi užitočné, keď máme tabuľky s veľkým množstvom údajov, inak plánovač namiesto indexového skenovania zvolí sekvenčné skenovanie.
V prípade, že máme tabuľku s nejakým druhom transakcií, ale aktívne sa využívajú len neukončené, môžeme vytvoriť index len pre určité riadky, napríklad pre tie, kde nie je stav transakcie ukončený. Ďalšou výhodou takéhoto indexu je, že zaberá menej miesta na disku.
Indexy sa zvyčajne používajú na načítanie malého množstva údajov, ale v závislosti od frekvencie dotazov a času odozvy niekedy bude rozumné vytvoriť index zo stĺpca, ktorý používa ORDER BY s LIMIT. ORDER BY je sám o sebe veľmi náročný príkaz a vyžaduje veľa času na jeho vykonanie. V ďalšom prípade je uvedený príklad použitia indexu spolu s ORDER BY:
Napriek tomu, že mohutnosť stĺpca order_date je menšia ako 1%, vykonávanie dopytu je teraz 2-4x rýchlejšie. Je to vďaka tomu, že dáta sú už triedené v indexovom súbore.