Agende a coleta de lixo (VACUUM) para horários de baixa demanda e evite que o autovacuum compita com sua carga de trabalho nos períodos de pico.
Pré-requisitos
Antes de começar, verifique se você tem:
Um cluster PolarDB for PostgreSQL (Compatible with Oracle) na versão 2.0, revisão 2.0.14.12.24.0 ou posterior
Execute SHOW polardb_version; para verificar a versão de revisão. Para atualizar, consulte Atualizar as versões . Você também pode visualizar a versão de revisão no console .
Contexto
O PolarDB for PostgreSQL (Compatible with Oracle) usa o autovacuum — processo de limpeza em segundo plano nativo do PostgreSQL — para recuperar tuplas mortas, atualizar estatísticas e evitar o estouro de ID de transação. O autovacuum inicia automaticamente quando o parâmetro autovacuum está definido como true.
Esse processo é acionado quando o número de linhas alteradas ou a idade do banco de dados ultrapassa um determinado limiar. Para mais informações sobre as condições, consulte 20.10. Limpeza automática. Durante os horários de pico, grandes volumes de dados mudam rapidamente e disparam o autovacuum com frequência. Isso gera três problemas:
Alto uso de recursos. O autovacuum compete diretamente com sua aplicação por CPU e I/O. Na prática, o consumo de CPU e o throughput de I/O do autovacuum podem ocupar o primeiro lugar entre todos os processos durante o horário de pico.


