AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 160649
Accepted
Eric
Eric
Asked: 2017-01-11 16:33:43 +0800 CST2017-01-11 16:33:43 +0800 CST 2017-01-11 16:33:43 +0800 CST

Índices compostos: coluna mais seletiva primeiro?

  • 772

Eu tenho lido sobre composite indexese 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 scanninge 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 columnser o primeiro na ordenação se você estiver antecipando Index Skip Scans. Mas não tenho muita certeza se isso está correto.

oracle oracle-10g
  • 7 7 respostas
  • 11586 Views

7 respostas

  • Voted
  1. Best Answer
    atokpas
    2017-01-24T22:00:59+08:002017-01-24T22:00:59+08:00

    De AskTom

    (no 9i, há um novo "index skip scan" - procure por ele para ler sobre isso. Isso torna o índice (a,b) OU (b,a) útil em ambos os casos acima às vezes!)

    Portanto, a ordem das colunas em seu índice depende de COMO SUAS CONSULTAS são escritas. Você deseja poder usar o índice para quantas consultas puder (para reduzir o número total de índices que possui) - isso direcionará a ordem das colunas. Nada mais (a seletividade de a ou b não conta).

    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.

    SQL> create table t as select * from all_objects;
    
    Table created.
    
    SQL> create index t_idx_1 on t(owner,object_type,object_name);
    
    Index created.
    
    SQL> create index t_idx_2 on t(object_name,object_type,owner);
    
    Index created.
    
    SQL> select count(distinct owner), count(distinct object_type), count(distinct object_name ), count(*)  from t;
    
    COUNT(DISTINCTOWNER) COUNT(DISTINCTOBJECT_TYPE) COUNT(DISTINCTOBJECT_NAME)      COUNT(*)
    -------------------- -------------------------- --------------------------      ----------
                     30                         45                       52205      89807
    
    SQL> analyze index t_idx_1 validate structure; 
    
    Index analyzed.
    
    SQL> select btree_space, pct_used, opt_cmpr_count, opt_cmpr_pctsave from index_stats;
    
    BTREE_SPACE   PCT_USED OPT_CMPR_COUNT OPT_CMPR_PCTSAVE
    ----------- ---------- -------------- ----------------
        5085584     90          2           28
    
    SQL> analyze index t_idx_2 validate structure; 
    
    Index analyzed.
    
    SQL> select btree_space, pct_used, opt_cmpr_count, opt_cmpr_pctsave  from index_stats; 
    
    BTREE_SPACE   PCT_USED OPT_CMPR_COUNT OPT_CMPR_PCTSAVE
    ----------- ---------- -------------- ----------------
        5085584     90          1           14
    

    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-

  2. select * from t where col1 = :a and col2 = :b;
  3. select * from t where col1 = :a;

    -então index(col1,col2)teria um desempenho melhor.

    Se suas consultas usam principalmente col2,

  4. select * from t where col1 = :a and col2 = :b;
  5. 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:

  6. Ordem das colunas no índice
  7. É menos eficiente ter colunas iniciais de baixa cardinalidade em um índice (à direita)?
  8. Index Skip Scan – A ordem da coluna do índice é mais importante? (Sinal de aviso)

  • 13
  • Chris Saxon
    2017-02-01T12:08:49+08:002017-02-01T12:08:49+08:00

    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:

    create table t(
      few_vals  varchar2(10),
      many_vals varchar2(10),
      lots_vals varchar2(10)
    );
    
    insert into t 
    with rws as (
      select lpad(mod(rownum, 10), 10, '0'), 
             lpad(mod(rownum, 1000), 10, '0'), 
             lpad(rownum, 10, '0') 
      from dual connect by level <= 10000
    )
      select * from rws;
    
    commit;
    
    select count(distinct few_vals),
           count(distinct many_vals) ,
           count(distinct lots_vals) 
    from   t;
    
    COUNT(DISTINCTFEW_VALS)  COUNT(DISTINCTMANY_VALS)  COUNT(DISTINCTLOTS_VALS)  
    10                       1,000                     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:

    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  few_vals = '0000000001';
    
    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  lots_vals = '0000000001';
    
    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  lots_vals = '0000000001'
    and    few_vals = '0000000001';
    

    O que você indexa?

    Um índice em apenas alguns_vals é apenas marginalmente melhor do que uma varredura completa da tabela:

    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  few_vals = '0000000001';
    
    select * 
    from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    -------------------------------------------------------------------------------------------  
    | Id  | Operation            | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  
    -------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT     |          |      1 |        |      1 |00:00:00.01 |      61 |  
    |   1 |  SORT AGGREGATE      |          |      1 |      1 |      1 |00:00:00.01 |      61 |  
    |   2 |   VIEW               | VW_DAG_0 |      1 |   1000 |   1000 |00:00:00.01 |      61 |  
    |   3 |    HASH GROUP BY     |          |      1 |   1000 |   1000 |00:00:00.01 |      61 |  
    |   4 |     TABLE ACCESS FULL| T        |      1 |   1000 |   1000 |00:00:00.01 |      61 |  
    -------------------------------------------------------------------------------------------
    
    select /*+ index (t (few_vals)) */
           count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  few_vals = '0000000001';
    
    select * 
    from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    -------------------------------------------------------------------------------------------------------------  
    | Id  | Operation                              | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  
    -------------------------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT                       |          |      1 |        |      1 |00:00:00.01 |      58 |  
    |   1 |  SORT AGGREGATE                        |          |      1 |      1 |      1 |00:00:00.01 |      58 |  
    |   2 |   VIEW                                 | VW_DAG_0 |      1 |   1000 |   1000 |00:00:00.01 |      58 |  
    |   3 |    HASH GROUP BY                       |          |      1 |   1000 |   1000 |00:00:00.01 |      58 |  
    |   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| T        |      1 |   1000 |   1000 |00:00:00.01 |      58 |  
    |   5 |      INDEX RANGE SCAN                  | FEW      |      1 |   1000 |   1000 |00:00:00.01 |       5 |  
    -------------------------------------------------------------------------------------------------------------
    

    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:

    ( few_vals, lots_vals )
    

    OU

    ( lots_vals, few_vals )
    

    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:

    create index few_lots on t(few_vals, lots_vals);
    
    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  lots_vals = '0000000001';
    
    select * 
    from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    -------------------------------------------------------------------------------------------  
    | Id  | Operation            | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  
    -------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT     |          |      1 |        |      1 |00:00:00.01 |      61 |  
    |   1 |  SORT AGGREGATE      |          |      1 |      1 |      1 |00:00:00.01 |      61 |  
    |   2 |   VIEW               | VW_DAG_0 |      1 |      1 |      1 |00:00:00.01 |      61 |  
    |   3 |    HASH GROUP BY     |          |      1 |      1 |      1 |00:00:00.01 |      61 |  
    |   4 |     TABLE ACCESS FULL| T        |      1 |      1 |      1 |00:00:00.01 |      61 |  
    -------------------------------------------------------------------------------------------  
    
    select /*+ index_ss (t few_lots) */count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  lots_vals = '0000000001';
    
    select * 
    from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    ----------------------------------------------------------------------------------------------------------------------  
    | Id  | Operation                              | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  
    ----------------------------------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT                       |          |      1 |        |      1 |00:00:00.01 |      13 |     11 |  
    |   1 |  SORT AGGREGATE                        |          |      1 |      1 |      1 |00:00:00.01 |      13 |     11 |  
    |   2 |   VIEW                                 | VW_DAG_0 |      1 |      1 |      1 |00:00:00.01 |      13 |     11 |  
    |   3 |    HASH GROUP BY                       |          |      1 |      1 |      1 |00:00:00.01 |      13 |     11 |  
    |   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| T        |      1 |      1 |      1 |00:00:00.01 |      13 |     11 |  
    |   5 |      INDEX SKIP SCAN                   | FEW_LOTS |      1 |     40 |      1 |00:00:00.01 |      12 |     11 |  
    ----------------------------------------------------------------------------------------------------------------------
    

    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)

    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  lots_vals = '0000000001'
    and    few_vals = '0000000001';
    
    select * 
    from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    -------------------------------------------------------------------------------------------------------------  
    | Id  | Operation                              | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  
    -------------------------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT                       |          |      1 |        |      1 |00:00:00.01 |       3 |  
    |   1 |  SORT AGGREGATE                        |          |      1 |      1 |      1 |00:00:00.01 |       3 |  
    |   2 |   VIEW                                 | VW_DAG_0 |      1 |      1 |      1 |00:00:00.01 |       3 |  
    |   3 |    HASH GROUP BY                       |          |      1 |      1 |      1 |00:00:00.01 |       3 |  
    |   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| T        |      1 |      1 |      1 |00:00:00.01 |       3 |  
    |   5 |      INDEX RANGE SCAN                  | FEW_LOTS |      1 |      1 |      1 |00:00:00.01 |       2 |  
    -------------------------------------------------------------------------------------------------------------  
    
    create index lots on t(lots_vals);
    
    select /*+ index (t (lots_vals)) */count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  lots_vals = '0000000001'
    and    few_vals = '0000000001';
    
    select * 
    from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    ----------------------------------------------------------------------------------------------------------------------  
    | Id  | Operation                              | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  
    ----------------------------------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT                       |          |      1 |        |      1 |00:00:00.01 |       3 |      1 |  
    |   1 |  SORT AGGREGATE                        |          |      1 |      1 |      1 |00:00:00.01 |       3 |      1 |  
    |   2 |   VIEW                                 | VW_DAG_0 |      1 |      1 |      1 |00:00:00.01 |       3 |      1 |  
    |   3 |    HASH GROUP BY                       |          |      1 |      1 |      1 |00:00:00.01 |       3 |      1 |  
    |   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| T        |      1 |      1 |      1 |00:00:00.01 |       3 |      1 |  
    |   5 |      INDEX RANGE SCAN                  | LOTS     |      1 |      1 |      1 |00:00:00.01 |       2 |      1 |  
    ----------------------------------------------------------------------------------------------------------------------  
    

    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:

    create index lots on t(lots_vals);
    create index lots_few on t(lots_vals, few_vals);
    create index few_lots on t(few_vals, lots_vals);
    
    select index_name, leaf_blocks, distinct_keys, clustering_factor
    from   user_indexes
    where  table_name = 'T';
    
    INDEX_NAME  LEAF_BLOCKS  DISTINCT_KEYS  CLUSTERING_FACTOR  
    FEW_LOTS    47           10,000         530                
    LOTS_FEW    47           10,000         53                 
    LOTS        31           10,000         53                 
    FEW         31           10             530    
    

    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

    create index few_many on t(many_vals, few_vals);
    create index many_few on t(few_vals, many_vals);
    
    select index_name, leaf_blocks, distinct_keys, clustering_factor 
    from   user_indexes
    where  index_name in ('FEW_MANY', 'MANY_FEW');
    
    INDEX_NAME  LEAF_BLOCKS  DISTINCT_KEYS  CLUSTERING_FACTOR  
    FEW_MANY    47           1,000          10,000             
    MANY_FEW    47           1,000          10,000   
    
    alter index few_many rebuild compress 1;
    alter index many_few rebuild compress 1;
    
    select index_name, leaf_blocks, distinct_keys, clustering_factor 
    from   user_indexes
    where  index_name in ('FEW_MANY', 'MANY_FEW');
    
    INDEX_NAME  LEAF_BLOCKS  DISTINCT_KEYS  CLUSTERING_FACTOR  
    MANY_FEW    31           1,000          10,000             
    FEW_MANY    34           1,000          10,000      
    

    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!

    alter index few_many rebuild compress 2;
    alter index many_few rebuild compress 2;
    
    select index_name, leaf_blocks, distinct_keys, clustering_factor 
    from   user_indexes
    where  index_name in ('FEW_MANY', 'MANY_FEW');
    
    INDEX_NAME  LEAF_BLOCKS  DISTINCT_KEYS  CLUSTERING_FACTOR  
    FEW_MANY    20           1,000          10,000             
    MANY_FEW    20           1,000          10,000   
    

    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:

    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  few_vals < '0000000002'
    and    many_vals = '0000000001';
    
    select * 
    from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    -------------------------------------------------------------------------------------------------------------  
    | Id  | Operation                              | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  
    -------------------------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT                       |          |      1 |        |      1 |00:00:00.01 |      12 |  
    |   1 |  SORT AGGREGATE                        |          |      1 |      1 |      1 |00:00:00.01 |      12 |  
    |   2 |   VIEW                                 | VW_DAG_0 |      1 |     10 |     10 |00:00:00.01 |      12 |  
    |   3 |    HASH GROUP BY                       |          |      1 |     10 |     10 |00:00:00.01 |      12 |  
    |   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| T        |      1 |     10 |     10 |00:00:00.01 |      12 |  
    |   5 |      INDEX RANGE SCAN                  | FEW_MANY |      1 |     10 |     10 |00:00:00.01 |       2 |  
    -------------------------------------------------------------------------------------------------------------  
    
    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  few_vals = '0000000001'
    and    many_vals < '0000000002';
    
    select * 
    from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    ----------------------------------------------------------------------------------------------------------------------  
    | Id  | Operation                              | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  
    ----------------------------------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT                       |          |      1 |        |      1 |00:00:00.01 |      12 |      1 |  
    |   1 |  SORT AGGREGATE                        |          |      1 |      1 |      1 |00:00:00.01 |      12 |      1 |  
    |   2 |   VIEW                                 | VW_DAG_0 |      1 |      2 |     10 |00:00:00.01 |      12 |      1 |  
    |   3 |    HASH GROUP BY                       |          |      1 |      2 |     10 |00:00:00.01 |      12 |      1 |  
    |   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| T        |      1 |      2 |     10 |00:00:00.01 |      12 |      1 |  
    |   5 |      INDEX RANGE SCAN                  | MANY_FEW |      1 |      1 |     10 |00:00:00.01 |       2 |      1 |  
    ----------------------------------------------------------------------------------------------------------------------  
    

    Notice they're using the opposite index.

    TL;DR

    • Columns with equality conditions should go first in index.
    • If you have multiple columns with equalities in your query, placing the one with the fewest different values first will give the best compression advantage
    • While index skip scans are possible, you need to be confident this will remain a viable option for the foreseeable future
    • Composite indexes including near-unique columns give minimal benefits. Be sure you really need to save the 1-2 IOs

    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

    • 4
  • Erik Hart
    2017-01-15T09:19:23+08:002017-01-15T09:19:23+08:00

    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.

    • 3
  • Anup Shah
    2017-01-31T15:06:58+08:002017-01-31T15:06:58+08:00

    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:

    1. que tipo de operador de consulta está sendo usado: Se as consultas tiverem operadores como
      ">, >=, <, <="
    2. Quantas linhas reais são esperadas como resultado da consulta: o resultado da consulta será a maioria das linhas da tabela.
    3. Se alguma função está sendo usada na coluna da tabela durante a cláusula Where: Se a consulta tiver qualquer função UPPER, LOWER, TRIM, SUBSTRING usada na coluna que está sendo usada na condição WHERE.

    ainda para manter a conversa relevante, minha resposta abaixo se aplica à seguinte situação:

    1. "90% do tipo de consultas em uma determinada tabela tem Cláusula WHERE com operador ="
    2. "no máximo a consulta está retornando 10% do total de linhas na tabela como resultado"
    3. "nenhum tipo de função está sendo usado na coluna da tabela na cláusula WHERE"
    4. "na maioria das vezes, as colunas na cláusula WHERE usadas são principalmente do tipo número,
      string"

    Na minha experiência, é sobre ambos que o DBA deve estar atento.

    Vamos imaginar que a única regra está sendo aplicada:

    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.

    • 1
  • Joe Yahchouchi
    2018-06-21T02:23:27+08:002018-06-21T02:23:27+08:00

    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.

    • 1
  • RMPJ
    2017-01-14T20:47:36+08:002017-01-14T20:47:36+08:00

    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.

    • -2
  • Andjelko Miovcic
    2018-01-30T11:24:51+08:002018-01-30T11:24:51+08:00

    From Column order in Index on Ask Tom:

    So, the order of columns in your index depends on HOW YOUR QUERIES are written. You want to be able to use the index for as many queries as you can (so as to cut down on the over all number of indexes you have) -- that will drive the order of the columns. Nothing else (selectivity of a or b does not count at all).

    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")

    • -2
  • relate perguntas

    • Backups de banco de dados no Oracle - Exportar o banco de dados ou usar outras ferramentas?

    • ORDER BY usando prioridades personalizadas para colunas de texto

    • Interface sqlplus confortável? [fechado]

    • Como encontrar as instruções SQL mais recentes no banco de dados?

    • Como posso consultar nomes usando expressões regulares?

    Sidebar

    Stats

    • Perguntas 205573
    • respostas 270741
    • best respostas 135370
    • utilizador 68524
    • Highest score
    • respostas
    • Marko Smith

      conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

      • 12 respostas
    • Marko Smith

      Como fazer a saída do sqlplus aparecer em uma linha?

      • 3 respostas
    • Marko Smith

      Selecione qual tem data máxima ou data mais recente

      • 3 respostas
    • Marko Smith

      Como faço para listar todos os esquemas no PostgreSQL?

      • 4 respostas
    • Marko Smith

      Listar todas as colunas de uma tabela especificada

      • 5 respostas
    • Marko Smith

      Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

      • 4 respostas
    • Marko Smith

      Como você mysqldump tabela (s) específica (s)?

      • 4 respostas
    • Marko Smith

      Listar os privilégios do banco de dados usando o psql

      • 10 respostas
    • Marko Smith

      Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

      • 4 respostas
    • Marko Smith

      Como faço para listar todos os bancos de dados e tabelas usando o psql?

      • 7 respostas
    • Martin Hope
      Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
    • Martin Hope
      Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
    • Martin Hope
      Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
    • Martin Hope
      Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
    • Martin Hope
      haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
    • Martin Hope
      qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
    • Martin Hope
      markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
    • Martin Hope
      Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
    • Martin Hope
      Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
    • Martin Hope
      Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

    Hot tag

    sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

    Explore

    • Início
    • Perguntas
      • Recentes
      • Highest score
    • tag
    • help

    Footer

    AskOverflow.Dev

    About Us

    • About Us
    • Contact Us

    Legal Stuff

    • Privacy Policy

    Language

    • Pt
    • Server
    • Unix

    © 2023 AskOverflow.DEV All Rights Reserve