PGMon - partitioning

Množství dat sesbíraných projektem PGMon může být poměrně značné, což následně působí potíže při jejich zpracování (čím více dat, tím pomalejší dotazy) a údržbě (sesbíraná data poměrně rychle zastarávají, a mazání velkých objemů dat má v PostgreSQL různá úskalí). Partitioning nabízí poměrně efektivní řešení právě uvedených problémů.

Uvažujme středně velkou databázi - 100 tabulek, 200 indexů (dva pro každou tabulku - primární klíč a jeden další) - a pokusme se spočítat množství dat sesbíraných za měsíc pokud jsou data sbírána každých 5 minut. Pro každý záznam o tabulce resp. o indexu je třeba přibližně 360B resp. 320B. Za měsíc bude pro každý objekt sesbíráno 8928 záznamů, což celkem dává 892800 záznamů pro tabulky a 1785600 záznamů pro indexy. Co se týká velikosti, jedná se o cca 300MB dat o tabulkách a 540MB dat o indexech.

Tento objem dat může znamenat různé problémy - platí totiž jednoduchá úměra "čím více dat, tím pomalejší dotazy." Sesbíraná data sice poměrně rychle zastarávají (data starší než 1 měsíc nejspíše příliš často používat nebudete) takže není třeba držet on-line příliš mnoho dat a stará data je možno průběžně zálohovat a odstraňovat. Odstraňování velkého množstí dat naráz však vzhledem k architektuře PostgreSQL působí různé problémy (bloating).

Poměrně efektivní řešení těchto problémů představuje partitioning dle času vložení, tj. využití dědičnosti a triggerů nebo pravidel (rules). Partitioning sice není ve standardní distribuci projektu PGMon použit, ale jeho nasazení je poměrně triviální - stačí definovat části tabulky (partitions), a pravidla pro přesměrování vkládaných dat do příslušných částí.

Následující SQL skript vytvoří dvě části (partitions) tabulky "Tables" pro leden a únor 2009, a také dvě pravidla přesměrovávající data do správné části:

-- partition pro leden 2009
CREATE TABLE Tables_2009_01 (
    PRIMARY KEY (stat_time, dbmane, schemaname, tablename),
    CHECK ( stat_time >= '2009-01-01' AND stat_time < '2009-02-01' )
) INHERITS (Tables);

-- partition pro únor 2009
CREATE TABLE Tables_2009_02 (
    PRIMARY KEY (stat_time, dbmane, schemaname, tablename),
    CHECK ( stat_time >= '2009-02-01' AND stat_time < '2009-03-01' )
) INHERITS (Tables);

-- pravidlo pro leden 2009
CREATE RULE Tables_insert_2009_01 AS
ON INSERT TO Tables WHERE
    ( stat_time >= '2009-01-01' AND stat_time < '2009-02-01' )
DO INSTEAD
    INSERT INTO Tables_2009_01 VALUES (NEW.*);

-- pravidlo pro únor 2009
CREATE RULE Tables_insert_2009_02 AS
ON INSERT TO Tables WHERE
    ( stat_time >= '2009-02-01' AND stat_time < '2009-03-01' )
DO INSTEAD
    INSERT INTO Tables_2009_02 VALUES (NEW.*);

Při definici partitions je třeba vhodně zvolit interval, přičemž měsíc považuji za rozumný kompromis a používám ho na většině míst. V některých případech používám týden nebo rok, ale kratší nebo delší intervaly se mi neosvědčily.

Partitions je třeba pravidelně vytvářet - je celkem jedno zda je budete pravidelně vytvářet ručně nebo automaticky (například cronovým skriptem), i když automatická varianta je lepší. Nevytvářejte však příliš mnoho partitions naráz, neboť vždy jsou vyhodnocována všechna pravidla a to při velkém počtu pravidel může působit výkonnostní problémy. Ze stejného důvodu také doporučuji rušit pravidla pro již historické partitions (minulý měsíc apod.).

Se systémem pravidel také souvisí nemožnost nespoléhat se na výchozí hodnotu v databázi, neboť ta je definována až při vlastním vložení do tabulky.

Komentáře

K tomuto článku zatím žádné komentáře neexistují (nebo čekají na schválení).

Nový komentář

Všechny komentáře podléhají schválení - mezi odesláním komentáře a jeho zobrazením na této stránce tedy může být prodleva. Vyplníte-li e-mailovou adresu, budete o schválení či neschválení komentáře informováni.

V titulku ani v textu nejsou povoleny HTML tagy - budou automaticky odstraněny. Odstavec ukončíte prázdným řádkem.

(nepovinné)