Um índice composto também é bom para consultas no primeiro campo?

86

Digamos que eu tenho uma tabela com campos Ae B. Eu faço consultas regulares no A+ B, então criei um índice composto no (A,B). As consultas somente Atambém seriam totalmente otimizadas pelo índice composto?

Além disso, criei um índice A, mas o Postgres ainda usa o índice composto apenas para consultas A. Se a resposta anterior for positiva, acho que isso realmente não importa, mas por que ela seleciona o índice composto por padrão, se o Aíndice único está disponível?

Luciano
fonte
Eu tentei montar um pequeno teste para isso. No meu caso, no entanto, o índice de duas colunas foi usado apenas quando eu soltei o de coluna única, não relacionado ao qual foi criado primeiro. É interessante que, se eu criei o índice de duas colunas primeiro, o plano inicial usaria uma verificação de heap de bitmap. Se eu criei o índice de uma coluna, execute a consulta (varredura de índice usada) e larguei o índice recém-criado, o plano que envolve o índice de duas colunas mudou para a varredura de índice. Veja as etapas no SQLFiddle
dezso
@dezso Interessante. Onde estão os custos de cada consulta?
Luciano
Custo da verificação do índice de bitmap: 107,98, 43 ms de tempo de execução. Varredura de índice de uma coluna: custo 8,69, duas colunas: 43,69. Os tempos de execução não diferem significativamente (a flutuação é maior que a diferença entre os dois).
Dez23
@Luciano Você pode mostrar o explain analyzetexto e a consulta?
Craig Ringer

Respostas:

88

Certamente é. Discutimos isso em detalhes na questão relacionada:

O espaço é alocado em múltiplos de MAXALIGN, normalmente 8 bytes em um sistema operacional de 64 bits ou (muito menos comum) 4 bytes em um sistema operacional de 32 bits. Se você não tiver certeza, verifique pg_controldata. Também depende dos tipos de dados das colunas indexadas (algumas requerem preenchimento de alinhamento) e do conteúdo real.

Um índice em, digamos, duas integercolunas (4 bytes cada) normalmente acaba exatamente do tamanho de um índice em apenas uma, onde outros 4 bytes são perdidos no preenchimento do alinhamento.

Nesse caso, não há realmente nenhuma desvantagem para o planejador de consultas usar um índice (a,b)- comparado a um índice apenas (a). E geralmente é preferível que várias consultas usem o mesmo índice. A chance de ele (ou parte dele) residir no cache (rápido) aumenta quando compartilhada.

Se você já mantém um índice ativado (a,b), não faz sentido criar outro índice apenas (a)- a menos que seja substancialmente menor. O mesmo não vale para (b,a)vs. (a). Siga o link na primeira linha para saber mais sobre isso.

Vindo da direção oposta, quando você precisar de um índice adicional como esse (a,b), considere soltar um índice existente apenas (a)- se possível. Geralmente não é possível, pois esse é o índice de uma PK ou UNIQUErestrição. Desde o Postgres 11, você pode simplesmente anexar bà definição de restrição com a INCLUDEcláusula. Detalhes no manual.

Ou crie o novo índice (b,a)para cobrir consultas apenas badicionalmente. Somente para condições de igualdade, a ordem das expressões de índice nos índices btree não importa. Porém, quando envolve condições de alcance. Vejo:

Existem possíveis desvantagens em incluir colunas adicionais em um índice, mesmo que isso use apenas o espaço perdido para o preenchimento do alinhamento:

  • Sempre que a coluna adicional é atualizada, o índice agora também precisa de uma atualização, o que pode aumentar o custo das operações de gravação e criar mais inchaço no índice.
  • As atualizações HOT (Heap Only Tuple) na tabela não são possíveis enquanto estiver envolvida qualquer coluna de índice.

Mais sobre atualizações HOT:

Como medir tamanhos de objeto:

Erwin Brandstetter
fonte
1
Você poderia estender isso para dizer que, se eu tiver um índice na coluna A e surgir a necessidade de adicionar um índice composto (A, B), o índice A deve ser descartado? Se a reutilização de um índice melhorar a eficiência do cache e (A, B) otimizar totalmente A, parece que um índice adicional em A desperdiçaria espaço e potencialmente
deixaria as
1
@ jvans: Geralmente verdade - com exceções e alternativas notáveis. Eu adicionei um parágrafo para resolver isso.
Erwin Brandstetter 02/04
2

De acordo com sua pergunta, você tem uma tabela com os campos A e B. Se sua consulta for:

SELECT * FROM [YOUR TBL]
WHERE A='XXXX'

O Optimizer escolheu o índice Composto para evitar Extrair acesso aleatório!

BongSey
fonte
-4

É o caso se você apenas usar apenas o primeiro no predicado.

Ele fará a varredura se você usar as primeiras colunas da chave composta e a coluna não chave da chave composta.

Para enganá-lo, você pode simplesmente manipular predicados como este e depois a coluna sem chave:

[A, B] é o seu índice, [C] - outra coluna

Para utilizar o índice, você escreve como:

SELECT
    A,B,C,D,E
FROM 
    test
WHERE
   A=1
AND
   B=B
AND 
   C=3

... por que ele seleciona o índice composto por padrão, se o único índice A está disponível?

Ele usará o índice apenas no caso se houver um ou dois predicados [A] ou [A], [B]. Não o usará na ordem [B], [A] ou [A], [C]. Para poder utilizar o índice com a coluna adicional [C], você precisa aplicar o índice ordenando predicados como [A], [B] e [C].

Farfarak
fonte
2
O que exatamente você consegue B=B? Eu acho que você conseguir nada, então eu estou votando para baixo na ausência de qualquer evidência isto não é simplesmente ignorada pelo otimizador
Jack Douglas
2
B=Bé efetivamente o mesmo que B IS NOT NULL, o que parece desnecessário. Certamente não é necessário usar um índice (a,b).
Erwin Brandstetter