Bileşik dizinler: İlk önce en seçici sütun mu?


17

Hakkında okudum composite indexesve sipariş konusunda biraz kafam karıştı. Bu dokümantasyon (yarıdan biraz daha az) diyor

Genel olarak, en sık kullanılması beklenen sütunu önce dizine koymalısınız.

Ancak, kısa bir süre sonra

önce en seçici sütunu koyarak bileşik bir dizin oluşturun; yani, en fazla değere sahip sütun.

Oracle da burada başka bir deyişle söylüyor

Tüm anahtarlar WHERE yan tümcelerinde eşit sıklıkta kullanılıyorsa, bu anahtarları CREATE INDEX deyiminde en seçici olandan en az seçici olana sıralamak sorgu performansını en iyi şekilde artırır.

Ancak, farklı söyleyen bir SO yanıtı buldum . Diyor ki

Sütunları önce en az seçici sütun ve en sonra en seçici sütun olacak şekilde düzenleyin. Tek başına kullanılması daha muhtemel olan kolon ile bir bağlantı kurşun durumunda.

Referans verdiğim ilk dokümanlar ilk önce en sık kullanılanları kullanmanız gerektiğini söylerken, SO yanıtı sadece kravat kopması için gerektiğini söylüyor. Sonra da siparişte farklılık gösterirler.

Bu dokümantasyon ayrıca hakkında konuşuyor skip scanningve diyor

Bileşik dizinin önde gelen sütununda birkaç farklı değer ve dizinin kurşunsuz anahtarında birçok farklı değer varsa, atlamayı tarama avantajlıdır.

Başka makale diyor

Önek sütunu, sorgularda en ayrımcı ve en yaygın kullanılan sütun olmalıdır

ki en ayrımcılığın en belirgin anlamına geleceğine inanıyorum.

Tüm bu araştırmalar beni hala aynı soruya götürüyor; En seçici sütun ilk mi yoksa son mu olmalıdır? İlk sütun en çok kullanılan ve en çok seçmeli mi olmalı?

Bu makaleler birbiriyle çelişiyor gibi görünüyor, ancak bazı örnekler sunuyorlar. Anlamıştım kadarıyla, onun için daha verimli görünmektedir least selective columnolmak ilk siz tahmin eğer sıralamada Index Skip Scans. Ama bunun doğru olup olmadığından emin değilim.


Yanıtlar:


9

AskTom Gönderen

