Bloating, jak tomu předejdu a jak se vypořádám s následky

28 views
Skip to first unread message

Jan Michálek

unread,
Nov 19, 2025, 3:40:41 AMNov 19
to postgr...@googlegroups.com
Čau
Mám tady problém, na který nestačím a potřeboval bych nasměrovat.
V databázi nám začaly trvat (i jednoduché) dotazy uplný nesmysl (pár set řádků, jednoduchý selekt s order by podle PK malé jednotky sekund), tak za mnou přišli kolegové, jestli něco nevykoukám.
S vydatnou pomocí chatgpt jsem se dopracoval k tomu, že tabulka má giga, index má čtvrt giga (při sedmistech záznamech) a v tabulce je 94 procent dead tuples.
VACUUM FULL nepomohlo, VACUUM FREEZE taky ne (jak je to možný?).
V databázi máme streaming repliku (repmgr a pgpool), tabulky, kterých se to týká jsou často dávkově přepisovány (někdy i stylem nalejt vylejt). AUTOVACUUM běží. hot_standby_feedback máme off. Logická replikace (pokud vím a nejsem si tím zcela jist) tak tam neběží.

Potřebuju nasměrovat, jak zjistím co děláme blbě, že se tohle děje a jak to vyřeším. Podle pg_stat_activity (na primáře) nevidim aktivní dotaz, který by zasahoval do těchto tabulek. Na stendbajku se nedostanu.
Dál bych potřeboval zjistit, jak se zbavím aktuálního zákysu. Pokud existuje jiná cesta, než to celý zadumpovat a vyrobit si to vedle (což mi radí AI a podle mě je to příliš poraženecké).

Díky

Je;

--
Jelen
Starší čeledín datovýho chlíva

Pavel Stehule

unread,
Nov 19, 2025, 4:03:35 AMNov 19
to postgr...@googlegroups.com
Ahoj

st 19. 11. 2025 v 9:40 odesílatel Jan Michálek <godzil...@gmail.com> napsal:
Čau
Mám tady problém, na který nestačím a potřeboval bych nasměrovat.
V databázi nám začaly trvat (i jednoduché) dotazy uplný nesmysl (pár set řádků, jednoduchý selekt s order by podle PK malé jednotky sekund), tak za mnou přišli kolegové, jestli něco nevykoukám.
S vydatnou pomocí chatgpt jsem se dopracoval k tomu, že tabulka má giga, index má čtvrt giga (při sedmistech záznamech) a v tabulce je 94 procent dead tuples.
VACUUM FULL nepomohlo, VACUUM FREEZE taky ne (jak je to možný?).

VACUUM FREEZE pomoct nemusi, ale ze nepomuze VACUUM FULL to je hodne divne (tomu bych skoro neveril)
 
V databázi máme streaming repliku (repmgr a pgpool), tabulky, kterých se to týká jsou často dávkově přepisovány (někdy i stylem nalejt vylejt). AUTOVACUUM běží. hot_standby_feedback máme off. Logická replikace (pokud vím a nejsem si tím zcela jist) tak tam neběží.

Potřebuju nasměrovat, jak zjistím co děláme blbě, že se tohle děje a jak to vyřeším. Podle pg_stat_activity (na primáře) nevidim aktivní dotaz, který by zasahoval do těchto tabulek. Na stendbajku se nedostanu.
Dál bych potřeboval zjistit, jak se zbavím aktuálního zákysu. Pokud existuje jiná cesta, než to celý zadumpovat a vyrobit si to vedle (což mi radí AI a podle mě je to příliš poraženecké).

zkontroluj jestli ti neco neblokuje promazavani dead tuples

