SELECT remove linhas mortas como o VACUUM?

9

Eu estava brincando VACUUMe notei algum comportamento inesperado em que SELECTas linhas de uma tabela parecem reduzir o trabalho que VACUUMdeve ser feito depois.

Dados de teste

Nota: o vácuo automático está desativado

CREATE TABLE numbers (num bigint);
ALTER TABLE numbers SET (
  autovacuum_enabled = 'f',
  toast.autovacuum_enabled = 'f'
);

INSERT INTO numbers SELECT generate_series(1, 5000);

Julgamento 1

Agora, executamos uma atualização em todas as linhas,

UPDATE numbers SET num = 0;

E quando corremos VACUUM (VERBOSE) numbers;, chegamos,

INFO:  vacuuming "public.numbers"
INFO:  "numbers": removed 5000 row versions in 23 pages
INFO:  "numbers": found 5000 removable, 5000 nonremovable row versions in 45 out of 45 pages
DETAIL:  0 dead row versions cannot be removed yet, oldest xmin: 6585
There were 0 unused item pointers.

Julgamento 2

Agora emitimos outro UPDATE, mas desta vez adicionamos um SELECTdepois,

UPDATE numbers SET num = 1;
SELECT * FROM numbers;

E quando corremos VACUUM (VERBOSE) numbers;, chegamos,

INFO:  vacuuming "public.numbers"
INFO:  "numbers": removed 56 row versions in 22 pages
INFO:  "numbers": found 56 removable, 5000 nonremovable row versions in 45 out of 45 pages
DETAIL:  0 dead row versions cannot be removed yet, oldest xmin: 6586
There were 56 unused item pointers.

O que exatamente está acontecendo aqui? Por que a segunda versão que eu executo, após SELECTremover tuplas mortas das páginas visitadas, é semelhante a VACUUMisso?

Estou executando o Postgres 11.3 no macOS 10.14.5.

rafbm
fonte
2
Qual cliente você usa para executar seus comandos? A confirmação automática está ativada?
mustaccio 5/06/19
2
Vou excluir a pergunta "A tabela VACUUM é basicamente apenas SELECT * FROM tabela sob o capô?" (não é) Eu acho que é um bom acompanhamento, a resposta aqui é simplesmente que o SELECT pode remover linhas mortas e compartilha isso em comum com o VACUUM. A diferença entre eles será uma conversa muito exaustiva sobre a substituição do XID e várias outras coisas. Essa pergunta é basicamente "Que outras coisas o vácuo faz além de remover as linhas mortas". (O que seria tipo de vaga)
Evan Carroll
@mustaccio Eu fiz esses testes com um script Ruby usando o ActiveRecord, que usa a gema PG sob o capô. Acredito que a confirmação automática está ativada por padrão, pois você não precisa emitir nenhum COMMIT, a menos que BEGIN seja usado explicitamente.
Rafbm 06/06/19

Respostas:

5

Deste post no / r / PostgreSQL para uma resposta de Laurenz Albe , parece que as atualizações de Heap Only Tuples (HOT) podem ser responsáveis. Na descrição das atualizações HOT emsrc/backend/access/heap/README.HOT

Efetivamente, a recuperação de espaço ocorre durante a recuperação da tupla quando a página está quase cheia (<10% livre) e um bloqueio de limpeza do buffer pode ser adquirido. Isto significa que UPDATE, DELETEe SELECTespaço de recuperação pode desencadear, mas muitas vezes não durante INSERT ... VALUESporque não recuperar uma linha.

A citação não está na resposta original, mas o resto é uma citação,

Para apoiar ou refutar essa teoria, execute a seguinte consulta:

SELECT n_tup_upd, n_tup_hot_upd
FROM pg_stat_user_tables
WHERE schemaname = 'public' AND relname = 'TABLE_NAME';

Se n_tup_hot_updfor maior que zero, temos um caso.

Evan Carroll
fonte
Agora estamos a falar. +1
mustaccio 6/06/19
HOT parece ser uma boa explicação. Se eu CREATE INDEX idx_numbers ON numbers USING btree (num), a saída VACUUM muda para INFO: "numbers": removed 5000 row versions in 45 pages. Observe, no entanto, que no cenário sem índice, n_tup_hot_updé sempre 0, tanto entre UPDATE e SELECT quanto entre SELECT e VACUUM. Também assegurei a execução SELECT pg_sleep(10)entre cada instrução para que as estatísticas estivessem atualizadas (eu vejo seq_scan: 2, uma para o UPDATE e outra para o SELECT).
Rafbm 06/06/19
A seleção gera WAL neste caso? Fiquei com a impressão de que os selecionados não geram WAL. Se sim, isso significaria que a remoção de linhas mortas é propagada para quaisquer escravos. Se não, isso significa que ainda é necessário aspirar o escravo. Significaria também que senhores e escravos não são nem um pouco idênticos. Hmm, talvez eu precise fazer alguma pesquisa e postar uma pergunta e / ou resposta ou duas.
Colin 'Hart Hart
1

No caso especial de uma tabela não indexada, sim, SELECT pode fazer o mesmo trabalho que VACUUM (no que diz respeito à remoção de linhas mortas).

jjanes
fonte
3
Você poderia adicionar uma explicação?
Laurenz Albe