Úvod
PostgreSQL dává vývojářům možnost vybrat si mezi dvěma možnými úložnými zařízeními pro velká binární data:Bytea a LargeObjects.
Velké objekty existují již dlouhou dobu a PostgreSQL má chytrý způsob ukládání velkých binárních dat. Dělá to tak, že je rozděluje na části LOBLKSIZE (čtvrtina BLCKSZ). Tímto způsobem se n-tice z pg_largeobject nevysypou na toustový stůl.
Na druhou stranu bytea ukládá binární data přímo do n-tice, což může vést ke špatnému výkonu v závislosti na tom, jak vaše schéma vypadá.
To zní skvěle, pokud máte inteligentní rozhraní pro manipulaci s těmito binárními soubory, zvláště pokud aktualizace upraví pouze malou část celého binárního souboru.
Ale normálně se neobtěžujeme psát kód, který toho využívá, a místo toho zapisujeme znovu celá binární data.
Jednou z věcí, které podle mého názoru přimějí lidi přijmout velké objekty, jsou funkce dostupné pro import a export souborů přímo z databázového serveru do jeho souborového systému. Má to nevýhodu:pokud je aplikace na jiném serveru, budete potřebovat další kód k přesunutí souboru na místo, kde je potřeba.
Problém, se kterým se můžete setkat
V minulých dnech jsem musel prozkoumat databázi používanou k ukládání informací o uživatelských relacích ze systému Java CAS. Zjistil jsem, že v databázi bylo téměř 100 milionů velkých objektů, ne příliš velkých.
Prošel jsem uživatelské tabulky a zkontroloval jsem pole, která měla oid a poté křížovým odkazem na hodnoty v těchto polích pomocí pg_largeobject_metadata stůl. Zjistil jsem, že 96 % těchto velkých objektů je osiřelých. To jsou velké objekty, na které se neodkazovala žádná n-tice z uživatelských tabulek.
Další vyšetřování dospělo k závěru, že Hibernate se nestaral o vyčištění velkých objektů, které vytvořil při mazání nebo aktualizaci n-tic s oidovými poli. Takže to generovalo velké množství nadýmání, které nebylo možné vyčistit vysáváním, ale muselo být odstraněno z tabulky pg_largeobjects ručně.
V konkrétním případě databáze CAS sloužil tento dotaz k identifikaci dosud používaných velkých objektů:
SELECT unnest(array[expiration_policy, authentication, services_granted_access_to]) FROM public.ticketgrantingticket UNION SELECT unnest(array[expiration_policy, service]) FROM public.serviceticket
Dotaz lze použít k vyloučení ze seznamu velkých objektů, které z nich odstranit. Něco jako toto:
SELECT lo_unlink(pg_largeobject_metadata.oid) FROM pg_largeobject_metadata WHERE pg_largeobject_metadata.oid NOT IN ( SELECT unnest(array[expiration_policy, authentication, services_granted_access_to]) FROM public.ticketgrantingticket UNION SELECT unnest(array[expiration_policy, service]) FROM public.serviceticket )
Závěr
Velké objekty mají své problémy, stejně jako jiné typy dat (zejména při použití typů k ukládání velkých binárních dat). Je na vývojářích a správcích databází, aby využili výhod a zmírnili nevýhody.
Dali jsme možný dotaz k provedení vyčištění, ale existuje také pěkné rozšíření, které vyčistí osiřelé velké objekty pomocí spouštěčů:Správce velkých objektů
Někteří lidé mohou upřednostňovat spouštění dotazu pro čištění během klidových hodin namísto spouštění spouštěče při každé AKTUALIZACI a SMAZAT . Na systémech s velmi, velmi nízkou hodnotou UPDATE a/nebo DELETE sazba, spouštěč nad každou tabulkou, která má oid pole, se jeví jako elegantnější řešení. A jakákoli ztráta výkonu kvůli nutnosti provést spouštěcí funkci by byla zbytečná.
V každém případě mají velké objekty stále velké fanoušky, s největší pravděpodobností kvůli interním funkcím pro import a export binárních dat přímo do místního souborového systému. S bytea byste normálně spotřebovali více paměti na aplikační vrstvě. Je to velmi běžný postup, jak celé binární pole načíst do proměnné a poté je zpracovat.
Možná bych mohl napsat něco o použití bytea, který jsem použil v jednom ze svých minulých vývojů, v budoucím příspěvku na blogu.