(2025-11-19 09:56:02) postgres=# VACUUM VERBOSE pg_class ;
INFO:  vacuuming "postgres.pg_catalog.pg_class"
INFO:  finished vacuuming "postgres.pg_catalog.pg_class": index scans: 0
pages: 0 removed, 14 remain, 14 scanned (100.00% of total), 0 eagerly scanned
tuples: 0 removed, 422 remain, 0 are dead but not yet removable
removable cutoff: 761, which was 0 XIDs old when operation ended
new relfrozenxid: 761, which is 11 XIDs ahead of previous value
frozen: 0 pages from table (0.00% of total) had 0 tuples frozen
visibility map: 0 pages set all-visible, 0 pages set all-frozen (0 were all-visible)
index scan not needed: 0 pages from table (0.00% of total) had 0 dead item identifiers removed
avg read rate: 63.723 MB/s, avg write rate: 12.745 MB/s
buffer usage: 40 hits, 5 reads, 1 dirtied
WAL usage: 1 records, 1 full page images, 7923 bytes, 7804 full page image bytes, 0 buffers full
system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
VACUUM

dohledej radek s tuples: 0 removed, 422 remain, 0 are dead but not yet removable 

Klicova je ta cast "0 are dead but not yet removable". Za provozu tam prakticky nikdy nebudes mit 0, ale pokud by tam bylo nejake velke cislo, ktere se navic zvetsuje, tak mas problem.

Co muze zpusobovat, ze mrtve verze nejsou odstranitelné?

1. zapomenuty nepouzivany replikacni slot
2. otevrena transakce
3. neukoncena 2pc transakce
4. neuzavrena transakce na replikce s hot_standby_feedback
5. nedobihajici (padajici) vacuum - zkontrolovat logy
6. podle mne by to mohla delat i zaseknuta logicka replikace - mozna by to mohlo byt videt v pg_stat_replication nebo pg_stat_replication_slot

Pavel





 

Díky

Je;

--
Jelen
Starší čeledín datovýho chlíva

--
Tuto zprávu jste obdrželi, protože jste přihlášeni k odběru skupiny „PostgreSQL-cz“ ve Skupinách Google.
Chcete-li zrušit odběr skupiny a přestat dostávat e‑maily ze skupiny, zašlete e-mail na adresu postgresql-c...@googlegroups.com.
Tuto diskuzi najdete na adrese https://groups.google.com/d/msgid/postgresql-cz/CAAYBy8YJqZA63LsqASSFMJp1XCxcychbuuCrMST_E%3D95aQzA0g%40mail.gmail.com.

Jan Michálek

unread,
Nov 19, 2025, 4:26:37 AMNov 19
to postgr...@googlegroups.com
Díky za reakci Pavle

st 19. 11. 2025 v 10:03 odesílatel Pavel Stehule <pavel....@gmail.com> napsal:
Ahoj

st 19. 11. 2025 v 9:40 odesílatel Jan Michálek <godzil...@gmail.com> napsal:
Čau
Mám tady problém, na který nestačím a potřeboval bych nasměrovat.
V databázi nám začaly trvat (i jednoduché) dotazy uplný nesmysl (pár set řádků, jednoduchý selekt s order by podle PK malé jednotky sekund), tak za mnou přišli kolegové, jestli něco nevykoukám.
S vydatnou pomocí chatgpt jsem se dopracoval k tomu, že tabulka má giga, index má čtvrt giga (při sedmistech záznamech) a v tabulce je 94 procent dead tuples.
VACUUM FULL nepomohlo, VACUUM FREEZE taky ne (jak je to možný?).

VACUUM FREEZE pomoct nemusi, ale ze nepomuze VACUUM FULL to je hodne divne (tomu bych skoro neveril)

main=# SELECT *
FROM pgstattuple('rl_table');
┌────────────┬─────────────┬───────────┬───────────────┬──────────────────┬────────────────┬────────────────────┬────────────┬──────────────┐
│ table_len  │ tuple_count │ tuple_len │ tuple_percent │ dead_tuple_count │ dead_tuple_len │ dead_tuple_percent │ free_space │ free_percent │
╞════════════╪═════════════╪═══════════╪═══════════════╪══════════════════╪════════════════╪════════════════════╪════════════╪══════════════╡
│ 1064542208 │         671 │    199522 │          0.02 │          3413377 │     1008836906 │              94.77 │   21575388 │         2.03 │
└────────────┴─────────────┴───────────┴───────────────┴──────────────────┴────────────────┴────────────────────┴────────────┴──────────────┘
(1 row)

