Optimalizace vyhodnocení výrazů v PL/pgSQL
Autor: Pavel Stěhule
Původní interpret PL/pgSQL byl napsán velice jednoduše a to tak, že veškeré výrazy převáděl na SQL příkazy, a sám o sobě realizoval pouze procedurální příkazy. Díky tomu byl programovací jazyk PL/pgSQL absolutně konzistentní s SQL prostředím ale jeho zpracování bylo poměrně pomalé - vzhledem k ostatním interpretovaným jazykům jako je Python, Perl, Lua. Postupem času se interpretace výrazů znatelně zrychlila, a nyní rychlostně zaostává za klasickými interprety o desítky (verze 13), nikoliv už ale o stovky procent. Rychlost PL/pgSQL byla většinou bezpředmětná vzhledem k jeho použití pouze pro psaní uložených procedur, kde naprosto jasným úzkým hrdlem je provádění SQL příkazů. Nicméně se PL/pgSQL začal používat i pro některé numericky orientované úlohy (PostGIS), a tam rychlost PL/pgSQL byla omezující.
Víceméně od samotného začátku se používají cache pro prováděcí plány SQL dotazů i výrazů (což fakticky jednoduchý SQL příkaz SELECT). Ve verzi 8.3 se správa cache plánů centralizovala. Od té doby se v PL/pgSQL nepracuje s prováděcími plány přímo, ale skrz pomocný objekt SPIPlanPtr - který se pak dál odkazuje na centrální cache prováděcích plánů (stále platí, že tato cache plánů je per proces - není sdílená). Díky nepřímému odkazu lze odstranit prováděcí plán dotazu z cache (např. po vymazání objektu na kterém prováděcí plán závisel), ale samotný ukazatel v PL/pgSQL zůstává stále platný. Po smazání konkrétního objektu lze odstranit pouze dotčené prováděcí plány a nikoliv všechny. Zavedením externí cache prováděcích plánů se vyřešil problém s neplatnými referencemi na smazané objekty.
Jednou z nejstarších optimalizací byla implementace tzv zjednodušeného vyhodnocování výrazů. Pro některé výrazy, kde se nepracuje přímo s daty v databázi, nemusíme inicializovat celý aparát pro vyhodnocení dotazu, a můžeme rovnou volat interpret výrazů. Stále se používá plancache, díky čemuž nejsou problémy s referencemi například na smazané a znovu vytvořené funkce. U extrémně jednoduchých výrazů byla výrazná režie kontroly platnosti plánů - plán se musí regenerovat pokud dojde k smazání objektu a také pokud dojde k ukončení transakce, kdy se může změnit definice funkce nebo např. po změně search_path. U jednoduchých výrazů tyto kontroly představovaly výraznou režii. Kontrola se prováděla před každým vyhodnocením. Počínaje verzí 13 se režie kontroly redukuje tím, že se definuje nadřazená struktura - resource owner, která sdružuje původně takto kontrolované plány, a přímo v reakci na některé události evidované plány odstraní z cache. Tudíž před spuštěním interpretu výrazů stačí jednoduchá kontrola existence plánu v cache (bez nutnosti ověření validnosti plánu v cache), a pokud plán v cache není, tak se vytvoří.