sql >> Database teknologi >  >> RDS >> PostgreSQL

Postgresql trunkeringshastighed

Dette er dukket op et par gange for nylig, både på SO og på PostgreSQL-mailinglisterne.

TL;DR for dine sidste to punkter:

(a) De større shared_buffers kan være årsagen til, at TRUNCATE er langsommere på CI-serveren. Forskellig fsync-konfiguration eller brugen af ​​rotationsmedier i stedet for SSD'er kan også være en fejl.

(b) TRUNCATE har en fast pris, men ikke nødvendigvis langsommere end DELETE , plus det gør mere arbejde. Se den detaljerede forklaring, der følger.

OPDATERING: En væsentlig diskussion om pgsql-performance opstod fra dette indlæg. Se denne tråd.

OPDATERING 2: Der er blevet tilføjet forbedringer til 9.2beta3, som skulle hjælpe med dette, se dette indlæg.

Detaljeret forklaring af TRUNCATE vs DELETE FROM :

Selvom jeg ikke er ekspert på emnet, er min forståelse, at TRUNCATE har en næsten fast pris pr. tabel, mens DELETE er mindst O(n) for n rækker; værre, hvis der er nogen fremmednøgler, der refererer til den tabel, der slettes.

Jeg har altid antaget, at de faste omkostninger ved en TRUNCATE var lavere end prisen på en DELETE på et næsten tomt bord, men det er slet ikke sandt.

TRUNCATE table; gør mere end DELETE FROM table;

Databasens tilstand efter en TRUNCATE table er meget det samme, som hvis du i stedet ville køre:

  • DELETE FROM table;
  • VACCUUM (FULL, ANALYZE) table; (kun 9.0+, se fodnote)

... selvom selvfølgelig TRUNCATE opnår faktisk ikke sine effekter med en DELETE og en VACUUM .

Pointen er, at DELETE og TRUNCATE gør forskellige ting, så du ikke bare sammenligner to kommandoer med identiske resultater.

En DELETE FROM table; tillader døde rækker og bloat at forblive, tillader indekserne at bære døde poster, opdaterer ikke tabelstatistikken, der bruges af forespørgselsplanlæggeren, osv.

En TRUNCATE giver dig en helt ny tabel og indekser, som om de bare var CREATE udg. Det er, som om du har slettet alle posterne, genindekseret tabellen og lavet en VACUUM FULL .

Hvis du er ligeglad med, om der er crud tilbage i tabellen, fordi du er ved at gå og fylde den op igen, kan du være bedre tjent med at bruge DELETE FROM table; .

Fordi du ikke kører VACUUM du vil opdage, at døde rækker og indeksposter akkumuleres som oppustethed, der skal scannes og derefter ignoreres; dette forsinker alle dine forespørgsler. Hvis dine test faktisk ikke skaber og sletter al så meget data, bemærker du måske ikke eller bekymrer dig, og du kan altid lave en VACUUM eller to halvvejs gennem dit testløb, hvis du gør det. Bedre, lad aggressive autovacuum-indstillinger sikre, at autovacuum gør det for dig i baggrunden.

Du kan stadig TRUNCATE alle dine borde efter hele testsuite kører for at sikre, at der ikke opbygges effekter på tværs af mange kørsler. På 9.0 og nyere, VACUUM (FULL, ANALYZE); globalt på bordet er mindst lige så god, hvis ikke bedre, og det er en hel del nemmere.

IIRC Pg har et par optimeringer, der betyder, at den måske bemærker, når din transaktion er den eneste, der kan se tabellen og straks markere blokkene som gratis alligevel. I test, når jeg har ønsket at skabe bloat, har jeg været nødt til at have mere end én samtidig forbindelse for at gøre det. Jeg ville dog ikke stole på dette.

DELETE FROM table; er meget billigt til små borde uden f/k refs

Til DELETE alle poster fra en tabel uden fremmednøglereferencer til den, skal alle Pg lave en sekventiel tabelscanning og indstille xmax af de stødte tupler. Dette er en meget billig operation - grundlæggende en lineær læsning og en semi-lineær skrivning. AFAIK det behøver ikke at røre indekserne; de fortsætter med at pege på de døde tupler, indtil de er ryddet op af et senere VACUUM der også markerer blokke i tabellen, der kun indeholder døde tupler som frie.

DELETE bliver kun dyrt, hvis der er masser af poster, hvis der er masser af fremmednøglereferencer, der skal kontrolleres, eller hvis du tæller den efterfølgende VACUUM (FULL, ANALYZE) table; nødvendig for at matche TRUNCATE s effekter inden for prisen på din DELETE .

I mine tests her, en DELETE FROM table; var typisk 4x hurtigere end TRUNCATE ved 0,5 ms vs. 2 ms. Det er en test-DB på en SSD, der kører med fsync=off fordi jeg er ligeglad med, om jeg mister alle disse data. Selvfølgelig, DELETE FROM table; ikke gør det samme arbejde, og hvis jeg følger op med en VACUUM (FULL, ANALYZE) table; det er meget dyrere 21ms, så DELETE er kun en sejr, hvis jeg faktisk ikke har brug for bordet uberørt.

TRUNCATE table; udfører meget mere faste omkostninger og husholdning end DELETE

Derimod en TRUNCATE skal lave en masse arbejde. Den skal allokere nye filer til tabellen, dens TOAST-tabel, hvis nogen, og hvert indeks tabellen har. Overskrifter skal skrives ind i disse filer, og systemkatalogerne skal muligvis også opdateres (ikke sikker på det punkt, har ikke tjekket). Den skal så erstatte de gamle filer med de nye eller fjerne de gamle og skal sikre, at filsystemet har indhentet ændringerne med en synkroniseringsoperation - fsync() eller lignende - der normalt tømmer alle buffere til disken . Jeg er ikke sikker på, om synkroniseringen er sprunget over, hvis du kører med (data-spise) muligheden fsync=off .

Jeg lærte for nylig, at TRUNCATE skal også tømme alle PostgreSQL's buffere relateret til den gamle tabel. Dette kan tage en ikke-triviel mængde tid med enorme shared_buffers . Jeg formoder, at det er derfor, det er langsommere på din CI-server.

Saldoen

I hvert fald kan du se, at en TRUNCATE af en tabel, der har en tilknyttet TOAST-tabel (de fleste gør), og flere indekser kan tage et øjeblik. Ikke lang, men længere end en DELETE fra et næsten tomt bord.

Derfor er det måske bedre at lave en DELETE FROM table; .

--

Bemærk:på DB'er før 9.0, CLUSTER table_id_seq ON table; ANALYZE table; eller VACUUM FULL ANALYZE table; REINDEX table; ville være mere ækvivalent med TRUNCATE . VACUUM FULL impl ændret til en meget bedre i 9.0.



  1. 4 måder at finde rækker, der indeholder store bogstaver i PostgreSQL

  2. Oprettelse af vedligeholdelsesplaner i SQL Server

  3. Hvad er SQLite browser, og hvordan bruger man den?

  4. Implementering af en meget tilgængelig Nextcloud med MySQL Galera Cluster og GlusterFS