main=# VACUUM FULL rl_table;
VACUUM
main=# SELECT *
FROM pgstattuple('rl_table');
┌────────────┬─────────────┬───────────┬───────────────┬──────────────────┬────────────────┬────────────────────┬────────────┬──────────────┐
│ table_len  │ tuple_count │ tuple_len │ tuple_percent │ dead_tuple_count │ dead_tuple_len │ dead_tuple_percent │ free_space │ free_percent │
╞════════════╪═════════════╪═══════════╪═══════════════╪══════════════════╪════════════════╪════════════════════╪════════════╪══════════════╡
│ 1064542208 │         671 │    199522 │          0.02 │          3413377 │     1008836906 │              94.77 │   21575388 │         2.03 │
└────────────┴─────────────┴───────────┴───────────────┴──────────────────┴────────────────┴────────────────────┴────────────┴──────────────┘
(1 row)

 
 
V databázi máme streaming repliku (repmgr a pgpool), tabulky, kterých se to týká jsou často dávkově přepisovány (někdy i stylem nalejt vylejt). AUTOVACUUM běží. hot_standby_feedback máme off. Logická replikace (pokud vím a nejsem si tím zcela jist) tak tam neběží.

Potřebuju nasměrovat, jak zjistím co děláme blbě, že se tohle děje a jak to vyřeším. Podle pg_stat_activity (na primáře) nevidim aktivní dotaz, který by zasahoval do těchto tabulek. Na stendbajku se nedostanu.
Dál bych potřeboval zjistit, jak se zbavím aktuálního zákysu. Pokud existuje jiná cesta, než to celý zadumpovat a vyrobit si to vedle (což mi radí AI a podle mě je to příliš poraženecké).

zkontroluj jestli ti neco neblokuje promazavani dead tuples

(2025-11-19 09:56:02) postgres=# VACUUM VERBOSE pg_class ;
INFO:  vacuuming "postgres.pg_catalog.pg_class"
INFO:  finished vacuuming "postgres.pg_catalog.pg_class": index scans: 0
pages: 0 removed, 14 remain, 14 scanned (100.00% of total), 0 eagerly scanned
tuples: 0 removed, 422 remain, 0 are dead but not yet removable
removable cutoff: 761, which was 0 XIDs old when operation ended
new relfrozenxid: 761, which is 11 XIDs ahead of previous value
frozen: 0 pages from table (0.00% of total) had 0 tuples frozen
visibility map: 0 pages set all-visible, 0 pages set all-frozen (0 were all-visible)
index scan not needed: 0 pages from table (0.00% of total) had 0 dead item identifiers removed
avg read rate: 63.723 MB/s, avg write rate: 12.745 MB/s
buffer usage: 40 hits, 5 reads, 1 dirtied
WAL usage: 1 records, 1 full page images, 7923 bytes, 7804 full page image bytes, 0 buffers full
system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
VACUUM

dohledej radek s tuples: 0 removed, 422 remain, 0 are dead but not yet removable 

Klicova je ta cast "0 are dead but not yet removable". Za provozu tam prakticky nikdy nebudes mit 0, ale pokud by tam bylo nejake velke cislo, ktere se navic zvetsuje, tak mas problem.



main=# VACUUM VERBOSE rl_table;
INFO:  vacuuming "sprava.rl_table"
INFO:  launched 4 parallel vacuum workers for index cleanup (planned: 4)
INFO:  table "rl_table": found 0 removable, 3414048 nonremovable row versions in 129949 out of 129949 pages
DETAIL:  3413377 dead row versions cannot be removed yet, oldest xmin: 4133120
Skipped 0 pages due to buffer pins, 0 frozen pages.
CPU: user: 3.71 s, system: 0.19 s, elapsed: 3.95 s.
INFO:  vacuuming "pg_toast.pg_toast_1899271"
INFO:  table "pg_toast_1899271": found 0 removable, 0 nonremovable row versions in 0 out of 0 pages
DETAIL:  0 dead row versions cannot be removed yet, oldest xmin: 4133120
Skipped 0 pages due to buffer pins, 0 frozen pages.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
VACUUM
main=#

 
Co muze zpusobovat, ze mrtve verze nejsou odstranitelné?

