2013/12/5 Matheus Saraiva <[email protected]>

> Tendo os campos A, B, C
>
> digamos que eu crie um índice composto (A, B) e também crie um índice
> simples ( C ). Sei que se for feita uma consulta apenas com o campo A o
> indice (A, B) será usado. Mas se eu fizer uma consulta com filtro em (C,
> A), os dois índices separados serão usados?
>

Eles poderão ser usados sim. Mas, como sempre, depende. Nesse caso irá
depender de quão seletivo seu filtro é para cada campo.

Vamos pensar num exemplo simples. Numa tabela com 10 milhões de registros,
supondo que você faça:

    SELECT ... FROM foo WHERE a = 10 AND c = 15;

O PostgreSQL vai poder usar qualquer um dos índices que você criou. Mas
para decidir qual (ou quais) usará, ele tentará "adivinhar" quantos
registros cada filtro retornará, da seguinte forma:

1. Quantas tuplas somente o filtro `a = 10` retorna?
2. Quantas tuplas somente o filtro `c = 15` retorna?
3. Quantas tuplas ambos filtros, `a = 10 AND c = 15` retornam?

Esse "adivinhar" é baseado nas estatísticas do banco de dados (vamos deixar
essa pra outro momento). Vamos supor alguns exemplos baseados nos itens
acima:

1. Existem aproximadamente 1 milhão de registros com `a = 10`.
2. Existem aproximadamente 5 mil registros com `c = 15`.
3. Existem aproximadamente mil registros com ambos.

Nesse caso podemos dizer (um chute) que o PostgreSQL iria preferir usar
somente o índice em (C). Com ele iria encontrar os 5 mil registros onde `c
= 15`, em seguida, buscaria (da tabela mesmo) os (meros) mil registros onde
`a = 10`. Vale mais a pena do que o trabalho extra para navegar nos dois
índices. Agora, se pensarmos diferente:

1. Existem aproximadamente 1 milhão de registros com `a = 10`.
2. Existem aproximadamente 800 mil registros com `c = 15`.
3. Existem aproximadamente 2 mil registros com ambos.

Nesse último caso, se ele pegar qualquer um dos dois índices unicamente,
ainda teria muitas tuplas para pegar da tabela, para no final ficar com
apenas 2 mil registros. Então ele irá preferir navegar pelos dois índices
juntos, e pegar só o que interessa da tabela. Agora, como ele faz isso? Da
seguinte forma:

1. Navega no índice em (A,B) e busca pelos campos onde `a = 10`. Com o
resultado, gera um bitmap marcando as páginas que casam com 1 e que não
casam com 0
2. Navega no índice em (C) e busca pelos campos onde `c = 15` e gera um
bitmap desse resultado também.
3. Realiza uma operação de AND nos dois bitmaps, o que é bem rápido (são só
bitmaps) e gera como resultado um novo bitmap, que mapeia quais são as
páginas da tabela que contém ambos os valores.
4. Por fim, basta navegar nas páginas marcadas com o bitmap resultante do
AND anterior. Nesse caso ele terá que "reverificar" cada tupla de cada
página, mas veja que se a tabela tem 10 milhões e queremos apenas 2 mil
registros, estamos falando de cerca de apenas 0,02% da tabela.

Vale ressaltar que o PostgreSQL usa dados estatísticos para encontrar esses
possíveis valores de retorno. Nesse caso ele não precisa da quantidade
**exata** de registros que cada filtro retorna, mas quanto mais próximo do
real, melhor serão os planos de execução criados. Logo, manter as
estatísticas atualizadas é uma tarefa muito importante.

Atenciosamente,
-- 
Matheus de Oliveira
Analista de Banco de Dados
Dextra Sistemas - MPS.Br nível F!
www.dextra.com.br/postgres
_______________________________________________
pgbr-geral mailing list
[email protected]
https://listas.postgresql.org.br/cgi-bin/mailman/listinfo/pgbr-geral

Responder a