Relační databázový systém PostgreSQL patří mezi populární a dobře zavedené open-source projekty s dlouhou historií a po mnoho let se těšil výsadnímu postavení "jediného skutečně svobodného plnohodnotného relačního databázového systému". O toto výsadní postavení ovšem přišel s nástupem nových hráčů na poli open-source relačních databází, jako je Firebird, MaxDB a nově také Ingres. Vývojáři PostgreSQL ovšem neusnuli na vavřínech a po řadě "menších" aktualizací nám přichystali zcela novou zásadní verzi - PostgreSQL 8.0.
Ačkoliv je PostgreSQL velice kvalitním systémem s množstvím zajímavých vlastností a funkcí, postrádá kvůli svým kořenům v akademické sféře některé vlastnosti a především "vyladěnost" nezbytnou pro náročné podnikové aplikace. Tato skutečnost vyniká obzvláště ve srovnání s ostatními open source RDBMS, které vzešly z čistě komerčních systémů (Firebird, MaxDB, Ingres). Proto se poslední tři roky vývojáři PostgreSQL zaměřují právě na odstranění těchto "nedostatků" a verze 8.0 je důležitým mezníkem na cestě k uspokojení náročných potřeb podnikové sféry.
Mezi nejvýznamnějšími novinkami nové verze nalezneme body návratu (savepoints) pro transakce, obnovu databáze k určitému časovému okamžiku (Point-In-Time Recovery), větší kontrolu nad fyzickým umístěním tabulek a indexů (tablespaces) a mnoho optimalizací a subtilních změn pro zvýšení výkonu, usnadnění konfigurace systému a administrace databází.
Body návratu transakcí
Body návratu (savepoints) umožňují odstranit část změn provedených v rámci transakce bez nutnosti zrušit (rollback) celou transakci. Vývojáři aplikací tak dostávají do rukou nástroj pro zotavení z chyb v rámci komplexních transakcí. Pro práci s body návratu slouží příkazy SAVEPOINT, ROLLBACK TO SAVEPOINT a RELEASE SAVEPOINT.
-- Vytvoření bodu návratu a pozdější -- zrušení operací k tomuto bodu: BEGIN; INSERT INTO table VALUES (1); SAVEPOINT my_savepoint; INSERT INTO table VALUES (2); ROLLBACK TO SAVEPOINT my_savepoint; INSERT INTO table VALUES (3); COMMIT; -- Vytvoření a pozdější zrušení -- bodu návratu: BEGIN; INSERT INTO table VALUES (3); SAVEPOINT my_savepoint; INSERT INTO table VALUES (4); RELEASE SAVEPOINT my_savepoint; COMMIT;
Tabulkové prostory
Pokud nevlastníte diskové pole a vaše databáze je příliš velká, než aby se vešla na jediný disk, je nutné ji rozdělit na více disků. Rovněž pro zvýšení výkonu může být výhodné umístit vybrané tabulky a indexy na různé svazky. U nové verze již pro tuto operaci není nutné používat initlocation a symbolické odkazy, ale můžete využít nově zavedených tabulkových prostorů (tablespaces), které celou operaci rozdělení databáze značně zjednodušují a zpřehledňují. Na rozdíl od jmenných prostorů (namespace) realizovaných v PostgreSQL jako schema, slouží tabulkové prostory pouze k určení fyzického umístění databázových objektů.
Pro definici nového tabulkového prostoru slouží příkaz CREATE TABLESPACE jméno [ OWNER uživatel ] LOCATION 'adresář'. Na takto definovaný tabulkový prostor se pak lze odkazovat v příkazech CREATE DATABASE, CREATE SCHEMA, CREATE TABLE, CREATE INDEX nebo ADD CONSTRAINT a dosáhnout tak fyzického uložení daného databázového objektu do požadované lokace. Tabulkové prostory jsou definovány globálně pro celý cluster a mohou být tedy sdíleny i mezi databázemi.
Umístění existujícího tabulkového prostoru již nelze změnit. Pokud tedy později vznikne potřeba přemístit databázové objekty do jiné lokace (např. kde je více prostoru), je nutné vytvořit nový tabulkový prostor a objekty do něj přesunout pomocí příslušných příkazů ALTER (DATABASE, TABLE atd.). Nepotřebné tabulkové prostory lze zrušit příkazem DROP TABLESPACE pouze tehdy, pokud již neobsahují žádné objekty.
-- Vytvoření tabulkových prostorů a definice tabulky která jich využívá: BEGIN; CREATE TABLESPACE dbspace LOCATION '/data/dbs'; CREATE TABLESPACE indexspace OWNER honza LOCATION '/data/indexes'; CREATE TABLE cinemas ( id serial PRIMARY KEY USING INDEX TABLESPACE indexspace, name text, location text ) TABLESPACE dbspace; COMMIT; -- Vytvoření nového tabulkového prostoru a přesun tabulky do tohoto prostoru: BEGIN; CREATE TABLESPACE dbspace2 LOCATION '/data2/dbs'; ALTER TABLE cinemas SET TABLESPACE dbspace2; COMMIT;
Průběžné zálohování
Průběžné (nebo též přírůstkové) zálohovaní využívá Write ahead log (WAL), který obsahuje informace o všech změnách provedených v databázi a který je vytvářen automaticky pro případné obnovení stavu databáze po havárii. Tento protokol je strukturován do segmentů o standardní velikosti 16 MB uchovávaných jako samostatné soubory, které mají číselné jméno odpovídající jejich logickému pořadí ve WAL sekvenci. PosgreSQL běžně udržuje pouze několik WAL segmentů, které recykluje tak, že přejmenovává již nepotřebné segmenty na segmenty s vyšším číslem na základě předpokladu, že segmenty, jejichž obsah předchází poslednímu kontrolnímu bodu (checkpoint), již nejsou zapotřebí. Průběžné zálohování spočívá ve vytvoření základní zálohy a následné půběžné archivace WAL souborů. Ačkoliv tento systém zálohování klade větší nároky na administraci než běžné zálohy, má rovněž několik důležitých předností:
- Základní záloha nemusí být zcela konzistentní, protože případné nekonzistence jsou korigovány pomocí WAL.
- Archivace WAL souborů nijak nezatěžuje systém, a umožňuje tak udržovat aktuální zálohu i v případech, kdy vytvoření běžné zálohy není možné z časových nebo jiných důvodů.
- Průběžnou archivací WAL souborů na jiný server můžeme vytvořit "hot standby" systém, který lze kdykoliv uvést do provozu s téměř aktuálním stavem databáze.
- Pomocí WAL souborů lze zrekonstruovat stav databáze k libovolnému časovému okamžiku.
Pro archivaci WAL souborů nabízí PostgreSQL velice jednoduchý, ale pružný mechanismus. Pomocí konfiguračního parametru archive_command lze specifikovat libovolný shell příkaz, který lze parametrizovat pomocí %p (absolutní cesta k archivovanému souboru) a %f (jméno archivovaného souboru). Například: archive_command = 'cp %p /mnt/server/archivedir/%f'. Tento příkaz je pak vykonán pokaždé, když je zkompletován WAL soubor. Pokud ovšem chcete archivovat i neúplné WAL soubory, je zapotřebí použít jiný mechanismus, např. vytvořit vlastní skript spouštěný jako cron job.
Postup při obnově databáze je relativně jednoduchý. Nejdříve je nutné zastavit server, vyčistit cluster od původních dat a obnovit datové soubory ze základní zálohy. Poté již stačí upravit nastavení v souboru recovery.conf a opět spustit server (postmaster). Server přejde do obnovovacího režimu a po ukončení práce přejmenuje soubor recovery.conf na recovery.done a přejde do normálního pracovního režimu.
Klíčovým bodem při obnově je nastavení správných parametrů v souboru recovery.conf. Jde především o definici příkazu pro obnovu WAL souborů z archivu (parametr restore_command, který je komplementem k již zmíněnému parametru archive_command). Volitelně lze specifikovat časový okamžik nebo číslo transakce, ke kterému se má databáze obnovit. Pokud není specifikováno jinak, jsou zpracovány všechny dostupné WAL soubory.
Pokud je stav databáze obnoven pouze k určitému časovému okamžiku v minulosti, dojde k zajímavému jevu označovanému jako rozštěpení časové linie historie databáze. Aby nedocházelo k přepisu WAL souborů staré historie databáze novými, zavádí PostgreSQL pojem časová linie (timeline). Jedná se o číselný údaj, který je součástí názvu WAL souborů a který je inkrementován pokaždé, když provedete obnovu k určitému okamžiku místo do konce řetězce WAL souborů. Pokud budete archivovat WAL soubory z různých časových os historie databáze, můžete se kdykoliv vrátit k libovolnému časovému okamžiku na kterékoliv časové ose. Implicitně je databáze obnovována podle časové linie aktuální při vytvoření prvotní zálohy databáze. Jinou časovou linii lze pro obnovu specifikovat pomocí parametru v souboru recovery.conf.
Průběžné zálohování má ve verzi 8.0 bohužel i několik nedostatků. Největším nedostatkem je absence informací ve WAL o operacích nad indexy, které nejsou založeny na binárních stromech (hash, R-tree a GiST indexy), takže při obnově nejsou tyto indexy aktualizovány. Po obnově je tedy nutné provést jejich manuální reindexaci.
Optimalizace pro zvýšení výkonu
Verze 8.0 používá lepší strategii pro správu vyrovnávací paměti. Starší verze používaly strategii uchovávající v paměti naposledy používané bloky paměti. Tento algoritmus nebral v úvahu, kolikrát byl daný blok použit, takže sekvenční procházení rozsáhlé tabulky odstranilo z vyrovnávací paměti užitečné stránky. Nový algoritmus používá čtyři samostatné seznamy pro sledování nejpoužívanějších stránek a dynamicky optimalizuje jejich nahrazování na základě zátěže.
U starších verzí docházelo při zpracování kontrolního bodu (checkpoint), který periodicky (typicky každých několik minut) ukládal všechny změněné bloky vyrovnávací paměti a následně si vynucoval zápis změn z vyrovnávací paměti OS na disk, často k výraznému nárůstu práce s diskem, což se negativně odráželo na výkonu. Nová verze používá zápis změn na pozadí, takže změny jsou zapisovány průběžně, a nikoliv nárazově. Rovněž pro uložení změn z vyrovnávací paměti OS na disk je použit mnohem šetrnější mechanismus.
Proces VACUUM odstraňující z databáze nepotřebné verze řádků provádí velké množství I/O operací, což může mít u velmi zatížených systémů negativní vliv na vyřizování požadavků uživatelů. V nové verzi je proto možné VACUUM "zpomalit" a snížit tak jeho vliv na výkon systému, ovšem za cenu celkového prodloužení doby nutné k vyčištění databáze.
U předchozích verzí byly při optimalizaci dotazů často ignorovány indexy, jejichž datový typ se neshodoval s datovým typem v dotazu. Interní přetypování v nové verzi tento nedostatek odstraňuje. Nová verze obsahuje rovněž mnoho vylepšení v optimalizaci dotazů s použitím indexů, například lepší zpracování duplicitních klíčů, využívání indexů pro predikáty spojené operací OR, a to i s použitím kompozitních indexů, lepší zpracování částečných shod klíčů atd.
Ostatní novinky a vylepšení
Kompletní seznam změn a vylepšení, která nová verze přináší, je skutečně impozantní, takže se zmíním jen o několika z nich, které osobně považuji za nejzajímavější.
Zásadní novinkou verze 8.0, která může významným způsobem zvýšit popularitu PostgreSQL, je nativní (nevyžadující Cygwin) verze pro platformu MS Windows, ale s ohledem na zaměření tohoto časopisu se jí nebudu detailněji zabývat. Musím ale vývojáře pochválit za mimořádnou péči, již věnovali verzi pro tuto platformu, a obzvláště pak za vynikající instalační program, který z jinak poměrně náročného procesu instalace a prvotní konfigurace PostgreSQL činí téměř příjemnou záležitost.
Nová verze vás určitě potěší rozšířením příkazu ALTER TABLE. Především je konečně možné změnit datový typ existujícího sloupce bez nutnosti jeho zrušení a opětovného vytvoření (ALTER COLUMN TYPE) a administrátoři jistě uvítají možnost uvést více ALTER akcí v rámci jediného příkazu ALTER TABLE.
Řady změn se dočkala i konfigurace, především směrem k větší srozumitelnosti parametrů. Ačkoliv je většina původních parametrů stále podporována, je vhodné zkontrolovat seznam změněných parametrů před přechodem na novou verzi. Administrátory zaručeně potěší rozšíření příkazu COPY o práci s CSV soubory.
Verze 8.0 disponuje zcela novým jazykem plPerl pro programování na straně serveru, podporující perzistentní sdílený prostor, triggery, záznamy (records) a pole záznamů jako návratové hodnoty, SPI volání a další.
Celkové zhodnocení
Verze 8.0 je rozhodně významným mezníkem ve vývoji PostgreSQL, která zajisté přispěje k větší popularitě tohoto systému. Stávající uživatele potěší podstatná vylepšení prakticky všech aspektů systému, ať už za účelem vyššího výkonu nebo pro zjednodušení administrace a práce s daty. Orientace vývoje na potřeby podnikových aplikací pak jen umocňuje postavení PostgreSQL mezi open-source relačními databázemi jako robustního, výkonného a velice flexibilního systému.