1. zapomenuty nepouzivany replikacni slot
2. otevrena transakce
3. neukoncena 2pc transakce
4. neuzavrena transakce na replikce s hot_standby_feedback
5. nedobihajici (padajici) vacuum - zkontrolovat logy
6. podle mne by to mohla delat i zaseknuta logicka replikace - mozna by to mohlo byt videt v pg_stat_replication nebo pg_stat_replication_slot

Pavel

Prověřím

Ještě jednou díky

Je; 





 

Díky

Je;

--
Jelen
Starší čeledín datovýho chlíva

--
Tuto zprávu jste obdrželi, protože jste přihlášeni k odběru skupiny „PostgreSQL-cz“ ve Skupinách Google.
Chcete-li zrušit odběr skupiny a přestat dostávat e‑maily ze skupiny, zašlete e-mail na adresu postgresql-c...@googlegroups.com.
Tuto diskuzi najdete na adrese https://groups.google.com/d/msgid/postgresql-cz/CAAYBy8YJqZA63LsqASSFMJp1XCxcychbuuCrMST_E%3D95aQzA0g%40mail.gmail.com.

--
Tuto zprávu jste obdrželi, protože jste přihlášeni k odběru skupiny „PostgreSQL-cz“ ve Skupinách Google.
Chcete-li zrušit odběr skupiny a přestat dostávat e‑maily ze skupiny, zašlete e-mail na adresu postgresql-c...@googlegroups.com.

Antonin Houska

unread,
Nov 19, 2025, 4:40:42 AMNov 19
to postgr...@googlegroups.com
Jan Michálek <godzil...@gmail.com> wrote:

> Díky za reakci Pavle
>
> st 19. 11. 2025 v 10:03 odesílatel Pavel Stehule <pavel....@gmail.com> napsal:
>
> VACUUM FREEZE pomoct nemusi, ale ze nepomuze VACUUM FULL to je hodne divne (tomu bych skoro neveril)
>
> main=# SELECT *
> FROM pgstattuple('rl_table');
> ┌────────────┬─────────────┬───────────┬───────────────┬──────────────────┬────────────────┬────────────────────┬────────────┬──────────────┐
>
> │ table_len │ tuple_count │ tuple_len │ tuple_percent │ dead_tuple_count │ dead_tuple_len │ dead_tuple_percent │ free_space │ free_percent
> │
> ╞════════════╪═════════════╪═══════════╪═══════════════╪══════════════════╪════════════════╪════════════════════╪════════════╪══════════════╡
>
> │ 1064542208 │ 671 │ 199522 │ 0.02 │ 3413377 │ 1008836906 │ 94.77 │ 21575388 │ 2.03 │
> └────────────┴─────────────┴───────────┴───────────────┴──────────────────┴────────────────┴────────────────────┴────────────┴──────────────┘

VACUUM FULL odstrani jen radky ve stavu DEAD, ale ty co jsou RECENTLY_DEAD,
(tzn. smazane, ale nektere transakce resp. replikacni sloty je stale
potrebuji), necha byt. A pgstattuple tyto pripady nerozlisuje a oboji pocita
do dead_tuple_....

Tonda H.

zdenek....@gmail.com

unread,
Nov 19, 2025, 4:43:36 AMNov 19
to PostgreSQL-cz

Pavel Stehule

unread,
Nov 19, 2025, 4:44:49 AMNov 19
to postgr...@googlegroups.com


st 19. 11. 2025 v 10:26 odesílatel Jan Michálek <godzil...@gmail.com> napsal:
Díky za reakci Pavle

