Podemos criar um índice parcial para um campo no Postgres.
Eu estou olhando para usar isso para parar as linhas que estão archived
em um índice em um created_at field
:
Primeiro criamos o índice:
test=# CREATE INDEX idx_my_table_created_at ON my_table(created_at) WHERE NOT(archived);
Inserimos duas linhas, uma que entra
idx_my_table_created_at
e outra que não:id | created_at | archived ----+----------------------------+---------- 2 | 2012-10-12 17:39:17.28511 | t 1 | 2012-10-12 17:38:55.531278 | f
Agora temos
UPDATE
uma linha que está atualmente no índice, de forma que não deveria estar no índice:test=# UPDATE my_table SET archived = true WHERE id = 1;
Minha pergunta: id = 1
Ainda está em idx_my_table_created_at
?
Esta questão segue uma resposta a uma pergunta anterior que fiz sobre como lidar com linhas que não serão consultadas quando forem antigas, portanto, archived
.
(Observação: não sou um profundo especialista em Pg guts. Este é apenas o meu entendimento. Você realmente deve ler as seções mvcc e internas do manual) .
Sim, inicialmente a linha com
id = 1
ainda está no índice, apesar daWHERE
cláusula do índice excluí-la porque foi atualizada comarchived = true
. Em algum ponto da trilha, a entrada do índice será limpaVACUUM
ou autovácua, liberando o espaço.A razão para isso é o design MVCC do PostgreSQL. Outras transações simultâneas ainda podem ver a versão antiga da linha com
id = 1, archived = false
-READ COMMITTED
transações com uma instrução de execução longa ouSERIALIZABLE
transações que não veem as alterações confirmadas após o início. Se a entrada do índice fosse removida quando a linha fosse atualizada, essas transações não encontrariam a linha nas varreduras de índice e produziriam o resultado errado.Tecnicamente, o que realmente está acontecendo é que a linha antiga ainda existe, ela apenas tinha um
xmax
conjunto para que as transações mais recentes a ignorem quando a virem. Após a atualização, o índice aponta para essa linha, como antes. Uma nova linha comarchived = true
foi inserida com umxmin
acima da linha antigaxmax
, portanto, qualquer transação visualiza a versão antiga ou a nova, nunca ambas. Essa nova linha não é adicionada ao índice.Eventualmente, não haverá nenhuma transação aberta que ainda possa ver a linha antiga, então
VACUUM
ela aparecerá e removerá a linha antiga e sua entrada de índice, liberando o espaço para reutilização.Observe que o próprio índice não possui informações de visibilidade de linha. Você pode - e geralmente tem - muitas versões de uma linha, cada uma com entradas de índice. Quando uma transação procura entradas de índice correspondentes, ela lê todas as versões (a menos que possa dizer no mapa de visibilidade que não precisa) e ignora todas, exceto aquela que possui um
xmin
exmax
que a torna visível para essa transação.Este é um dos muitos bons motivos para garantir que o autovaccum seja executado com frequência. Ele reduz o número de entradas de índice mortas e linhas mortas que você tem desperdiçando espaço e E/S.