PostgreSQL använder inte IN-PLACE-uppdateringsmekanismen, så enligt hur kommandona DELETE och UPDATE är utformade,
- Närhelst DELETE-operationer utförs, markeras den befintliga tuppeln som DÖD istället för att fysiskt ta bort dessa tupler.
- På liknande sätt, närhelst UPDATE-operationen utförs, markerar den motsvarande befintliga tuppel som DÖD och infogar en ny tuppel (dvs. UPDATE-operation =DELETE + INSERT).
Så varje DELETE- och UPDATE-kommando kommer att resultera i en DEAD-tuppel, som aldrig kommer att användas (såvida det inte finns parallella transaktioner). Dessa döda tuplar kommer att leda till onödig extra utrymmesanvändning trots samma eller färre antal effektiva poster. Detta kallas även rymduppsvälldhet i PostgreSQL. Eftersom PostgreSQL används allmänt som OLTP-typ av relationsdatabassystem, där det ofta utförs INSERT, UPDATE och DELETE-operationer, kommer det att finnas många DEAD-tupler och därmed motsvarande konsekvenser. Så PostgreSQL krävde en stark underhållsmekanism för att hantera dessa DEAD-tupler. VACUUM är underhållsprocessen som tar hand om DEAD tuple tillsammans med några fler aktiviteter användbara för att optimera VACUUM-driften. Låt oss förstå lite terminologi som ska användas senare i den här bloggen.
Synlighetskarta
Som namnet antyder, upprätthåller den synlighetsinformation om sidor som endast innehåller tupler som är kända för att vara synliga för alla aktiva transaktioner. För varje sida används en bit. Om biten är inställd på 1 betyder det att alla tuplar på motsvarande sida är synliga. Biten satt till 0 betyder att det inte finns något ledigt utrymme på den givna sidan och tuplar kan vara synliga för alla transaktioner.
Synlighetskarta upprätthålls för varje relation (tabell och index) och associeras tillsammans med huvudrelationer, dvs. om relationsfilens nodnamn är 12345, lagras synlighetsfilen i parallellfilen 12345_vm.
Friutrymmeskarta
Det upprätthåller information om ledigt utrymme som innehåller information om tillgängligt utrymme i relationen. Detta lagras också i filen parallellt med relationshuvudfilen, dvs om nodnamnet för relationsfilen är 12345, lagras kartfilen för ledigt utrymme i parallellfilen 12345_fsm.
Frys tuppel
PostgreSQL använder 4 byte för att lagra transaktions-id, vilket innebär att maximalt 2 miljarder transaktioner kan genereras innan det omsluts. Tänk nu på att någon tupel fortfarande innehåller initialt transaktions-id säg 100, sedan för den nya transaktionen (som använder den omslutna transaktionen) säg 5, transaktions-id 100 kommer att se in i framtiden och den kommer inte att kunna se data som läggs till /modifierad av det även om det faktiskt var i det förflutna. För att undvika detta speciella transaktions-id tilldelas FrozenTransactionId (lika med 2). Detta speciella transaktions-ID anses alltid vara i det förflutna och kommer att vara synligt för alla transaktioner.
VAKUUM
VACUUMs primära uppgift är att återta lagringsutrymme som upptas av DEAD-tuplar. Återvunnet lagringsutrymme ges inte tillbaka till operativsystemet utan defragmenteras bara på samma sida, så de är bara tillgängliga för att återanvändas genom framtida infogning av data i samma tabell. Medan VAKUUM-operation pågår på ett visst bord, kan andra LÄS/SKRIV-operationer samtidigt utföras på samma bord eftersom exklusiv låsning inte används på det specifika bordet. Om ett tabellnamn inte anges, kommer VACUUM att utföras på alla tabeller i databasen. VACUUM-operationen utförs under en serie operationer inom ett ShareUpdateExclusive-lås:
- Skanna alla sidor i alla tabeller (eller specificerade tabeller) i databasen för att få alla döda tuplar.
- Frys in gamla tuplar om det behövs.
- Ta bort indextuplen som pekar mot respektive DEAD-tuplar.
- Ta bort DEAD-tuplarna på en sida som motsvarar en specifik tabell och omfördela live-tuplarna på sidan.
- Uppdatera lediga utrymmeskarta (FSM) och Visibility Map (VM).
- Trunkera den sista sidan om möjligt (om det fanns DÖDA tuplar som blev befriade).
- Uppdatera alla motsvarande systemtabeller.
Som vi kan se från ovanstående arbetssteg för VACUUM är det tydligt att det är en mycket kostsam operation eftersom den behöver bearbeta alla sidor i relationen. Så det är väldigt välbehövligt att hoppa över möjliga sidor som inte behöver dammsugas. Eftersom Visibility map (VM) ger information om sidan där om det inte finns något ledigt utrymme, kan det antas att motsvarande sidvakuum inte krävs och därför kan den här sidan säkert hoppa över.
Eftersom VACUUM ändå går igenom alla sidor och deras alla tupler, så passar det på att göra en annan viktig uppgift att frysa de kvalificerande tuplarna.
Fullt VAKUUM
Som diskuterats i föregående avsnitt, även om VACUUM tar bort alla DEAD-tupler och defragmenterar sidan för framtida användning, hjälper det inte att minska den totala lagringen av tabellen eftersom utrymme faktiskt inte frigörs till operativ system. Anta att en tabell tbl1 att det totala lagringsutrymmet har nått 1,5 GB och av detta 1 GB ockuperat av död tuppel, sedan efter VAKUUM kommer ytterligare cirka 1 GB att vara tillgängligt för ytterligare tuppelinsättning men ändå kommer det totala lagringsutrymmet att vara 1,5 GB.
Fullt vakuum löser detta problem genom att faktiskt frigöra utrymme och återföra det till operativsystemet. Men detta kommer till en kostnad. Till skillnad från VACUUM tillåter FULL VACUUM inte parallell drift eftersom det kräver ett exklusivt lås för att relationen blir FULL VACUUM. Nedan följer stegen:
- Tar exklusivt lås på relationen.
- Skapa en parallell tom lagringsfil.
- Kopiera alla live-tupler från nuvarande lagring till nyligen allokerad lagring.
- Frigör sedan det ursprungliga lagringsutrymmet.
- Frigör låset.
Så som det också framgår av stegen kommer den att ha lagring som endast krävs för återstående data.
Automatisk VAKUUM
Istället för att göra VACUUM manuellt, stöder PostgreSQL en demon som automatiskt utlöser VACUUM med jämna mellanrum. Varje gång VACUUM vaknar (som standard 1 minut) anropar det flera arbeten (beroende på konfigurationen av autovacuum_worker processer).
Autodammsugare utför VAKUUM-processer samtidigt för respektive angivna tabeller. Eftersom VACUUM inte tar något exklusivt lås på tabeller, påverkar det inte (eller minimalt) annat databasarbete.
Konfigurationen av Auto-VACUUM bör göras baserat på databasens användningsmönster. Det bör inte vara för ofta (eftersom det kommer att slösa bort arbetarnas uppvaknande eftersom det kanske inte finns eller för lite döda tupler) eller för mycket fördröjda (det kommer att orsaka många döda tupler tillsammans och därmed uppblåst bord).
VAKUUM eller Full VAKUUM
I idealfallet bör databasapplikationen utformas på ett sätt så att det inte finns något behov av FULLSTÄNDIG VAKUUM. Som förklarats ovan återskapar FULL VACUUM lagringsutrymme och lägger tillbaka data, så om det bara finns färre döda tuplar, kommer omedelbart lagringsutrymme att återskapas för att lägga tillbaka all originaldata. Eftersom FULL VACUUM tar exklusivt lås på bordet, blockerar det alla operationer på motsvarande bord. Så att göra HELT VAKUUM ibland kan sakta ner den övergripande databasen.
Sammanfattningsvis Full VACUUM bör undvikas om det inte är känt att majoriteten av lagringsutrymmet beror på döda tuplar. PostgreSQL-tillägget pg_freespacemap kan användas för att få en rättvis ledtråd om ledigt utrymme.
Låt oss se ett exempel på den förklarade VAKUUMprocessen.
Låt oss först skapa en tabelldemo1:
postgres=# create table demo1(id int, id2 int);
CREATE TABLE
Och infoga lite data där:
postgres=# insert into demo1 values(generate_series(1,10000), generate_series(1,
10000));
INSERT 0 10000
postgres=# SELECT count(*) as npages, round(100 * avg(avail)/8192 ,2) as average_freespace_ratio FROM pg_freespace('demo1');
npages | average_freespace_ratio
--------+-------------------------
45 | 0.00
(1 row)
Nu, låt oss radera data:
postgres=# delete from demo1 where id%2=0;
DELETE 5000
Och kör ett manuellt vakuum:
postgres=# vacuum demo1;
VACUUM
postgres=# SELECT count(*) as npages, round(100 * avg(avail)/8192 ,2) as average_freespace_ratio FROM pg_freespace('demo1');
npages | average_freespace_ratio
--------+-------------------------
45 | 45.07
(1 row)
Det här lediga utrymmet är nu tillgängligt för återanvändning av PostgreSQL, men om du vill frigöra det utrymmet till operativsystemet, kör:
postgres=# vacuum full demo1;
VACUUM
postgres=# SELECT count(*) as npages, round(100 * avg(avail)/8192 ,2) as average_freespace_ratio FROM pg_freespace('demo1');
npages | average_freespace_ratio
--------+-------------------------
23 | 0.00
(1 row)
Slutsats
Och det här var ett kort exempel på hur VAKUUM-processen fungerar. Tack vare den automatiska vakuumprocessen, för det mesta och i en vanlig PostgreSQL-miljö, behöver du lyckligtvis inte tänka på detta eftersom det hanteras av motorn själv.