Usamos PostgreSQL 12 e temos uma tabela simples, event_participant
armazenando 100 GB de dados.
event_participant
possui todos os índices necessários, então todas as linhas são buscadas usando-os, ou seja, nenhuma linha é buscada usando varreduras sequenciais.
Normalmente, ele busca 65 linhas/segundo, mas um dia, às 10h, executamos uma campanha planejada em que o número de linhas buscadas usando varreduras de índice saltou para 5,4 milhões de linhas/segundo. No entanto, o número de varreduras de índice permaneceu o mesmo, 200 por segundo. O conteúdo da tabela começou a mudar lentamente, mas não o suficiente para acionar a análise automática porque autovacuum_analyze_scale_factor
é 0,01 ou 1% do tamanho da tabela.
Vale ressaltar que configuramos plan_cache_mode
o TO force_custom_plan
neste banco de dados porque nosso aplicativo usa Demonstrativos Preparados e queremos evitar planos genéricos por causa de campanhas ativas.
Após 3 horas de grande carga de CPU e varreduras de índice, realizamos manualmente um ANALYZE
dos event_participant
, e o número de linhas ativas buscadas pelas varreduras de índice caiu imediatamente de 5,4 milhões de linhas/s para 450 linhas/s .
Estou tentando descobrir como o ANALYZE
comando afetou o número de linhas ativas obtidas pelas varreduras de índice, enquanto o número de varreduras de índice permaneceu o mesmo.
Atualização - incluindo mais detalhes sobre a estrutura e índices da tabela.
> \d+ event_participant
Table "public.event_participant"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
----------+------------------+-----------+----------+---------+----------+--------------+-------------
event_id | text | | not null | | extended | |
user_id | bigint | | not null | | plain | |
progress | text | | not null | | extended | |
level | integer | | not null | 0 | plain | |
quality | double precision | | | | plain | |
Indexes:
"event_participant_pkey" PRIMARY KEY, btree (user_id, event_id)
"event_participant_event_id_idx" btree (event_id)
Access method: heap
Assim, às 10h, começou a campanha com um novo evento (new event_id), e a event_participant
tabela começou a crescer. A cada login do usuário, o aplicativo backend, sabendo quais eventos estão ativos, seleciona todas as entradas por user_id e event_id: SELECT * from event_participant WHERE user_id=? AND event_id=?;
para acompanhar o progresso do usuário.