Ydelsesoptimering og optimering af forespørgsler i PostgreSQL · Lektion

Præcis måling af tabel- og indeks-bloat

Brug pgstattuple og estimeringsforespørgsler til at kvantificere ubrugt plads, før De vælger en løsning.

Lektion 1 af 413 trin

Præcis måling af tabel- og indeks-bloat er en gratis Ydelsesoptimering og optimering af forespørgsler i PostgreSQL-lektion på CoddyKit. Dette er lektion 1 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Ydelsesoptimering og optimering af forespørgsler i PostgreSQL, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Ydelsesoptimering og optimering af forespørgsler i PostgreSQL-kurset indeholder 4 lektioner i alt.

Hvorfor oppustning opstår

PostgreSQL bruger MVCC (samtidig kontrol med flere versioner). Når du UPDATE eller DELETE en række, slettes den gamle version ikke med det samme. Den bliver til en død tuple, der stadig optager plads, indtil VACUUM markerer den som genanvendelig.

  • Oppustning = plads optaget af døde tupler plus uudfyldt ledig plads, som tabellen eller indekset ikke længere har brug for.
  • Oppustning øger størrelsen på disken, gør sekventielle scanninger langsommere og reducerer cacheeffektiviteten.
  • Indeks bliver også oppustede: B-træsider beholder pegere til døde heap-tupler, indtil de ryddes op.

Før du vælger en løsning (VACUUM, VACUUM FULL, pg_repack eller REINDEX), skal du først måle, hvor meget oppustning der faktisk findes. Gætteri fører til unødvendig og forstyrrende vedligeholdelse.

Aktive og døde tupler

Det billigste første signal kommer fra statistikindsamleren. pg_stat_user_tables registrerer et estimat for aktive og døde tupler pr. tabel, opdateret af ANALYZE og autovacuum.

  • n_live_tup — estimeret antal aktive rækker.
  • n_dead_tup — estimeret antal døde rækker, der afventer oprydning.
  • En høj andel af n_dead_tup tyder på, at autovacuum ikke kan følge med.

Dette er et estimat, ikke en byte-nøjagtig måling, men det koster ingenting og er et fremragende filter til den første vurdering.

SELECT relname,
       n_live_tup,
       n_dead_tup,
       round(n_dead_tup * 100.0 / NULLIF(n_live_tup + n_dead_tup, 0), 2) AS dead_pct,
       last_autovacuum
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 20;

Estimering kontra nøjagtig måling

Der findes to grupper af metoder til måling af oppustning, hver med sine afvejninger:

  • Estimeringsforespørgsler læser kun katalogstatistik (pg_class, pg_statistic). De er hurtige og kræver ingen låse, men er omtrentlige — nøjagtigheden afhænger af en aktuel ANALYZE og antagelser om kolonnebredder.
  • pgstattuple scanner fysisk relationen for at tælle nøjagtige byte for aktive og døde data. Den er præcis, men I/O-tung på store tabeller.

Den praktiske arbejdsgang er: Brug billig estimering til at finde kandidater, og brug derefter pgstattuple til at bekræfte de værste, før du beslutter dig for en løsning.

Installation af pgstattuple

pgstattuple er en contrib-udvidelse, der leveres med PostgreSQL. Den skal aktiveres pr. database, før den kan bruges.

  • Aktivering kræver superbrugerrettigheder eller en rolle med CREATE på databasen.
  • Dens funktioner kræver rollen pg_stat_scan_tables (eller superbrugerrettigheder) for at kunne køres mod vilkårlige relationer.

Når den er installeret, får du pgstattuple(), pgstatindex() og den lettere pgstattuple_approx().

CREATE EXTENSION IF NOT EXISTS pgstattuple;

Læsning af pgstattuple-output

pgstattuple('relation') udfører en fuld scanning og returnerer én række med byte-nøjagtige oplysninger om heapen.

  • table_len — relationens samlede størrelse i byte.
  • tuple_count / tuple_len — antal og samlet størrelse i byte for aktive tupler.
  • dead_tuple_count / dead_tuple_len — døde tupler og deres størrelse i byte.
  • free_space / free_percent — genanvendelig ledig plads.

