Eu tenho lido sobre composite indexes
e estou um pouco confuso sobre o pedido. Esta documentação (pouco menos da metade) diz
Em geral, você deve colocar a coluna que deve ser usada com mais frequência primeiro no índice.
No entanto, pouco depois diz
crie um índice composto colocando a coluna mais seletiva primeiro; ou seja, a coluna com mais valores.
A Oracle também diz isso aqui em outras palavras
Se todas as chaves forem usadas nas cláusulas WHERE com a mesma frequência, a ordem dessas chaves da mais seletiva para a menos seletiva na instrução CREATE INDEX melhora melhor o desempenho da consulta.
No entanto, encontrei uma resposta SO que diz de forma diferente. Diz
Organize as colunas com a coluna menos seletiva primeiro e a coluna mais seletiva por último. No caso de empate leve com a coluna que tem mais chances de ser usada sozinha.
A primeira documentação que mencionei diz que você deve primeiro usar o mais usado, enquanto a resposta do SO diz que deve ser apenas para desempate. Então eles também diferem na ordem.
Esta documentação também fala skip scanning
e diz
A varredura de salto é vantajosa se houver poucos valores distintos na coluna inicial do índice composto e muitos valores distintos na chave não inicial do índice.
Outro artigo diz
A coluna de prefixo deve ser a mais discriminativa e a mais amplamente usada em consultas
o que eu acredito que mais discriminador significaria mais distinto.
Toda essa pesquisa ainda me leva à mesma pergunta; A coluna mais seletiva deve ser a primeira ou a última? A primeira coluna deve ser a mais usada e apenas a mais seletiva em um tie-break?
Esses artigos parecem se contradizer, mas oferecem alguns exemplos. Pelo que reuni, parece ser mais eficiente least selective column
ser o primeiro na ordenação se você estiver antecipando Index Skip Scans
. Mas não tenho muita certeza se isso está correto.
De AskTom
Um dos argumentos para organizar as colunas no índice composto na ordem do menos discriminante (valores menos distintos) ao mais discriminante (valores mais distintos) é para compactação de chave de índice.
De acordo com as estatísticas do índice, o primeiro índice é mais compressível.
Outra é como o índice é usado em suas consultas. Se suas consultas usam principalmente
col1
,Por exemplo, se você tiver dúvidas como-
select * from t where col1 = :a and col2 = :b;
select * from t where col1 = :a;
-então
index(col1,col2)
teria um desempenho melhor.Se suas consultas usam principalmente
col2
,select * from t where col1 = :a and col2 = :b;
select * from t where col2 = :b;
-então
index(col2,col1)
teria um desempenho melhor. Se todas as suas consultas sempre especificarem ambas as colunas, não importa qual coluna vem primeiro no índice composto.Concluindo, as principais considerações na ordem das colunas do índice composto são a compactação da chave do índice e como você usará esse índice em suas consultas.
Referências:
Ao escolher a ordem das colunas do índice, a preocupação primordial é:
Existem predicados (de igualdade) contra esta coluna em minhas consultas?
Se uma coluna nunca aparecer em uma cláusula where, não vale a pena indexar(1)
OK, então você tem uma tabela e consultas em cada coluna. Às vezes mais de um.
Como você decide o que indexar?
Vejamos um exemplo. Aqui está uma tabela com três colunas. Um contém 10 valores, outro 1.000, os últimos 10.000:
Estes são números deixados preenchidos com zeros. Isso ajudará a entender a compactação mais tarde.
Então você tem três consultas comuns:
O que você indexa?
Um índice em apenas alguns_vals é apenas marginalmente melhor do que uma varredura completa da tabela:
Portanto, é improvável que valha a pena indexar por conta própria. Consultas em Lots_vals retornam algumas linhas (apenas 1 neste caso). Portanto, definitivamente vale a pena indexar.
Mas e as consultas em ambas as colunas?
Você deve indexar:
OU
Pergunta capciosa!
A resposta é nenhum dos dois.
Claro que few_vals é uma string longa. Então você pode obter uma boa compressão dele. E você (pode) obter uma varredura de salto de índice para as consultas usando (few_vals, Lots_vals) que possuem apenas predicados em Lots_vals. Mas não estou aqui, embora tenha um desempenho notavelmente melhor do que uma varredura completa:
Você gosta de jogos de azar? (2)
Portanto, você ainda precisa de um índice com Lots_vals como a coluna inicial. E, pelo menos neste caso, o índice composto (poucos, muitos) faz a mesma quantidade de trabalho que apenas (muitos)
Haverá casos em que o índice composto economiza 1-2 IOs. Mas vale a pena ter dois índices para essa economia?
E há outro problema com o índice composto. Compare o fator de agrupamento para os três índices, incluindo LOTS_VALS:
Notice that the clustering factor for few_lots is 10x higher than for lots and lots_few! And this is in a demo table with perfect clustering to begin with. In real world databases the effect is likely to be worse.
So what's so bad about that?
The clustering factor is one of the key drivers determining how "attractive" an index is. The higher it is, the less likely the optimizer is to choose it. Particularly if lots_vals aren't actually unique, but still normally have few rows per value. If you're unlucky this could be enough to make the optimizer think a full scan is cheaper...
OK, so composite indexes with few_vals and lots_vals only have edge case benefits.
What about queries filtering few_vals and many_vals?
Single columns indexes only give small benefits. But combined they return few values. So a composite index is a good idea. But which way round?
If you place few first, compressing the leading column will make that smaller
With fewer different values in the leading column compresses better. So there's marginally less work to read this index. But only slightly. And both are already a good chunk smaller than the original (25% size decrease).
And you can go further and compress the whole index!
Now both indexes are back to the same size. Note this takes advantage of the fact there's a relationship between few and many. Again it's unlikely you'll see this kind of benefit in the real world.
So far we've only talked about equality checks. Often with composite indexes you'll have an inequality against one of the columns. e.g. queries such as "get the orders/shipments/invoices for a customer in the past N days".
If you have these kinds of queries, you want the equality against the first column of the index:
Notice they're using the opposite index.
TL;DR
1: In some cases it may be worth including a column in an index if this means all the columns in your query are in the index. This enables an index only scan, so you don't need to access the table.
2: If you're licensed for Diagnostics and Tuning, you could force the plan to a skip scan with SQL Plan Management
ADDEDNDA
PS - the docs you've quoted there are from 9i. That's reeeeeeally old. I'd stick with something more recent
O mais seletivo primeiro é útil apenas quando esta coluna está na cláusula WHERE real.
Quando o SELECT é por um grupo maior (menos seletivo) e possivelmente por outros valores não indexados, um índice com colunas menos seletivas ainda pode ser útil (se houver um motivo para não criar outro).
Se houver uma tabela ADDRESS, com
RUA DA CIDADE DO PAÍS, outra coisa...
A indexação de RUA, CIDADE, PAÍS produzirá as consultas mais rápidas com um nome de rua. Mas, consultando todas as ruas de uma cidade, o índice será inútil e a consulta provavelmente fará uma varredura completa da tabela.
A indexação de PAÍS, CIDADE, RUA pode ser um pouco mais lenta para ruas individuais, mas o índice pode ser usado para outras consultas, selecionando apenas por país e/ou cidade.
Há mais elementos de consulta que contribuem para a decisão final sobre com o que um índice composto deve começar e/ou conter além da seletividade da coluna.
por exemplo:
">, >=, <, <="
ainda para manter a conversa relevante, minha resposta abaixo se aplica à seguinte situação:
string"
Na minha experiência, é sobre ambos que o DBA deve estar atento.
1) Se eu criar um índice com a coluna mais seletiva sendo a primeira, mas essa coluna não for realmente usada pela maioria das consultas nessa tabela, não será útil para o mecanismo de banco de dados.
2) Se eu criar um índice com a coluna mais usada em uma consulta sendo a primeira no índice, mas a coluna tiver baixa seletividade, o desempenho da minha consulta também não será bom.
Vou listar as colunas que são mais usadas em 90% das consultas à tabela. Em seguida, coloque-os apenas na ordem de maior cardinalidade para menor cardinalidade.
Usamos índices para melhorar o desempenho da consulta de leitura e esse fluxo de trabalho (tipos de consulta de leitura) deve orientar apenas a criação do índice. Na verdade, à medida que os dados crescem (bilhões de linhas), o índice compactado pode economizar armazenamento, mas com certeza prejudica o desempenho da consulta de leitura.
In theory the most selective column yields the fastest search. But at work I just stumbled on a situation where we have a composite index of 3 parts with the most selective part first. (date, author, publishing company lets say, in that order, table monitors thumbs up on posts) and I have a query that uses all 3 parts. Mysql defaults to using the author onlny index skipping the composite index containing company and date despite them being present in my query. I used force index to use the composite and the query actually ran slower. Why did that happen? I shall tell you:
I was selecting a range on the date, so despite the date being highly selective, the fact that we are using it for range scans(even though the range is relatively short, 6 months out of 6 years of data) made the composite harmful for mysql. To use the composite in that particular case, mysql has to grab all articles written since new years then dive into who the author is, and given that the author has not written that many articles compared to other authors, mysql preferred to just find that author.
In another case the query ran much much faster on the composite, the case was when an author was hugely popular and owned most of the records, sorting by date made sense. But mysql did not auto detect that case, I had to force index... So you know, it varies. Range scans could render your selective column useless. The distribution of the data could make cases where columns are more selective for different records...
What I would do differently is shift the date (which again, in theory is the most selective) to the right, since I know I will be performing a range scan on it now and that makes a difference.
Casos diferentes para situações diferentes. Conheça seu objetivo; em seguida, crie seus índices e execute planos de explicação para cada um e você terá sua melhor resposta para sua situação.
From Column order in Index on Ask Tom:
Agree, that we have to order columns based on where clause, but the statement "(selectivity of a or b does not count at all)" is not correct.)". The most selective columns should be leading if it is satisfied first role ("where clause")