Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vffks-003zN0-2O for pgsql-admin@arkaria.postgresql.org; Tue, 13 Jan 2026 14:52:23 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vffkr-005DK5-1i for pgsql-admin@arkaria.postgresql.org; Tue, 13 Jan 2026 14:52:21 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vffkr-005DJx-0S for pgsql-admin@lists.postgresql.org; Tue, 13 Jan 2026 14:52:21 +0000 Received: from mail-oi1-x235.google.com ([2607:f8b0:4864:20::235]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1vffkp-000EwF-0E for pgsql-admin@lists.postgresql.org; Tue, 13 Jan 2026 14:52:21 +0000 Received: by mail-oi1-x235.google.com with SMTP id 5614622812f47-459ac2f1dc2so4402869b6e.3 for ; Tue, 13 Jan 2026 06:52:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1768315937; x=1768920737; darn=lists.postgresql.org; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=XhEpH2kovCeddUVHIEbfPYj71VAeXeQzicf2JVe7cT8=; b=lHFZXMhf4m7NagZLGlsmr7MOld0daeLpvsrZJnNt8Qb/IpexxeO4ryBxMJnuGUt7VZ rcH3c/j4mGKti/jWUIQ3YMU4i7+Ja+s4nkCQYwWegwOu6iJ7ssc38rviJBrNdztPz/hg X3kN2K/D3PRfVEAfosdo7PMvzTj1/D/23S5BMP/lb3caNpPzqOqBU0gxp0Jt3xoYcnxX ZJiDW2+zcjIOAK1C/XwM+CZ8S2l01Zf/wwem7ypqn4hvkx/6W2+fKpl5QPCBJRI5MZFt XCQ9gzO9vS4b15C69LxP934TGmfTugCgarbFcZTK2zc9As8P0ps9C6r18/LN+T5eksah jb0A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1768315937; x=1768920737; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=XhEpH2kovCeddUVHIEbfPYj71VAeXeQzicf2JVe7cT8=; b=rKTYLTuDgBUI5pHbOCXjS6qQDzrVE7D7KRQrzcBhNReQf6RVno/ZGogaXczh4ftoK4 dYMnSHCJutIACQG4XmyBoampJTfT3WJDBVZupMhLYRQd4NupdyyvoEp4nyefpi97Hf8l Dn1R4+BVNof833UIJmCc58F/z/a6XVnX1Wx7bgjgumXGIpnHv6G41ro/n3EuOthOUMlT nJQEiYVDztYLf4eAwV80qj77yvpdteco3VPiIVPJ9AITBhmtDX0DhOoITFcOC1yHzOTs buXqyujJvOj0kev3/kFMwaK4h5G5CyhGfWgirSIP/zx8U2cZnABYI3dO3PS9O+8V5k6Q EP7Q== X-Gm-Message-State: AOJu0Yx+fFcj/L3/2sk6vOL4i2BmEkZc9wLtIeVz2dzR8M8pR8ZtKPp6 QJt/ZWNQqJ5cFYXpb9Ue08/kQMuCd72wFOuiVxA0FjZmE9agP/6FZhbQ/sPLBQ+jwadc3Jm1f8c d6+FpAeFwv2eHXWHgMgJlnfhm9F1rJljU+T3g X-Gm-Gg: AY/fxX5YyYuus9dBFMzJU+ep1NAayi4P7mN5TANsBCPIKevrYGOjkqOgGp+4vc0wBQl NhH/fGpzY9//A+sSkYgWBdBg9dZP4Wo0fg8aICml4p2SKewrpKGOWb9/rt6u6X8d48XygG4EQ7j b3VGNRnA2osUgrnyG+/Gr2inEYy5j+TRJyL4ICb3DMX+br7tRGLIvPzaPWjI7H75kWc/2zoDF4g vziKePPCedC1ybFv+WDt6R25Jq2cgY6Fn+caDI9quOZt9UQSokLx2WEdWhVnF/n+c2L7qc0D/Cw br/x08k= X-Google-Smtp-Source: AGHT+IEquNQuleR2+omByamXCen1mL4c/d01KuenIxX8cL8gat8O/Q5mKRGE1SK17v7aHcGqsTk4XqrVNkeVCCFZDS0= X-Received: by 2002:a05:6808:2215:b0:450:1eaf:ee2a with SMTP id 5614622812f47-45a6bf1a1d0mr9409263b6e.54.1768315936518; Tue, 13 Jan 2026 06:52:16 -0800 (PST) MIME-Version: 1.0 References: <81c12173-6da4-43e9-866a-00321a00415a@pscs.co.uk> <05e54ad2-0d6b-49b0-834a-4107fee68c51@pscs.co.uk> In-Reply-To: <05e54ad2-0d6b-49b0-834a-4107fee68c51@pscs.co.uk> From: Ron Johnson Date: Tue, 13 Jan 2026 09:52:05 -0500 X-Gm-Features: AZwV_Qjh6fRgLFbMkm7Pi49sixUhAth5vYQ2wvgB-IYUeElu4Il_QJuk_zGAWK4 Message-ID: Subject: Re: VACUUM/ANALYZE Strategy for Low-Activity PostgreSQL 15 Instance To: Pgsql-admin Content-Type: multipart/alternative; boundary="0000000000003f353d06484623e9" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --0000000000003f353d06484623e9 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Tue, Jan 13, 2026 at 6:39=E2=80=AFAM Paul Smith* wrote= : > On 13/01/2026 11:09, Gabriel Guillem Barcel=C3=B3 Soteras wrote: > > CheckMK, as Anton case, monitors several metrics with a PostgreSQL > integration . In this case is last > vacuum and analyse . It > generates a monitoring item with pre-populated thresholds. > > You are not wrong at all. The* lazy admin problem *is that adjusting > monitoring system on per-table basis is very time consuming, compared wit= h > a weekly manual vacuum + analyze that makes 'no harm' out of business > hours. I think i will go the weekly vacumdb route, or I will have to > deactivate VACUUM and ANALYSE monitoring items. > > OK > > As you say, it does no harm, so you could do that, but I'd argue that it'= s > also unnecessary. Personally, I'd disable those vacuum & analyze monitors= . > 'last autovacuum' and 'last autoanalyze' are a bit more useful monitoring > stats than last manual vacuum/analyze, unless you have a company policy > mandating otherwise. > I created a view that joins pg_stat_user_tables to pg_class and then does: select sut.table_name , GREATEST(sut.last_vacuum, sut.last_autovacuum)::timestamp(3) without time zone AS latest_vacuum , GREATEST(sut.last_analyze, sut.last_autoanalyze)::timestamp(3) without time zone AS latest_analyze , sut.n_mod_since_analyze as mod_ana , sut.n_dead_tup as dead_rows , cl.reltuples::bigint as row_count , case when cl.reltuples > 0 then (100.0*sut.n_mod_since_analyze/cl.reltuples)::decimal(6,2) else null end as mod_pct , case when cl.reltuples > 0 then (100.0*sut.n_dead_tup/cl.reltuples)::decimal(6,2) else null end as dead_pct That shows percentages as well as counts. Very helpful. Even then, I've just looked at one of our databases that's been running > since 2019, and the 'last vacuum' AND 'last autovacuum' times are still > null for a lot of the tables. It's simply unnecessary to vacuum those > tables, or even analyze them, as they just hold a few rows of data that > rarely change. > And yet sometimes the course of least resistance is to make the metricians happy. Fortunately, my metricians are reasonable enough to let me exclude rows where (n_mod_since_analyze =3D 0 OR n_dead_tup =3D 0). If OP's metricians are not reasonable, or there's too much hassle in modifying the filter to exclude unmodified tables, then just "vacuumdb --analyze -t foo -t bar -t ..." all tables that haven't been vacuumed or analyzed in the last, for example, 28 days. A bash+psql command can easily generate a "-t t1 -t t2 -t t3 ..." string that you pass to vacuumdb. > I'd say you're better monitoring other metrics, eg "n_mod_since_analyze" = & > "n_dead_tup", to see if vacuum/analyze is necessary for that table. That > will show if autovacuum/analyze isn't keeping up with the job. > --=20 Death to , and butter sauce. Don't boil me, I'm still alive. lobster! --0000000000003f353d06484623e9 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
On Tue, Jan 13, 2026 at 6:39=E2=80=AFAM P= aul Smith* <paul@pscs.co.uk> w= rote:
=20 =20 =20
On 13/01/2026 11:09, Gabriel Guillem Barcel=C3=B3 Soteras wrote:

CheckMK, as Anton case, monitors several metrics with a PostgreSQL = integration=C2=A0. In this case= is last vacuum and analyse. It generates a monitoring item with pre-populated thresholds.

You are not wrong at all. The=C2=A0lazy admin=C2=A0problem is that adjusting monitoring system on per-table basis is very time consuming, compared with =C2=A0a weekly manual vacuum + analyze that makes 'no harm' out of business hours. I thi= nk i will go the weekly vacumdb route, or I will have to deactivate VACUUM and ANALYSE monitoring items.

OK

As you say, it does no harm, so you could do that, but I'd argue that it's also unnecessary. Personally, I'd disable those vac= uum & analyze monitors. 'last autovacuum' and 'last autoa= nalyze' are a bit more useful monitoring stats than last manual vacuum/analyze, unless you have a company policy mandating otherwise.


I created a view= that joins pg_stat_user_tables to pg_class and then does:
select sut.table_name
=C2=A0 =C2=A0 =C2=A0, GREATEST(= sut.last_vacuum, sut.last_autovacuum)::timestamp(3) without time zone AS la= test_vacuum
=C2=A0 =C2=A0 =C2=A0, GREATEST(sut.last_analyze, sut.last_au= toanalyze)::timestamp(3) without time zone AS latest_analyze
=C2=A0 =C2= =A0 =C2=A0, sut.n_mod_since_analyze as mod_ana
=C2=A0 =C2=A0 =C2=A0, sut= .n_dead_tup as dead_rows
=C2=A0 =C2=A0 =C2=A0, cl.reltuples::bigint as r= ow_count
=C2=A0 =C2=A0 =C2=A0, case
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0when cl.reltuples > 0 then (100.0*sut.n_mod_since_analyze/cl.r= eltuples)::decimal(6,2)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0else nu= ll
=C2=A0 =C2=A0 =C2=A0 =C2=A0end as mod_pct
=C2=A0 =C2=A0 =C2=A0, ca= se
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0when cl.reltuples > 0 the= n (100.0*sut.n_dead_tup/cl.reltuples)::decimal(6,2)
=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0else null
=C2=A0 =C2=A0 =C2=A0 =C2=A0end as dead_pc= t

That shows percentages as well as cou= nts.=C2=A0 Very helpful.

Even then, I've just looked at one of our databases that's b= een running since 2019, and the 'last vacuum' AND 'last autov= acuum' times are still null for a lot of the tables. It's simply unnecessary to vacuum those tables, or even analyze them, as they just hold a few rows of data that rarely change.


And yet sometimes the course of least resistance is t= o make the metricians happy.=C2=A0 Fortunately, my metricians=C2=A0are reas= onable enough=C2=A0to let me exclude rows where (n_mod_since_analyze =3D 0 = OR=C2=A0n_dead_tup =3D 0).

If OP's metricians = are not reasonable, or there's too much hassle in modifying the filter = to exclude unmodified tables, then just "vacuumdb --analyze -t foo -t = bar -t ..." all tables that haven't been vacuumed or analyzed in t= he last, for example, 28 days.

A bash+psql command= can easily generate a "-t t1 -t t2 -t t3 ..." string that you pa= ss to vacuumdb.

I'd say you're better monitoring other metrics, eg "n_mod_since_analyze" & "n_dead_tup", to see = if vacuum/analyze is necessary for that table. That will show if autovacuum/analyze isn't keeping up with the job.


--
Death to <Redacted>, a= nd butter sauce.
Don't boil me, I'm still alive.
&= lt;Redacted> lobster!
--0000000000003f353d06484623e9--