Det vigtigste signal for oppustning er dead_tuple_percent plus free_percent: Tilsammen fortæller de, hvor stor en del af filen der ikke indeholder aktive data.

SELECT table_len,
       tuple_count,
       tuple_len,
       dead_tuple_count,
       dead_tuple_len,
       dead_tuple_percent,
       free_space,
       free_percent
FROM pgstattuple('public.orders');

Omkostningen ved en fuld scanning

pgstattuple() læser hver side i relationen. På en tabel på 500 GB er det meget I/O og kan fortrænge nyttige data fra cachen.

  • Den tager kun en ACCESS SHARE-lås, så den blokerer ikke læsninger eller skriveoperationer — men I/O-belastningen er reel.
  • På store tabeller bør du foretrække pgstattuple_approx(), som bruger visibility map til at springe over sider, der er synlige for alle, og tager stikprøver af resten.
  • approx returnerer approx_free_percent og dead_tuple_percent, som ligger tæt på de nøjagtige værdier til en brøkdel af omkostningen.

Tommelfingerregel: Estimér først, kør approx på mellemstore tabeller, og reserver den nøjagtige pgstattuple() til den endelige bekræftelse af en konkret mistænkt tabel.

SELECT table_len,
       approx_tuple_count,
       approx_tuple_percent,
       dead_tuple_count,
       dead_tuple_percent,
       approx_free_percent
FROM pgstattuple_approx('public.orders');

Måling af indeksoppustning

Indeks bliver oppustede uafhængigt af deres tabel. Brug pgstatindex() til B-træsindeks for at få strukturelle detaljer.

  • avg_leaf_density — procentdelen af bladsider, der er udfyldt med nyttige data. Sunde indeks ligger omkring 90 %; værdier, der falder mod 50 %, signalerer kraftig oppustning.
  • leaf_fragmentation — hvor meget bladsiderne står ude af rækkefølge; høj fragmentering skader intervalscanninger.
  • index_size og internal_pages / leaf_pages beskriver træets opbygning.

En lav avg_leaf_density er det tydeligste argument for en REINDEX (helst REINDEX ... CONCURRENTLY).

SELECT version,
       index_size,
       leaf_pages,
       avg_leaf_density,
       leaf_fragmentation
FROM pgstatindex('public.orders_customer_id_idx');

Metoden med estimeringsforespørgsler

Når du slet ikke har råd til en scanning, beregner den community-udviklede forespørgsel til estimering af oppustning (fra check_postgres / pgsql-bloat-estimation) den forventede størrelse ud fra statistik og sammenligner den med den faktiske størrelse.

Dens grundidé er:

  • Hent den gennemsnitlige rækkebredde fra pg_statistic (den avg_width pr. kolonne, som ANALYZE registrerede).
  • Tilføj overhead for rækkeheader og justering, og dividér derefter tabelstørrelsen med det forventede antal tupler pr. side.
  • Forskellen mellem forventede og faktiske sider er den estimerede oppustning.

Metoden er omtrent­lig og følsom over for forældet statistik, men kører på millisekunder i hele databasen.

Hvorfor estimater afviger

Estimeringsnøjagtigheden kollapser, når inputtene er forkerte. Vær opmærksom på disse faldgruber:

  • Forældet statistik: Hvis ANALYZE ikke er kørt for nylig, er avg_width og rækkeantallene forældede. Kør ANALYZE, før du stoler på estimaterne.
  • Brede kolonner med variabel længde: Meget varierende bredder for text/jsonb gør gennemsnit pr. række upålidelige.
  • TOAST: Store værdier, der er gemt uden for rækken, ligger i en separat TOAST-tabel; heap-estimater overser denne lagerplads fuldstændigt.
  • Fillfactor: En tabel, der er oprettet med fillfactor < 100, efterlader med vilje ledig plads — det er ikke oppustning.

Kontrollér altid et overraskende estimat med pgstattuple_approx(), før du handler.

ANALYZE public.orders;

Glem ikke TOAST-tabellen

Store kolonneværdier flyttes til en skjult TOAST-tabel, som oppustes separat. En heap kan se ren ud, mens dens TOAST-relation er enorm.

  • Find TOAST-relationen via pg_class.reltoastrelid.
  • Kør pgstattuple() direkte på TOAST-relationens OID for at måle dens døde plads.

