On Sun, 1 Aug 2021 at 10:27, Ayub M <hia...@gmail.com> wrote:
>
> Hello, when maintenance_work_mem and autovacuum_work_mem are set, my
understanding is that the vacuum and autovacuum sessions should be limited
to use the memory limits set by these parameters. But I am seeing more
memory being used than these limits by autovacuum sessions, any reason why
this would happen?
>
> Please see below examples, where maintenance_work_mem is set to 20mb and
shared_buffers is 128mb. When I see the memory for this session in top, it
shows 162mb. But when default_statistics_target is increased to 3000, the
session usage is 463mb, which is way more than 20mb maintenance_work_mem
and 128mb shared_buffer. Shouldn't the process memory be capped to 20+128mb?
>
>
> postgres=# show maintenance_work_mem ;
>  maintenance_work_mem
> ----------------------
>  20MB
> (1 row)
> postgres=# vacuum analyze mdm_context;
> VACUUM
> postgres=# show shared_buffers;
>  shared_buffers
> ----------------
>  128MB
> (1 row)
>
>    PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+
COMMAND

>  62246 postgres  20   0  422892 165996 139068 R 57.1 15.7  25:06.34
postgres: postgres postgres [local] VACUUM
>

your assumption may be right, but i am not sure of the interpretation from
top.
I have to admit I am not great at understanding top output (RES vs VIRT) in
general when it comes to limits.

I did a demo cgroup setup with limit max memory to 5MB, started psql using
cgexec and ran vacuum with maintenance_work_mem = 1024 (1MB)
it ran fine. I am not sharing the results, it may divert the convo.

The vacuum process seems to get dead tuples as a function of
maintenance_work_mem, and if it is small, it will loop many times (the run
may take longer)
but respect that limit (+- tolerance). also, vacuum verbose only prints CPU
usage per iteration of removing dead tupes from pages, but no mem usage. so
idk.

DEBUG:  StartTransaction(1) name: unnamed; blockState: DEFAULT; state:
INPROGRESS, xid/subid/cid: 0/1/0
DEBUG:  CommitTransaction(1) name: unnamed; blockState: STARTED; state:
INPROGRESS, xid/subid/cid: 0/1/0
DEBUG:  StartTransaction(1) name: unnamed; blockState: DEFAULT; state:
INPROGRESS, xid/subid/cid: 0/1/0
DEBUG:  vacuuming "public.t"
DEBUG:  launched 1 parallel vacuum worker for index vacuuming (planned: 1)
DEBUG:  scanned index "t_col1_idx" to remove 174518 row versions
DETAIL:  CPU: user: 0.04 s, system: 0.00 s, elapsed: 0.04 s
DEBUG:  CommitTransaction(1) name: unnamed; blockState: STARTED; state:
INPROGRESS, xid/subid/cid: 0/1/0
DEBUG:  StartTransaction(1) name: unnamed; blockState: DEFAULT; state:
INPROGRESS, xid/subid/cid: 0/1/0
DEBUG:  starting parallel vacuum worker for bulk delete
DEBUG:  scanned index "t_col1_idx1" to remove 174518 row versions
DETAIL:  CPU: user: 0.01 s, system: 0.00 s, elapsed: 0.02 s
DEBUG:  CommitTransaction(1) name: unnamed; blockState:
PARALLEL_INPROGRESS; state: INPROGRESS, xid/subid/cid: 0/1/0
DEBUG:  "t": removed 174518 dead item identifiers in 1424 pages


i can be corrected, as i could not really get values from the source to
profile mem usage per function call.
from the source,
i have a feeling, shared_mem has nothing to do with vacuum, but i may be
wrong.

I think someone who is more aware of the process/code can throw more light.
but thanks for asking. will learn something figuring this out.

FROM THE CODE COMMENTS:
 * The major space usage for LAZY VACUUM is storage for the array of dead
tuple
 * TIDs.  We want to ensure we can vacuum even the very largest relations
with
 * finite memory space usage.  To do that, we set upper bounds on the
number of
 * tuples we will keep track of at once.
 *
 * We are willing to use at most maintenance_work_mem (or perhaps
 * autovacuum_work_mem) memory space to keep track of dead tuples.  We
 * initially allocate an array of TIDs of that size, with an upper limit
that
 * depends on table size (this limit ensures we don't allocate a huge area
 * uselessly for vacuuming small tables).  If the array threatens to
overflow,
 * we suspend the heap scan phase and perform a pass of index cleanup and
page
 * compaction, then resume the heap scan with an empty TID array.
 *
 * If we're processing a table with no indexes, we can just vacuum each page
 * as we go; there's no need to save up multiple tuples to minimize the
number
 * of index scans performed.  So we don't use maintenance_work_mem memory
for
 * the TID array, just enough to hold as many heap tuples as fit on one
page.
 *
 * Lazy vacuum supports parallel execution with parallel worker processes.
In
 * a parallel vacuum, we perform both index vacuum and index cleanup with
 * parallel worker processes.  Individual indexes are processed by one
vacuum
 * process.  At the beginning of a lazy vacuum (at lazy_scan_heap) we
prepare
 * the parallel context and initialize the DSM segment that contains shared
 * information as well as the memory space for storing dead tuples.  When
 * starting either index vacuum or index cleanup, we launch parallel worker
 * processes.  Once all indexes are processed the parallel worker processes
 * exit.  After that, the leader process re-initializes the parallel context
 * so that it can use the same DSM for multiple passes of index vacuum and
 * for performing index cleanup.  For updating the index statistics, we need
 * to update the system table and since updates are not allowed during
 * parallel mode we update the index statistics after exiting from the
 * parallel mode.
 *

vacuumlazy.c
<https://github.com/postgres/postgres/blob/70685385d70f8da73ab189a72f46311091ff09be/src/backend/access/heap/vacuumlazy.c#L12>
compute_max_dead_tuples
<https://github.com/postgres/postgres/blob/70685385d70f8da73ab189a72f46311091ff09be/src/backend/access/heap/vacuumlazy.c#L3457>
parallel_workers
<https://github.com/postgres/postgres/blob/70685385d70f8da73ab189a72f46311091ff09be/src/backend/access/heap/vacuumlazy.c#L3802>

Reply via email to