Bloqueio de requisições de leitura/escrita devido a tabelas travadas. Ao recuperar páginas vazias, o autovacuum mantém um bloqueio exclusivo que impede brevemente outras operações na tabela e degrada o desempenho no pior momento possível.
Invalidação do cache de planos. Quando o autovacuum coleta estatísticas, ele invalida o cache de planos existente. Nos horários de pico, muitas conexões podem regenerar planos de execução simultaneamente e aumentar os tempos de resposta.
O recurso de cache global de planos (GPC) no PolarDB for PostgreSQL (Compatible with Oracle) reduz o impacto da invalidação do cache de planos. Para obter detalhes, consulte Cache global de planos .
A causa raiz é que o PostgreSQL nativo não possui o conceito de horários de baixa demanda. O PolarDB for PostgreSQL (Compatible with Oracle) adiciona esse conceito: você define uma janela de tempo e o cluster utiliza recursos ociosos nessa janela para executar o vacuum completo no banco de dados. Isso reduz a frequência de execução do autovacuum durante os horários de pico e libera CPU e I/O para sua aplicação.
Benefícios
Agendar a coleta de lixo para horários de baixa demanda oferece os seguintes benefícios:
Menor contenção de recursos. O autovacuum roda com menos frequência nos horários de pico e reduz a competição por CPU e I/O com sua carga de trabalho.
Idade do banco de dados mais saudável. Mais IDs de transação são recuperados fora do pico, o que diminui o risco de estouro de ID de transação e indisponibilidade do banco de dados.
Planos de consulta melhores. Estatísticas mais atualizadas ajudam o otimizador de consultas a escolher planos de execução mais precisos e reduzem consultas lentas.
Menos operações bloqueadas. Agendar operações de autovacuum que travam tabelas para fora do pico reduz a chance de bloqueio em requisições de leitura e escrita.
Redução de invalidações do cache de planos. As invalidações causadas pela coleta de estatísticas do autovacuum ocorrem nos horários de baixa demanda, em vez de momentos de carga máxima.
Observações de uso
Os métodos descritos neste documento exigem a versão de revisão 2.0.14.12.24.0 ou posterior. Se o seu cluster executa uma revisão anterior, atualize-o no console do PolarDB. Para obter detalhes, consulte Atualização de versão secundária .
Para configurar os horários de baixa demanda sem atualizar: entre em contato conosco e forneça o horário de início, horário de término e fuso horário. Essa configuração de backend pode parar de funcionar após eventos de operações e manutenção (O&M), como failover primário/secundário, alterações de configuração ou troca de zona. Atualize para a versão secundária mais recente para obter uma solução permanente.
Configurar a coleta de lixo em horários de baixa demanda
Etapa 1: Criar a extensão
Crie a extensão polar_advisor no banco de dados postgres e em todos os bancos de dados que necessitam de coleta de lixo.
CREATE EXTENSION IF NOT EXISTS polar_advisor;
Para atualizar uma extensão polar_advisor existente:
ALTER EXTENSION polar_advisor UPDATE;
Etapa 2: Definir a janela de baixa demanda
Execute a seguinte instrução no banco de dados postgres para definir os horários de baixa demanda:
-- Execute in the postgres database.
SELECT polar_advisor.set_advisor_window(start_time, end_time);
|
Parâmetro |
Descrição |
|
|
Horário de início da janela de baixa demanda |
|
|
Horário de término da janela de baixa demanda |
A janela entra em vigor a partir do dia atual. O cluster executa a coleta de lixo diariamente durante essa janela.
Apenas a janela definida no banco de dados postgres tem efeito.
O deslocamento do fuso horário deve corresponder à configuração de fuso horário do cluster; caso contrário, a janela não terá efeito.
Exemplo: Defina 23:00–02:00 (UTC+8) como a janela de baixa demanda.
SELECT polar_advisor.set_advisor_window(start_time => '23:00:00+08', end_time => '02:00:00+08');
Etapa 3: Verificar a janela
Execute as seguintes instruções no banco de dados postgres para confirmar se a janela está configurada corretamente:
-- View window details.
SELECT * FROM polar_advisor.get_advisor_window();
-- View window duration (in seconds).
SELECT polar_advisor.get_advisor_window_length();
-- Check whether the current time falls within the window.
SELECT now(), * FROM polar_advisor.is_in_advisor_window();
-- View time remaining until the window starts (in seconds).
SELECT * FROM polar_advisor.get_secs_to_advisor_window_start();
-- View time remaining until the window ends (in seconds).
SELECT * FROM polar_advisor.get_secs_to_advisor_window_end();
Saída de exemplo:
-- Window details
postgres=# SELECT * FROM polar_advisor.get_advisor_window();
start_time | end_time | enabled | last_error_time | last_error_detail | others
-------------+-------------+---------+-----------------+-------------------+--------
23:00:00+08 | 02:00:00+08 | t | | |
(1 row)
-- Window duration
postgres=# SELECT polar_advisor.get_advisor_window_length() / 3600.0 AS "Window duration/h";
Window duration/h
--------------------
3.0000000000000000
(1 row)
-- Current time vs. window
postgres=# SELECT now(), * FROM polar_advisor.is_in_advisor_window();
now | is_in_advisor_window
-------------------------------+----------------------
2024-04-01 07:40:37.733911+00 | f
(1 row)
-- Time to window start
postgres=# SELECT * FROM polar_advisor.get_secs_to_advisor_window_start();
secs_to_window_start | time_now | window_start | window_end
----------------------+--------------------+--------------+-------------
26362.265179 | 07:40:37.734821+00 | 15:00:00+00 | 18:00:00+00
(1 row)
-- Time to window end
postgres=# SELECT * FROM polar_advisor.get_secs_to_advisor_window_end();
secs_to_window_end | time_now | window_start | window_end
--------------------+--------------------+--------------+-------------
36561.870337 | 07:40:38.129663+00 | 15:00:00+00 | 18:00:00+00
(1 row)
Etapa 4: Ativar ou desativar a janela
A janela vem ativada por padrão. Se precisar suspender temporariamente a coleta de lixo em horários de baixa demanda — por exemplo, para evitar conflitos com operações de O&M planejadas — desative a janela e reative-a ao concluir.
-- Execute in the postgres database.
-- Disable the window.
SELECT polar_advisor.disable_advisor_window();
-- Re-enable the window.
SELECT polar_advisor.enable_advisor_window();
-- Check whether the window is enabled.
SELECT polar_advisor.is_advisor_window_enabled();
Saída de exemplo:
-- The window is currently enabled.
postgres=# SELECT polar_advisor.is_advisor_window_enabled();
is_advisor_window_enabled
---------------------------
t
(1 row)
-- Disable the window.
postgres=# SELECT polar_advisor.disable_advisor_window();
disable_advisor_window
------------------------
(1 row)
-- Confirm it is disabled.
postgres=# SELECT polar_advisor.is_advisor_window_enabled();
is_advisor_window_enabled
---------------------------
f
(1 row)
-- Re-enable the window.
postgres=# SELECT polar_advisor.enable_advisor_window();
enable_advisor_window
-----------------------
(1 row)
-- Confirm it is re-enabled.
postgres=# SELECT polar_advisor.is_advisor_window_enabled();
is_advisor_window_enabled
---------------------------
t
(1 row)
Configurações avançadas
Excluir tabelas específicas da coleta de lixo
Quando os horários de baixa demanda estão ativos, o sistema seleciona automaticamente as tabelas para coleta de lixo. Para excluir uma tabela, adicione-a à lista de bloqueios de VACUUM & ANALYZE.
-- Execute in the business database that contains the table.
-- Add a table to the blacklist.
SELECT polar_advisor.add_relation_to_vacuum_analyze_blacklist(schema_name, relation_name);
-- Check whether a table is in the blacklist.
SELECT polar_advisor.is_relation_in_vacuum_analyze_blacklist(schema_name, relation_name);
-- List all blacklisted tables.
SELECT * FROM polar_advisor.get_vacuum_analyze_blacklist();
Saída de exemplo:
-- Add public.t1 to the blacklist.
postgres=# SELECT polar_advisor.add_relation_to_vacuum_analyze_blacklist('public', 't1');
add_relation_to_vacuum_analyze_blacklist
---------------------------
t
(1 row)
-- Confirm the table is in the blacklist.
postgres=# SELECT polar_advisor.is_relation_in_vacuum_analyze_blacklist('public', 't1');
is_relation_in_vacuum_analyze_blacklist
--------------------------
t
(1 row)
-- List all blacklisted tables.
postgres=# SELECT * FROM polar_advisor.get_vacuum_analyze_blacklist();
schema_name | relation_name | action_type
-------------+---------------+----------------
public | t1 | VACUUM ANALYZE
(1 row)
Impedir a execução da coleta de lixo durante tráfego residual de pico
O sistema monitora as conexões ativas durante a janela de baixa demanda. Se as conexões ativas excederem o limiar, ele ignora a coleta de lixo naquele ciclo. Isso evita que as operações de vacuum interfiram em qualquer tráfego de negócios que se estenda para a janela de baixa demanda.
O limiar padrão é de 5 a 10 conexões, dependendo do número de núcleos de CPU no cluster.
-- Execute in the postgres database.
-- Get the current threshold.
SELECT polar_advisor.get_active_user_conn_num_limit();
-- Query the actual number of active connections.
-- Alternatively, check in the PolarDB console:
-- Performance Monitoring > Advanced Monitoring > Standard View > Sessions > active_session.
SELECT COUNT(*) FROM pg_catalog.pg_stat_activity sa
JOIN pg_catalog.pg_user u ON sa.usename = u.usename
WHERE sa.state = 'active'
AND sa.backend_type = 'client backend'
AND NOT u.usesuper;
-- Set a custom threshold (overrides the default).
SELECT polar_advisor.set_active_user_conn_num_limit(active_user_conn_limit);
-- Reset to the default threshold.
SELECT polar_advisor.unset_active_user_conn_num_limit();
Exemplo: O limiar padrão é 5, mas as conexões ativas reais são 8. Aumente o limiar para 10 para permitir que a coleta de lixo prossiga.
-- Default threshold is 5.
postgres=# SELECT polar_advisor.get_active_user_conn_num_limit();
NOTICE: get active user conn limit by CPU cores number
get_active_user_conn_num_limit
--------------------------------
5
(1 row)
-- Actual active connections: 8 (exceeds the threshold of 5, so GC is skipped).
postgres=# SELECT COUNT(*) FROM pg_catalog.pg_stat_activity sa JOIN pg_catalog.pg_user u ON sa.usename = u.usename
postgres-# WHERE sa.state = 'active' AND sa.backend_type = 'client backend' AND NOT u.usesuper;
count
-------
8
(1 row)
-- Raise the threshold to 10 so GC runs even with 8 active connections.
postgres=# SELECT polar_advisor.set_active_user_conn_num_limit(10);
set_active_user_conn_num_limit
--------------------------------
(1 row)
-- Confirm the new threshold.
postgres=# SELECT polar_advisor.get_active_user_conn_num_limit();
NOTICE: get active user conn limit from table
get_active_user_conn_num_limit
--------------------------------
10
(1 row)
-- Reset to the default.
postgres=# SELECT polar_advisor.unset_active_user_conn_num_limit();
unset_active_user_conn_num_limit
----------------------------------
(1 row)
-- Threshold returns to 5.
postgres=# SELECT polar_advisor.get_active_user_conn_num_limit();
NOTICE: get active user conn limit by CPU cores number
get_active_user_conn_num_limit
--------------------------------
5
(1 row)
Visualizar resultados da operação
Os resultados da coleta de lixo em horários de baixa demanda ficam registrados em tabelas de log no banco de dados postgres. As tabelas de log retêm dados dos últimos 90 dias.
Verificação rápida
Execute esta consulta para confirmar que a coleta de lixo em horários de baixa demanda está em execução e ver quando os últimos ciclos foram concluídos:
-- Execute in the postgres database.
SELECT COUNT(*) AS "Tables/indexes",
MIN(start_time) AS "Start time",
MAX(end_time) AS "End time",
exec_id AS "Round"
FROM polar_advisor.advisor_log
GROUP BY exec_id
ORDER BY exec_id DESC;
Saída de exemplo mostrando três rodadas recentes, cada uma processando cerca de 4.390 tabelas entre 01:00 e 04:00:
Tables/indexes | Start time | End time | Round
---------------+--------------------------------+--------------------------------+------
4391 | 2024-09-23 01:00:09.413901 +08 | 2024-09-23 03:25:39.029702 +08 | 139
4393 | 2024-09-22 01:03:07.365759 +08 | 2024-09-22 03:37:45.227067 +08 | 138
4393 | 2024-09-21 01:03:08.094989 +08 | 2024-09-21 03:45:20.280011 +08 | 137
Esquemas das tabelas de log
polar_advisor.db_level_advisor_log registra uma entrada por banco de dados por rodada de coleta de lixo.
CREATE TABLE polar_advisor.db_level_advisor_log (
id BIGSERIAL PRIMARY KEY,
exec_id BIGINT,
start_time TIMESTAMP WITH TIME ZONE,
end_time TIMESTAMP WITH TIME ZONE,
db_name NAME,
event_type VARCHAR(100),
total_relation BIGINT,
acted_relation BIGINT,
age_before BIGINT,
age_after BIGINT,
others JSONB
);
|
Parâmetro |
Descrição |
|
|
Chave primária, valores em ordem crescente |
|
|
Número da rodada. Uma rodada é executada uma vez por dia e pode abranger vários bancos de dados, portanto, várias linhas no mesmo dia compartilham o mesmo |
|
|
Horário de início da operação de coleta de lixo |
|
|
Horário de término da operação de coleta de lixo |
|
|
Banco de dados no qual a coleta de lixo foi realizada |
|
|
Tipo de operação. Fixo como |
|
|
Número total de subtabelas e índices elegíveis para coleta de lixo |
|
|
Número de subtabelas e índices realmente processados |
|
|
Idade do banco de dados antes da coleta de lixo |
|
|
Idade do banco de dados após a coleta de lixo |
|
|
Estatísticas estendidas. |
polar_advisor.advisor_log registra uma entrada por tabela ou índice processado. Várias linhas nesta tabela correspondem a uma única linha em db_level_advisor_log.
CREATE TABLE polar_advisor.advisor_log (
id BIGSERIAL PRIMARY KEY,
exec_id BIGINT,
start_time TIMESTAMP WITH TIME ZONE,
end_time TIMESTAMP WITH TIME ZONE,
db_name NAME,
schema_name NAME,
relation_name NAME,
event_type VARCHAR(100),
sql_cmd TEXT,
detail TEXT,
tuples_deleted BIGINT,
tuples_dead_now BIGINT,
tuples_now BIGINT,
pages_scanned BIGINT,
pages_pinned BIGINT,
pages_frozen_now BIGINT,
pages_truncated BIGINT,
pages_now BIGINT,
idx_tuples_deleted BIGINT,
idx_tuples_now BIGINT,
idx_pages_now BIGINT,
idx_pages_deleted BIGINT,
idx_pages_reusable BIGINT,
size_before BIGINT,
size_now BIGINT,
age_decreased BIGINT,
others JSONB
);
|
Parâmetro |
Descrição |
|
|
Chave primária, valores em ordem crescente |
|
|
Número da rodada (corresponde a |
|
|
Horário de início da operação de coleta de lixo |
|
|
Horário de término da operação de coleta de lixo |
|
|
Banco de dados no qual a coleta de lixo foi realizada |
|
|
Schema da tabela ou índice processado |
|
|
Nome da tabela ou índice processado |
|
|
Tipo de operação. Fixo como |
|
|
Comando executado. Exemplo: |
|
|
Resultados detalhados, por exemplo, a saída de |
|
|
Tuplas mortas recuperadas da tabela |
|
|
Tuplas mortas restantes após a coleta de lixo |
|
|
Tuplas vivas na tabela após a coleta de lixo |
|
|
Páginas verificadas durante a coleta de lixo |
|
|
Páginas que não puderam ser excluídas devido a referências de cache |
|
|
Páginas congeladas após a coleta de lixo |
|
|
Páginas vazias excluídas ou truncadas |
|
|
Total de páginas na tabela após a coleta de lixo |
|
|
Tuplas mortas recuperadas dos índices |
|
|
Tuplas vivas nos índices após a coleta de lixo |
|
|
Páginas de índice após a coleta de lixo |
|
|
Páginas de índice excluídas |
|
|
Páginas de índice marcadas como reutilizáveis |
|
|
Tamanho da tabela ou índice antes da coleta de lixo |
|
|
Tamanho da tabela ou índice após a coleta de lixo |
|
|
Redução na idade da tabela |
|
|
Estatísticas estendidas |
Coletar estatísticas
Consulte o número de tabelas ou índices processados por dia:
-- Execute in the postgres database.
SELECT start_time::pg_catalog.date AS "Date",
count(*) AS "Tables/indexes"
FROM polar_advisor.advisor_log
GROUP BY start_time::pg_catalog.date
ORDER BY start_time::pg_catalog.date DESC, count(*) DESC;
Saída de exemplo:
Date | Tables/indexes
------------+---------------
2024-09-23 | 4391
2024-09-22 | 4393
2024-09-21 | 4393
Consulte por data e banco de dados para ver como o trabalho é distribuído entre os bancos de dados:
-- Execute in the postgres database.
SELECT start_time::date AS "Date",
db_name AS "DB",
count(*) AS "Tables/indexes"
FROM polar_advisor.advisor_log
WHERE now() - start_time::date < INTERVAL '3 days'
GROUP BY start_time::date, db_name
ORDER BY start_time::date DESC, count(*) DESC;
Saída de exemplo:
Date | DB | Tables/indexes
------------+--------------+---------------
2024-03-05 | db_123456789 | 697
2024-03-05 | db_123 | 277
2024-03-04 | db_123456789 | 695
2024-03-04 | db_123 | 267
2024-03-04 | db_12345 | 174
2024-03-03 | postgres | 65
(6 rows)
Dados detalhados
Consulte o resumo de benefícios por banco de dados por rodada:
-- Execute in the postgres database.
SELECT id,
start_time AS "Start time",
end_time AS "End time",
db_name AS "DB",
event_type AS "Operation type",
total_relation AS "Total tables",
acted_relation AS "Processed tables",
CASE WHEN others->>'cluster_age_before' IS NOT NULL AND others->>'cluster_age_after' IS NOT NULL
THEN (others->>'cluster_age_before')::BIGINT - (others->>'cluster_age_after')::BIGINT
ELSE NULL END AS "Age decrease",
CASE WHEN others->>'db_size_before' IS NOT NULL AND others->>'db_size_after' IS NOT NULL
THEN (others->>'db_size_before')::BIGINT - (others->>'db_size_after')::BIGINT
ELSE NULL END AS "Storage reduction"
FROM polar_advisor.db_level_advisor_log
ORDER BY id DESC;
Saída de exemplo:
id | Start time | End time | DB | Operation type | Total tables | Processed tables | Age decrease | Storage reduction
------+-------------------------------+-------------------------------+--------------+----------------+--------------+------------------+--------------+------------------
1184 | 2024-03-05 00:44:26.776894+08 | 2024-03-05 00:45:56.396519+08 | db_12345 | VACUUM | 174 | 164 | 694 | 0
1183 | 2024-03-05 00:43:30.243505+08 | 2024-03-05 00:44:26.695602+08 | db_123456789 | VACUUM | 100 | 90 | 396 | 0
1182 | 2024-03-05 00:41:47.70952+08 | 2024-03-05 00:43:30.172527+08 | db_12345 | VACUUM | 163 | 153 | 701 | 0
(3 rows)
Consulte detalhes por tabela para as operações mais recentes:
-- Execute in the postgres database.
SELECT start_time AS "Start time",
end_time AS "End time",
db_name AS "DB",
schema_name AS "Schema",
relation_name AS "Table/index",
event_type AS "Operation type",
tuples_deleted AS "Dead tuples reclaimed",
pages_scanned AS "Pages scanned",
pages_truncated AS "Empty pages reclaimed",
idx_tuples_deleted AS "Index dead tuples reclaimed",
idx_pages_deleted AS "Index pages reclaimed",
age_decreased AS "Table age decrease"
FROM polar_advisor.advisor_log
ORDER BY id DESC LIMIT 3;
Saída de exemplo:
Start time | End time | DB | Schema | Table/index | Operation type | Dead tuples reclaimed | Pages scanned | Empty pages reclaimed | Index dead tuples reclaimed | Index pages reclaimed | Table age decrease
-------------------------------+-------------------------------+----------+--------+-------------+----------------+-----------------------+---------------+-----------------------+-----------------------------+-----------------------+-------------------
2024-03-05 00:45:56.204254+08 | 2024-03-05 00:45:56.357263+08 | db_12345 | public | cccc | VACUUM | 0 | 33 | 0 | 0 | 0 | 1345944
2024-03-05 00:45:56.068499+08 | 2024-03-05 00:45:56.200036+08 | db_12345 | public | aaaa | VACUUM | 0 | 28 | 0 | 0 | 0 | 1345946
2024-03-05 00:45:55.945677+08 | 2024-03-05 00:45:56.065316+08 | db_12345 | public | bbbb | VACUUM | 0 | 0 | 0 | 0 | 0 | 1345947
(3 rows)
Encontrar rodadas com maior redução na idade do banco de dados
O PolarDB for PostgreSQL (Compatible with Oracle) possui aproximadamente 2,1 bilhões de IDs de transação disponíveis. A idade do banco de dados mede quantos foram consumidos. Quando a idade atinge 2,1 bilhões, os IDs de transação sofrem estouro e o banco de dados fica indisponível. Para verificar a idade atual do cluster, execute:
-- Execute in the postgres database.
-- Alternatively, check in the PolarDB console:
-- Performance Monitoring > Advanced Monitoring > Standard View > Vacuum- > db_age.
SELECT MAX(pg_catalog.age(datfrozenxid)) AS "Cluster age" FROM pg_catalog.pg_database;
Para encontrar as rodadas que mais reduziram a idade do cluster:
-- Execute in the postgres database.
-- Find the top 3 rounds by cluster age decrease.
SELECT id,
exec_id AS "Round",
start_time AS "Start time",
end_time AS "End time",
db_name AS "DB",
event_type AS "Operation type",
CASE WHEN others->>'cluster_age_before' IS NOT NULL AND others->>'cluster_age_after' IS NOT NULL
THEN (others->>'cluster_age_before')::BIGINT - (others->>'cluster_age_after')::BIGINT
ELSE NULL END AS "Age decrease"
FROM polar_advisor.db_level_advisor_log
ORDER BY "Age decrease" DESC NULLS LAST LIMIT 3;
-- Then drill into a specific round (replace 91 with the exec_id from the previous query).
SELECT id,
start_time AS "Start time",
end_time AS "End time",
db_name AS "DB",
schema_name AS "Schema",
relation_name AS "Table name",
sql_cmd AS "Command",
event_type AS "Operation type",
age_decreased AS "Age decrease"
FROM polar_advisor.advisor_log
WHERE exec_id = 91
ORDER BY "Age decrease" DESC NULLS LAST;
Saída de exemplo:
-- Top rounds by cluster age decrease.
postgres=# SELECT id, exec_id AS "Round", start_time AS "Start time", end_time AS "End time", db_name AS "DB", event_type AS "Operation type", CASE WHEN others->>'cluster_age_before' IS NOT NULL AND others->>'cluster_age_after' IS NOT NULL THEN (others->>'cluster_age_before')::BIGINT - (others->>'cluster_age_after')::BIGINT ELSE NULL END AS "Age decrease" FROM polar_advisor.db_level_advisor_log ORDER BY "Age decrease" DESC NULLS LAST LIMIT 3;
id | Round | Start time | End time | DB | Operation type | Age decrease
-----+-------+-------------------------------+-------------------------------+---------------+----------------+-------------
259 | 91 | 2024-02-22 00:00:18.847978+08 | 2024-02-22 00:14:18.785085+08 | aaaaaaaaaaaaa | VACUUM | 9275406
256 | 90 | 2024-02-21 00:00:39.607552+08 | 2024-02-21 00:00:42.054733+08 | bbbbbbbbbbbbb | VACUUM | 7905122
262 | 92 | 2024-02-23 00:00:05.999423+08 | 2024-02-23 00:00:08.411993+08 | postgres | VACUUM | 578308
-- Drill into Round 91: the age decrease comes from vacuuming pg_catalog system tables.
postgres=# SELECT id, start_time AS "Start time", end_time AS "End time", db_name AS "DB", schema_name AS "Schema", relation_name AS "Table name", event_type AS "Operation type", age_decreased AS "Age decrease" FROM polar_advisor.advisor_log WHERE exec_id = 91 ORDER BY "Age decrease" DESC NULLS LAST;
id | Start time | End time | DB | Schema | Table name | Operation type | Age decrease
----------+-------------------------------+-------------------------------+-----+------------+--------------------+----------------+-------------
43933 | 2024-02-22 00:00:19.070493+08 | 2024-02-22 00:00:19.090822+08 | abc | pg_catalog | pg_subscription | VACUUM | 27787409
43935 | 2024-02-22 00:00:19.116292+08 | 2024-02-22 00:00:19.13875+08 | abc | pg_catalog | pg_database | VACUUM | 27787408
43936 | 2024-02-22 00:00:19.140992+08 | 2024-02-22 00:00:19.171938+08 | abc | pg_catalog | pg_db_role_setting | VACUUM | 27787408
-- Current cluster age: ~20 million, well below the 2.1 billion limit.
postgres=> SELECT MAX(pg_catalog.age(datfrozenxid)) AS "Cluster age" FROM pg_catalog.pg_database;
Cluster age
-----------
20874380
(1 row)
Exemplos de otimização
Os exemplos a seguir mostram resultados reais de clusters após a ativação da coleta de lixo em horários de baixa demanda.
Melhorias no bloqueio de tabelas travadas e na invalidação do cache de planos não são facilmente capturadas em gráficos e não aparecem aqui.
Os resultados variam conforme a carga de trabalho. Clusters com alta carga ao longo do dia ou com tarefas de análise de dados, importação ou atualização de visões materializadas agendadas durante os horários de baixa demanda podem apresentar melhorias menores.
Uso de memória
Após ativar os horários de baixa demanda, o pico de memória do autovacuum caiu de 2,06 GB para 37 MB — uma redução de 98%.

O pico total de memória em todos os processos diminuiu de 10 GB para 8 GB, uma redução de 20%.

Throughput de I/O
O pico de IOPS do PolarDB File System (PFS) do autovacuum caiu cerca de 50%.

O pico total de IOPS do PFS em todos os processos diminuiu de 35.000 para cerca de 21.000, uma redução de 40%.

O pico de throughput do PFS do autovacuum caiu de 225 MB para 173 MB (23%). O throughput médio caiu de 65,5 MB para 42,5 MB (35%), com picos menos frequentes e mais estreitos.

Uso de CPU
O uso de CPU pelo autovacuum diminuiu gradualmente após a ativação dos horários de baixa demanda e caiu cerca de 50% no pico.

Número de execuções do autovacuum
O número de execuções do autovacuum durante os horários de pico caiu de 2 para 1.

Idade do banco de dados
Em dois dias após a ativação dos horários de baixa demanda, um cluster recuperou mais de 1 bilhão de IDs de transação e reduziu a idade do banco de dados de mais de 1 bilhão para menos de 0,1 bilhão. Isso reduz significativamente o risco de estouro de ID de transação.