st 19. 11. 2025 v 10:03 odesílatel Pavel Stehule <pavel....@gmail.com> napsal:
Ahoj

st 19. 11. 2025 v 9:40 odesílatel Jan Michálek <godzil...@gmail.com> napsal:
Čau
Mám tady problém, na který nestačím a potřeboval bych nasměrovat.
V databázi nám začaly trvat (i jednoduché) dotazy uplný nesmysl (pár set řádků, jednoduchý selekt s order by podle PK malé jednotky sekund), tak za mnou přišli kolegové, jestli něco nevykoukám.
S vydatnou pomocí chatgpt jsem se dopracoval k tomu, že tabulka má giga, index má čtvrt giga (při sedmistech záznamech) a v tabulce je 94 procent dead tuples.
VACUUM FULL nepomohlo, VACUUM FREEZE taky ne (jak je to možný?).

VACUUM FREEZE pomoct nemusi, ale ze nepomuze VACUUM FULL to je hodne divne (tomu bych skoro neveril)

main=# SELECT *
FROM pgstattuple('rl_table');
┌────────────┬─────────────┬───────────┬───────────────┬──────────────────┬────────────────┬────────────────────┬────────────┬──────────────┐
│ table_len  │ tuple_count │ tuple_len │ tuple_percent │ dead_tuple_count │ dead_tuple_len │ dead_tuple_percent │ free_space │ free_percent │
╞════════════╪═════════════╪═══════════╪═══════════════╪══════════════════╪════════════════╪════════════════════╪════════════╪══════════════╡
│ 1064542208 │         671 │    199522 │          0.02 │          3413377 │     1008836906 │              94.77 │   21575388 │         2.03 │
└────────────┴─────────────┴───────────┴───────────────┴──────────────────┴────────────────┴────────────────────┴────────────┴──────────────┘
(1 row)

main=# VACUUM FULL rl_table;
VACUUM
main=# SELECT *
FROM pgstattuple('rl_table');
┌────────────┬─────────────┬───────────┬───────────────┬──────────────────┬────────────────┬────────────────────┬────────────┬──────────────┐
│ table_len  │ tuple_count │ tuple_len │ tuple_percent │ dead_tuple_count │ dead_tuple_len │ dead_tuple_percent │ free_space │ free_percent │
╞════════════╪═════════════╪═══════════╪═══════════════╪══════════════════╪════════════════╪════════════════════╪════════════╪══════════════╡
│ 1064542208 │         671 │    199522 │          0.02 │          3413377 │     1008836906 │              94.77 │   21575388 │         2.03 │
└────────────┴─────────────┴───────────┴───────────────┴──────────────────┴────────────────┴────────────────────┴────────────┴──────────────┘
(1 row)


tak jsem chytrejsi - VACUUM FULL tedy zkopiruje i neodstranitelne mrtve verze. To jsem nevedel.

 

Jan Michálek

unread,
Nov 19, 2025, 4:46:55 AMNov 19
to postgr...@googlegroups.com
Díky. A dovedu si nějak vypsat každý zvlášť?

st 19. 11. 2025 v 10:40 odesílatel 'Antonin Houska' via PostgreSQL-cz <postgr...@googlegroups.com> napsal:
--
Tuto zprávu jste obdrželi, protože jste přihlášeni k odběru skupiny PostgreSQL-cz ve Skupinách Google.
Chcete-li zrušit odběr skupiny a přestat dostávat e‑maily ze skupiny, zašlete e-mail na adresu postgresql-c...@googlegroups.com.

Jan Michálek

unread,
Nov 19, 2025, 4:47:10 AMNov 19
to postgr...@googlegroups.com
Super, díky.

st 19. 11. 2025 v 10:43 odesílatel zdenek....@gmail.com <zdenek....@gmail.com> napsal:
--
Tuto zprávu jste obdrželi, protože jste přihlášeni k odběru skupiny „PostgreSQL-cz“ ve Skupinách Google.
Chcete-li zrušit odběr skupiny a přestat dostávat e‑maily ze skupiny, zašlete e-mail na adresu postgresql-c...@googlegroups.com.