(9i'de yeni bir "indeks atlama taraması" vardır - bunu okumak için orada arayın. (a, b) indeksini VEYA (b, a) bazen yukarıdaki durumların her ikisinde de yararlı olur!)

Bu nedenle, dizininizdeki sütunların sırası SORULARINIZ NASIL yazıldığına bağlıdır. Dizini olabildiğince çok sorgu için kullanmak istiyorsunuz (sahip olduğunuz tüm dizin sayısını aşmak için) - sütunların sırasını yönlendirecektir. Başka bir şey yok (a veya b'nin seçiciliği hiç sayılmaz).

Bileşik dizindeki sütunları en az ayırt edici (daha az farklı değerler) ile en ayırt edici (daha farklı değerler) arasında sıralamaya yönelik argümanlardan biri dizin anahtarı sıkıştırması içindir.

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

Endeks istatistiklerine göre, ilk endeks daha sıkıştırılabilir.

Bir diğeri, dizinin sorgularınızda nasıl kullanıldığıdır. Sorgularınız çoğunlukla kullanıyorsa col1,

Örneğin,

  • select * from t where col1 = :a and col2 = :b;
  • select * from t where col1 = :a;

    -O index(col1,col2)zaman daha iyi performans gösterirdi.

    Sorgularınız çoğunlukla kullanıyorsa col2,

  • select * from t where col1 = :a and col2 = :b;
  • select * from t where col2 = :b;

    -O index(col2,col1)zaman daha iyi performans gösterirdi. Tüm sorgularınız her zaman her iki sütunu da belirtiyorsa, bileşik dizinde hangi sütunun ilk sırada geldiği önemli değildir.

    Sonuç olarak, bileşik dizinin sütun sıralamasında dikkat edilmesi gereken noktalar dizin anahtarı sıkıştırması ve bu dizini sorgularınızda nasıl kullanacağınızdır.

    Referanslar:

  • Dizindeki sütun sırası
  • Bir Endekste Düşük Kardinaliteye Yönelik Sütunlara Sahip Olmak Daha Az Etkili mi (Doğru)?
  • Dizin Taramayı Atla - Dizin Sütunu Sırası Artık Önemli mi? (Uyarı işareti)


  • 3

    İlk önce en seçici, yalnızca bu sütun gerçek WHERE yan tümcesinde olduğunda yararlıdır.

    SELECT daha büyük bir gruba (daha az seçici) ve daha sonra muhtemelen dizine eklenmemiş diğer değerlere göre olduğunda, daha az seçici sütun içeren bir dizin yine de yararlı olabilir (başka bir tane oluşturmamanın bir nedeni varsa).

    ADDRESS adlı bir tablo varsa,

    COUNTRY CITY STREET, başka bir şey ...

    dizin, STREET, CITY, COUNTRY bir cadde adı ile en hızlı sorguları verecektir. Ancak bir şehrin tüm sokaklarını sorgularken, dizin işe yaramaz ve sorgu büyük olasılıkla tam bir tablo taraması yapar.

    ÜLKE, ŞEHİR, SOKAK, tek tek sokaklar için biraz daha yavaş olabilir, ancak dizin diğer sorgular için kullanılabilir, yalnızca ülke ve / veya şehre göre seçilir.


    3

    Dizin sütunu sırasını seçerken, geçersiz kılma endişesi:

    Sorularımda bu sütuna karşı (eşitlik) tahminleri var mı?

    Bir sütun hiçbir yerde bir cümlede görünmezse, dizine eklemeye değmez (1)

    Tamam, böylece her sütuna karşı bir tablo ve sorgularınız var. Bazen birden fazla.

    Neyin endeksleneceğine nasıl karar verirsiniz?

    Bir örneğe bakalım. İşte üç sütunlu bir tablo. Biri 10, diğeri 1.000, son 10.000 değeri tutar:

    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     

    Bunlar sıfırlarla doldurulmuş sayılardır. Bu, daha sonra sıkıştırma ile ilgili noktayı belirtmeye yardımcı olacaktır.

    Yani üç yaygın sorgunuz var:

    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';

    Neyi endekslersin?

    Yalnızca birkaç_değerdeki bir dizin, tam tablo taramasından yalnızca marjinal olarak daha iyidir:

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

    Bu yüzden kendi başına endekslemeye değecek gibi görünmüyor. Lots_vals üzerindeki sorgular birkaç satır döndürür (bu durumda yalnızca 1). Bu kesinlikle endekslemeye değer.

    Peki her iki sütuna karşı sorgular ne olacak?

    Dizine eklemeniz gerekir:

    ( few_vals, lots_vals )

    VEYA

    ( lots_vals, few_vals )

    Tuzak soru!

    Cevap da değil.

    Tabii few_vals uzun bir dizedir. Böylece iyi bir sıkıştırma elde edebilirsiniz. Ve yalnızca lots_vals için tahminleri olan (az_değer, çok_değer) kullanarak sorgular için bir dizin atlama taraması alabilirsiniz (olabilir). Ancak tam bir taramadan belirgin şekilde daha iyi performans göstermesine rağmen burada değilim:

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

    Kumar oynamayı sever misin? (2)

    Bu nedenle, önde gelen sütun olarak lots_vals içeren bir dizine ihtiyacınız vardır. Ve en azından bu durumda bileşik endeksi (birkaç, lot) sadece (lotlar) ile aynı miktarda iş yapar

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

    Bileşik endeksin size 1-2 IO kazandırdığı durumlar olacaktır. Ancak bu tasarruf için iki endekse sahip olmaya değer mi?

    Bileşik endeks ile ilgili başka bir sorun daha var. LOTS_VALS dahil üç dizin için kümeleme faktörünü karşılaştırın:

    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    

    Few_lots için kümeleme faktörünün lot ve lots_few için olduğundan 10 kat daha yüksek olduğuna dikkat edin ! Ve bu, başlamak için mükemmel kümelenmeye sahip bir demo tablosunda. Gerçek dünya veritabanlarında etkinin daha kötü olması muhtemeldir.

    Peki bunda kötü olan ne?

    Kümeleme faktörü, bir endeksin ne kadar "çekici" olduğunu belirleyen temel faktörlerden biridir. Ne kadar yüksek olursa, optimize edicinin onu seçme olasılığı o kadar düşük olur. Özellikle lots_val değerleri aslında benzersiz değilse de, normalde değer başına birkaç satır varsa. Şanssızsanız, bu, optimize edicinin tam bir taramanın daha ucuz olduğunu düşünmesini sağlamak için yeterli olabilir ...

    Tamam, bu nedenle az_değer ve çok_değer içeren bileşik dizinlerin yalnızca kenar durumu avantajları vardır.

    Few_vals ve many_vals filtreleme sorgularına ne olacak?

    Tek sütun dizinleri yalnızca küçük avantajlar sağlar. Ancak kombine edildiğinde birkaç değer döndürürler. Dolayısıyla bileşik bir endeks iyi bir fikirdir. Ama hangi yönden?

    İlk önce birkaç tane yerleştirirseniz, önde gelen sütunu sıkıştırmak

    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      

    Önde gelen sütundaki daha az farklı değerle daha iyi sıkıştırır. Yani bu endeksi okumak için çok az iş var. Ama sadece biraz. Ve her ikisi de zaten orijinalinden daha iyi bir yığın (% 25 boyut küçültme).

    Ve daha ileri gidip tüm endeksi sıkıştırabilirsiniz!

    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   

    Şimdi her iki dizin de aynı boyutta. Bunun az ve çok arasında bir ilişki olduğu gerçeğinden faydalandığını unutmayın. Yine, gerçek dünyada bu tür bir fayda görmeniz pek olası değildir.

    Şimdiye kadar sadece eşitlik kontrolleri hakkında konuştuk. Genellikle bileşik dizinlerde sütunlardan birine karşı eşitsizliğe sahip olursunuz. örneğin "son N gün içinde bir müşteri için siparişleri / gönderileri / faturaları alın" gibi sorgular.

    Bu tür sorgularınız varsa, dizinin ilk sütununda eşitliği istiyorsanız:

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

    Karşı indeksi kullandıklarına dikkat edin.

    TL; DR

    • Eşitlik koşullarına sahip sütunlar dizinde ilk sırada yer almalıdır.
    • Sorgunuzda eşitliklere sahip birden çok sütun varsa, en az farklı değere sahip sütunu ilk sıraya yerleştirmek en iyi sıkıştırma avantajını sağlar
    • İndeks atlama taramaları mümkün olmakla birlikte, bunun öngörülebilir gelecek için uygun bir seçenek olarak kalacağından emin olmanız gerekir.
    • Neredeyse benzersiz sütunlar içeren bileşik dizinler, minimum fayda sağlar. 1-2 IO'yu gerçekten kaydetmeniz gerektiğinden emin olun

    1: Bazı durumlarda, sorgunuzdaki tüm sütunların dizinde olduğu anlamına gelirse, dizine bir sütun eklemeye değer olabilir. Bu, yalnızca bir dizin taramasını etkinleştirir, bu nedenle tabloya erişmeniz gerekmez.

    2: Tanılama ve Ayarlama lisansına sahipseniz, planı SQL Plan Yönetimi ile atlamayı zorlamaya zorlayabilirsiniz

    ADDEDNDA

    PS - orada alıntıladığınız dokümanlar 9i'den. Bu gerçekten yaşlı. Daha yeni bir şeye sadık kalırım


    Sorgu select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )gerçekten yaygın mı? Oracle, select count (distinct few_vals, many_vals, lots_vals )herhangi bir dize birleştirmesi yapmayan, sütunların metin türü olması gerekmeyen ve :karakterin yokluğuna bağlı olmayan sözdizimine izin vermez mi?
    ypercubeᵀᴹ

    @ ypercubeᵀᴹ count ( distinct x, y, z )Oracle'da yapamazsınız . Bu nedenle, farklı bir alt sorgu yapmanız ve sonuçları veya yukarıdaki gibi bir birleştirmeyi saymanız gerekir. Ben sadece bir tablo erişimi (sadece dizin taraması yerine) zorlamak için burada yaptım ve sonuçta sadece bir satır var
    Chris Saxon

    1

    Bir Kompozit Endeksin sütun seçiciliğinin yanı sıra neyle başlaması ve / veya içermesi gerektiğine dair nihai karara katkıda bulunan daha fazla sorgu öğesi vardır.

    Örneğin:

    1. ne tür sorgu operatörü kullanılıyor: Sorgularda
      ">,> =, <, <=" gibi işleçler varsa
    2. Sorgunun sonucu olarak kaç gerçek satır bekleniyor: Sorgu sonucu tablodaki satırların çoğu olacak mı?
    3. Where cümlesi sırasında tablo sütununda herhangi bir işlev kullanılıyor mu?

    ancak konuşmayı alakalı tutmak için aşağıdaki cevabım aşağıdaki durum için geçerlidir:

    1. "Belirli bir tablodaki% 90 sorgu türünde işleç içeren WHERE Yan tümcesi var ="
    2. "en fazla sorgu sonuç olarak tablodaki toplam satırların% 10'unu döndürüyor"
    3. "WHERE yan tümcesinde tablo sütununda hiçbir tür işlev kullanılmıyor"
    4. "WHERE Yan tümcesinde kullanılan zaman sütunlarının çoğu çoğunlukla
      string , type number türündedir"

    Deneyimlerime göre, DBA'nın dikkat etmesi gereken her ikisi de.

    Tek bir kuralın uygulandığını düşünelim:

    1) En seçici sütun ilk olmakla birlikte dizin oluşturursam, ancak bu sütun aslında bu tablodaki çoğu sorgu tarafından db motoru için kullanılmasından daha fazla kullanılmazsa.

    2) Bir sorguda en çok kullanılan sütunda bir dizinde ilk dizin olmak, ancak sütun benim sorgu performansı iyi olmayacak daha düşük seçiciliğe sahip bir dizin oluşturursanız.

    Çoğunlukla tablo sorgularının% 90'ında kullanılan sütunları listeleyeceğim. Sonra bunları sadece en kardinallik sırasına en az kardinaliteye yerleştirin.

    Dizinleri, okuma sorgusu performansını iyileştirmek için kullanırız ve bu iş akışı (okuma sorgusunun türleri) yalnızca dizin oluşturma işlemini yönlendirmelidir. Aslında veriler büyüdükçe (milyarlarca satır) sıkıştırılmış dizin depolama alanından tasarruf sağlayabilir, ancak okuma sorgusu performansına zarar verebilir.


    1

    Teoride en seçici sütun en hızlı araştırmayı sağlar. Ama işte, en seçici kısmı ilk önce 3 parçadan oluşan bileşik bir endekse sahip olduğum bir durumla karşılaştım. (tarih, yazar, yayıncılık şirketi diyelim ki, sırayla, tablo yazılarda başparmak izler) ve ben 3 bölümünün tümünü kullanan bir sorgu var. Mysql benim sorguda mevcut olmasına rağmen şirket ve tarih içeren bileşik dizini atlayarak yazar onlny dizinini kullanmak için varsayılan. Kompozit kullanmak için kuvvet endeksi kullandım ve sorgu aslında daha yavaş koştu. Bu neden oldu? Size söyleyeceğim:

    Tarihte bir aralık seçiyordum, bu nedenle tarihin çok seçici olmasına rağmen, aralık taramaları için kullandığımız gerçeği (aralık nispeten kısa olsa da, 6 yıllık verilerin 6 ayından 6'sı) kompoziti mySQL. Bu durumda kompoziti kullanmak için, mysql yeni yıllardan beri yazılan tüm makaleleri kapmak ve yazarın kim olduğunu araştırmak zorundadır ve yazarın diğer yazarlara kıyasla birçok makaleyi yazmamış olması nedeniyle, mysql sadece bu yazarı bulmayı tercih etti .

    Başka bir durumda, sorgu kompozit üzerinde çok daha hızlı koştu, durum bir yazarın çok popüler olduğu ve kayıtların çoğuna sahip olduğu, tarihe göre sıralama yapıldı. Ama mysql bu durumu otomatik olarak tespit etmedi, endeksi zorlamak zorunda kaldım ... Yani biliyorsun, değişir. Aralık taramaları, seçici sütununuzu işe yaramaz hale getirebilir. Verilerin dağıtımı, sütunların farklı kayıtlar için daha seçici olduğu durumlar oluşturabilir ...

    Farklı yapacağım, tarihi (yine teoride en seçici olanı) sağa kaydırmaktır, çünkü şimdi üzerinde bir aralık taraması yapacağımı biliyorum ve bu bir fark yaratıyor.


    1
    Sorgunuzda böyle bir şey varsa, WHERE (date BETWEEN @x AND @y) AND (author = @a) AND (publishing company = @p)üzerinde (author, publishing_company, date)veya üstünde bir dizin (publishing_company, author, date)daha iyi olurdu ve zorlanmadan kullanılır.
    ypercubeᵀᴹ

    -2

    Farklı durumlar için farklı durumlar. Hedefinizi bilin; sonra dizinlerinizi oluşturun ve her biri için açıklama planları çalıştırın ve durumunuz için en iyi cevabınız olacaktır.


    -2

    Gönderen Endeksinde Sütun sırayla Tom Ask tarih:

    Bu nedenle, dizininizdeki sütunların sırası SORULARINIZ NASIL yazıldığına bağlıdır. Dizini olabildiğince çok sorgu için kullanmak istiyorsunuz (sahip olduğunuz tüm dizin sayısını aşmak için) - sütunların sırasını yönlendirecektir. Başka bir şey yok (a veya b'nin seçiciliği hiç sayılmaz).

    Kabul edin, sütunları nerede cümleye göre sipariş etmemiz gerektiğini, ancak "(a veya b'nin seçiciliği hiç sayılmaz)" ifadesi doğru değildir.) ". ("nerede fıkra")

    Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
    Licensed under cc by-sa 3.0 with attribution required.