sql >> Databasteknik >  >> RDS >> PostgreSQL

De där jäkla stora föremålen

Intro

PostgreSQL ger utvecklare chansen att välja mellan två möjliga lagringsfaciliteter för stora binära data:Bytea och LargeObjects.

Stora objekt har funnits länge och PostgreSQL har ett smart sätt att lagra stora binära data. Det gör det genom att dela upp det i bitar av LOBLKSIZE (en fjärdedel av BLCKSZ). På så sätt spills inte tuplarna från pg_largeobject på toastbordet.

Å andra sidan bytea lagrar binärdata direkt i tupeln, vilket kan leda till dålig prestanda beroende på hur ditt schema ser ut.

Detta låter bra om du har ett intelligent gränssnitt för att hantera manipulering av dessa binära filer, speciellt om uppdateringen ändrar bara en liten del av hela den binära filen.

Men normalt bryr vi oss inte om att skriva kod som drar fördel av detta, utan istället skriver vi om hela binära data.

En av de saker som jag tror får människor att ta till sig stora objekt är de funktioner som är tillgängliga för att importera och exportera filer direkt från databasservern till dess filsystem. Det finns en nackdel med detta:om applikationen finns på en annan server behöver du mer kod för att flytta filen till den plats där den behövs.

Ett problem du kan möta

De senaste dagarna var jag tvungen att undersöka en databas som används för att lagra information om användarsessioner från ett Java CAS-system. Jag upptäckte att det fanns nästan 100 miljoner stora objekt i databasen, inte särskilt stora.

Jag gick igenom användartabellerna och kontrollerade fälten som hade en oid och sedan korshänvisar jag värdena i dessa fält med pg_largeobject_metadata tabell. Jag upptäckte att 96% av de stora föremålen var föräldralösa. Det är stora objekt som inte refererades av någon tupel från användartabellerna.

Ytterligare undersökningar drog slutsatsen att Hibernate inte tog hand om att rensa de stora objekt som skapades när de raderade eller uppdaterade tupler med oid-fält. Så det genererade en stor mängd svullnad som inte kunde städas upp genom att dammsuga, utan måste rensas bort från tabellen pg_largeobjects manuellt.

I det speciella fallet med CAS-databasen tjänade denna fråga för att identifiera de stora objekt som fortfarande används:

SELECT unnest(array[expiration_policy,
                    authentication,
                    services_granted_access_to])
       FROM public.ticketgrantingticket
UNION
SELECT unnest(array[expiration_policy, 
                    service])
       FROM public.serviceticket

Frågan kan användas för att utesluta från listan över stora objekt vilka som ska tas bort. Något så här:

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
)

Slutsats

Stora objekt har sina problem, precis som andra typer av data (särskilt när man använder typer för att lagra stora binära data). Det är upp till utvecklarna och databasadministratörerna att dra fördel av fördelarna och mildra nackdelarna.

Vi gav en möjlig fråga för att utföra rensningen, men det finns också en trevlig tillägg som rensar upp föräldralösa stora objekt med triggers:Large Object Manager

Vissa människor kanske föredrar att köra en rensningsfråga under tysta timmar istället för att köra en trigger vid varje UPPDATERING och RADERA . På system med mycket, mycket låg UPPDATERING och/eller RADERA rate, en utlösare över varje tabell som har en oid område, verkar vara en mer elegant lösning. Och varje prestandaförlust för att behöva utföra triggerfunktionen skulle vara överflödig.

I vilket fall som helst har stora objekt fortfarande stora fans, troligen på grund av de interna funktionerna som tillhandahålls för att importera och exportera binära data direkt till det lokala filsystemet. Med bytea skulle du normalt använda mer minne på applikationsnivån. Det är en mycket vanlig procedur att läsa in det binära fältet helt till en variabel och sedan bearbeta det.

Jag kanske skriver något om att använda bytea som jag använde i en av mina tidigare utvecklingar i ett framtida blogginlägg.


  1. oracle-fråga sekventiell summering per rad

  2. Hur man listar alla tabeller i Oracle

  3. Några idéer om resurspooling på låg nivå i PostgreSQL

  4. SQL Server 2016