Jan Michálek

unread,
Nov 19, 2025, 4:47:35 AMNov 19
to postgr...@googlegroups.com
Našel jsem tam tohle

┌─[ RECORD 1 ]─────┬───────────────────────────────┐
│ datid            │                               │
│ datname          │                               │
│ pid              │ 1261817                       │
│ leader_pid       │                               │
│ usesysid         │ 10                            │
│ usename          │ postgres                      │
│ application_name │                               │
│ client_addr      │                               │
│ client_hostname  │                               │
│ client_port      │                               │
│ backend_start    │ 2025-10-25 17:33:57.293116+02 │
│ xact_start       │                               │
│ query_start      │                               │
│ state_change     │                               │
│ wait_event_type  │ Activity                      │
│ wait_event       │ LogicalLauncherMain           │
│ state            │                               │
│ backend_xid      │                               │
│ backend_xmin     │                               │
│ query_id         │                               │
│ query            │                               │
│ backend_type     │ logical replication launcher  │
└──────────────────┴───────────────────────────────┘


st 19. 11. 2025 v 10:44 odesílatel Pavel Stehule <pavel....@gmail.com> napsal:

Pavel Stehule

unread,
Nov 19, 2025, 4:53:47 AMNov 19
to postgr...@googlegroups.com


st 19. 11. 2025 v 10:47 odesílatel Jan Michálek <godzil...@gmail.com> napsal:
Našel jsem tam tohle

┌─[ RECORD 1 ]─────┬───────────────────────────────┐
│ datid            │                               │
│ datname          │                               │
│ pid              │ 1261817                       │
│ leader_pid       │                               │
│ usesysid         │ 10                            │
│ usename          │ postgres                      │
│ application_name │                               │
│ client_addr      │                               │
│ client_hostname  │                               │
│ client_port      │                               │
│ backend_start    │ 2025-10-25 17:33:57.293116+02 │
│ xact_start       │                               │
│ query_start      │                               │
│ state_change     │                               │
│ wait_event_type  │ Activity                      │
│ wait_event       │ LogicalLauncherMain           │
│ state            │                               │
│ backend_xid      │                               │
│ backend_xmin     │                               │
│ query_id         │                               │
│ query            │                               │
│ backend_type     │ logical replication launcher  │
└──────────────────┴───────────────────────────────┘

tohle je normalni

 

Jan Michálek

unread,
Nov 19, 2025, 4:58:23 AMNov 19
to postgr...@googlegroups.com
Ahoj, všem.
Problém jsem vyřešil, visel mi tam v pg_stat_activity dotaz, kterej jsem si myslel, že ničemu neškodí (protože nesahal do žádných tabulek), ale nakonec jsem ho stejně zabil a to vacuum odblokovalo.
Díky všem za pomoc.

Je;

st 19. 11. 2025 v 10:53 odesílatel Pavel Stehule <pavel....@gmail.com> napsal:

Pavel Stehule

unread,
Nov 19, 2025, 5:23:52 AMNov 19
to postgr...@googlegroups.com


st 19. 11. 2025 v 10:58 odesílatel Jan Michálek <godzil...@gmail.com> napsal:
Ahoj, všem.
Problém jsem vyřešil, visel mi tam v pg_stat_activity dotaz, kterej jsem si myslel, že ničemu neškodí (protože nesahal do žádných tabulek), ale nakonec jsem ho stejně zabil a to vacuum odblokovalo.
Díky všem za pomoc.

:-)

Pavel
 

David Turoň

unread,
Nov 19, 2025, 9:44:27 AMNov 19
to postgr...@googlegroups.com
ano - ono totiz VACUUM resi az mrtve radky transakci, ktere uz nikdo nemuze videt, ale bezici dotaz nebo idle in trans. to zablokuje, proto bloat ...

st 19. 11. 2025 v 10:58 odesílatel Jan Michálek <godzil...@gmail.com> napsal:
Reply all
Reply to author
Forward
0 new messages