Tabeller med hyppigt opdaterede jsonb- eller bytea-kolonner skjuler ofte det meste af deres oppustning i TOAST.

SELECT c.relname,
       pg_size_pretty(pg_relation_size(c.reltoastrelid)) AS toast_size,
       t.dead_tuple_percent
FROM pg_class c
CROSS JOIN LATERAL pgstattuple(c.reltoastrelid) AS t
WHERE c.relname = 'orders'
  AND c.reltoastrelid <> 0;

Fra tal til beslutning

Når du har nøjagtige tal, skal du knytte dem til en løsning:

  • dead_tuple_percent høj, free_percent høj: autovacuum er bagefter — en almindelig VACUUM (eller justering af autovacuum) frigiver normalt genanvendelig plads uden at omskrive filen.
  • free_percent meget høj, men tabellen bliver ikke mindre: Filen har ledig plads til sidst, som VACUUM ikke kan returnere til operativsystemet — overvej pg_repack (online) eller VACUUM FULL (låser tabellen).
  • Indeksets avg_leaf_density lav: REINDEX CONCURRENTLY.

Fastlæg en tærskel (f.eks. at du kun handler over cirka 20 % oppustning og en betydelig absolut størrelse), så du ikke kører forstyrrende vedligeholdelse for ubetydelige gevinster.

Hurtigt tjek

Du har mistanke om, at en tabel på 400 GB er kraftigt oppustet, og du ønsker et nøjagtigt tal for oppustningen med mindst mulig I/O-påvirkning, når autovacuum holder visibility map forholdsvis opdateret. Hvilket værktøj passer bedst?

Opsummering

Du har nu en lagdelt metode til at kvantificere oppustning, før du handler:

  • Første vurdering med pg_stat_user_tables (andelen af n_dead_tup) — gratis og øjeblikkelig.
  • Estimér i hele databasen med statistikbaserede forespørgsler om oppustning — hurtigt, men bekræft med en aktuel ANALYZE.
  • Bekræft præcist med pgstattuple(), eller med pgstattuple_approx() på store tabeller, hvor du læser dead_tuple_percent og free_percent.
  • Indeks: Brug pgstatindex(), og hold øje med avg_leaf_density og leaf_fragmentation.
  • Glem ikke TOAST, og træk tilsigtet ledig plads fra på grund af fillfactor.

Først når tallene overskrider en meningsfuld tærskel, vælger du VACUUM, pg_repack, VACUUM FULL eller REINDEX — målingen styrer løsningen, aldrig omvendt.

Gratis at komme i gang

Lær SQL med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
22
Lektioner
88

Ofte stillede spørgsmål

Er lektionen “Præcis måling af tabel- og indeks-bloat” gratis?

Ja — alle 3 lektioner i læringssporet Ydelsesoptimering og optimering af forespørgsler i PostgreSQL, inklusive “Præcis måling af tabel- og indeks-bloat”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Ydelsesoptimering og optimering af forespørgsler i PostgreSQL-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Præcis måling af tabel- og indeks-bloat”?

Brug pgstattuple og estimeringsforespørgsler til at kvantificere ubrugt plads, før De vælger en løsning. Du øver dig i Ydelsesoptimering og optimering af forespørgsler i PostgreSQL med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Ydelsesoptimering og optimering af forespørgsler i PostgreSQL?

Der kræves ingen tidligere erfaring. Ydelsesoptimering og optimering af forespørgsler i PostgreSQL på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 1 af 4.

Hvor lang tid tager lektionen “Præcis måling af tabel- og indeks-bloat”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Ydelsesoptimering og optimering af forespørgsler i PostgreSQL-lektion?

Ja. Alle Ydelsesoptimering og optimering af forespørgsler i PostgreSQL-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Præcis måling af tabel- og indeks-bloat
  2. Frigivelse af plads med pg_repack
  3. Justering af fillfactor for tabeller med mange opdateringer
  4. TOAST-interne detaljer og lagring af store værdier
← Tilbage til Ydelsesoptimering og optimering af forespørgsler i PostgreSQL