Se um índice tiver mais de um atributo, há ganho de velocidade em uma select
instrução cuja where
cláusula usa um dos atributos do índice?
Por exemplo, pegue uma tabela T
com um índice de atributos a
e b
. O índice é útil para a consulta:
select * from T where a='foo'
Pergunto porque o livro que estou lendo tem a seguinte frase que não consigo entender:
Se a chave para o índice multiatributo for realmente a concatenação dos atributos em alguma ordem, podemos até usar esse índice para encontrar todas as tuplas com um determinado valor no primeiro dos atributos.
Há duas perguntas aí:
Um índice pode
(a,b)
ser usado para esta consulta?A resposta para isso geralmente é sim. Talvez nem todos os bancos de dados tenham essa capacidade, mas a maioria dos principais tem o AFAIK. Substitua a seleção por
select a,b from ...
e o mecanismo não só pode usar o índice, mas também não acessar a tabela real para responder à consulta.O otimizador escolherá usar o índice?
Isso vai depender do sistema de banco de dados e quanta informação o otimizador tem sobre os dados. Se puder determinar que a primeira coluna é "seletiva o suficiente", provavelmente a usará. Se não, provavelmente não.
Aqui está uma ilustração no Oracle XE 11g.
A
all_objects
visão contém informações sobre todos os objetos (tabelas, visões, procedimentos, etc.) presentes no banco de dados. Osobject_name
campos não são únicos, mas não há muitas duplicatas (pelo menos neste banco de dados), de modo que o próprio campo inicial é muito seletivo.O custo de fazer uma varredura de intervalo no índice e, em seguida, procurar a linha estimada por rowid será muito menor do que fazer uma varredura completa da tabela, portanto, o otimizador segue esse caminho.
Esta é uma situação e um plano bastante comuns, você provavelmente se deparará muito com isso (ou algo semelhante em outros mecanismos de banco de dados).
Agora, aqui está um cenário diferente em que o otimizador pode usar uma imagem detalhada do conteúdo real das colunas para otimizar as coisas de maneira diferente:
A tabela é intencionalmente completamente distorcida, a primeira coluna tem
'a'
como único valor. Se o otimizador souber disso, ele poderá optar por caminhos diferentes com base no valor real da chave consultada, como visto acima.Se
'a'
for solicitado, usar o índice é uma má jogada - você precisa percorrer todo o índice e toda a tabela para obter todas as linhas, o que é (potencialmente muito) mais caro do que apenas digitalizar a tabela.Se o valor solicitado não for
'a'
, a varredura do índice é muito mais eficiente, pois provavelmente não retornará nenhuma linha.Aqui está algo talvez um pouco mais surpreendente: o índice on
(a,b)
pode realmente ser usado quando awhere
cláusula filtrab
somente on.Isso funciona porque a coluna inicial tem poucos valores distintos, mas a segunda coluna é essencialmente única. Pense nisso como o otimizador particionando o índice pela primeira coluna e fazendo uma pesquisa binária em cada partição. Isso será eficiente se o número de partições for pequeno e os outros critérios forem bastante seletivos. (ou seja, não funciona para a tabela
T
neste exemplo.)Sim, mas depende de qual chave de índice você pesquisa.
Pense nisso como uma daquelas velhas listas telefônicas de "páginas em branco". Em uma lista telefônica, as pessoas são ordenadas nas páginas na ordem Sobrenome, Nome. Isso significa que há dois componentes no índice da lista telefônica.
Se você está procurando por todas as pessoas com o sobrenome "Smith", basta encontrar o primeiro "Smith" (fácil de fazer, pois está em ordem), continue lendo até encontrar alguém que não seja um "Smith" .
Mas se você estiver procurando por todas as pessoas com o nome "William", terá dificuldades. Você terá que escanear cada entrada na lista telefônica, coletando respostas, mesmo que FirstName esteja no "índice" da lista telefônica.
Índices de banco de dados (conceitualmente) funcionam exatamente da mesma maneira.
Experiência PostgreSQL.
Temos tabela com 3 colunas
então temos dois índices
então, se usarmos a declaração (1)
o planejador de consulta deve usar o índice first_idx (o valor 'qualquer' é, por exemplo, 5% de todos os registros). É mais rápido porque o índice é menor, então há menos leitura.
Para consulta (2)
é óbvio que o índice first_second_idx será usado
Mas se removermos first_idx em ambas as consultas, a plaina deve usar first_second_idx.
Se não houver nenhum índice para esta tabela, a varredura completa da tabela será acionada.
Portanto, se você tiver os dois tipos de consultas do aplicativo: