समग्र सूचकांक: सबसे पहले चयनात्मक स्तंभ?


17

मैं पढ़ composite indexesरहा हूं और मैं ऑर्डर देने को लेकर थोड़ा उलझन में हूं। यह दस्तावेज़ीकरण (नीचे आधे रास्ते से थोड़ा कम) कहता है

सामान्य तौर पर, आपको सबसे पहले अक्सर सूचकांक में उपयोग किए जाने वाले कॉलम को रखना चाहिए।

हालांकि, कुछ ही समय बाद यह कहता है

सबसे चुनिंदा कॉलम पहले डालते हुए एक समग्र सूचकांक बनाएं; वह है, सबसे अधिक मान वाला स्तंभ।

ओरेकल भी इसे दूसरे शब्दों में यहाँ कहता है

यदि सभी कुंजियों का उपयोग WHERE क्लॉज़ में समान रूप से अक्सर किया जाता है, तो इन कुंजियों को क्रिएट इंडेक्स स्टेटमेंट में सबसे चयनात्मक से कम से कम चयनात्मक बनाने के लिए ऑर्डर करने से क्वेरी प्रदर्शन में सुधार होता है।

हालाँकि, मुझे एक SO उत्तर मिला है जो अलग तरीके से कहता है। इसे कहते हैं

पहले कम से कम चयनात्मक स्तंभ के साथ स्तंभों की व्यवस्था करें और सबसे अंतिम स्तंभ चुनें। स्तंभ के साथ एक टाई लीड के मामले में जो अपने आप उपयोग किए जाने की अधिक संभावना है।

मैंने जो पहले दस्तावेज़ीकरण का उल्लेख किया है, वह कहता है कि आपको पहले सबसे अधिक बार उपयोग किया जाना चाहिए जबकि एसओ उत्तर कहता है कि केवल टाई ब्रेकिंग के लिए होना चाहिए। फिर वे भी आदेश देने पर भिन्न होते हैं।

यह प्रलेखन भी कहता है skip scanningऔर कहता है

कंपोजिट इंडेक्स के प्रमुख कॉलम में कुछ अलग वैल्यू होने और इंडेक्स के नॉनलाइडिंग की में कई अलग-अलग वैल्यू होने पर स्किप स्कैनिंग फायदेमंद है।

एक अन्य लेख कहता है

उपसर्ग कॉलम सबसे अधिक भेदभाव वाला और प्रश्नों में सबसे अधिक व्यापक रूप से उपयोग किया जाना चाहिए

मेरा मानना ​​है कि सबसे अधिक भेदभाव का मतलब सबसे विशिष्ट होगा।

इस शोध के सभी अभी भी मुझे एक ही सवाल पर ले जाते हैं; सबसे चयनात्मक स्तंभ पहले या अंतिम होना चाहिए? क्या पहले स्तंभ का सबसे अधिक उपयोग किया जाना चाहिए और केवल टाई-ब्रेक पर सबसे अधिक चयनात्मक होना चाहिए?

ये लेख एक दूसरे के विपरीत प्रतीत होते हैं, लेकिन वे कुछ उदाहरण प्रस्तुत करते हैं। जो मैंने इकट्ठा किया है, उससे यह प्रतीत होता है कि यदि आप अनुमान लगा रहे हैं तो आदेश देने में पहलेleast selective column से अधिक कुशल होना चाहिए । लेकिन मुझे यकीन नहीं है कि अगर यह सही है।Index Skip Scans


जवाबों:


9

AskTom से

(9i में, एक नया "इंडेक्स स्किप स्कैन" है - इसके बारे में पढ़ने के लिए वहां खोजें। यह इंडेक्स (ए, बी) या (बी, ए) उपरोक्त दोनों मामलों में कभी-कभी उपयोगी बनाता है! "

तो, आपकी अनुक्रमणिका में स्तंभों का क्रम इस बात पर निर्भर करता है कि कैसे आपके प्रश्न लिखे गए हैं। आप अनुक्रमणिका का उपयोग उतने प्रश्नों के लिए कर सकते हैं जितना आप कर सकते हैं (ताकि आपके पास मौजूद सभी अनुक्रमणिकाओं की संख्या में कटौती हो सके) - जो स्तंभों के क्रम को चलाएंगे। और कुछ नहीं (एक बी की चयनात्मकता बिल्कुल भी नहीं गिनती है)।

कम से कम भेदभाव (कम विशिष्ट मूल्यों) से लेकर सबसे अधिक भेदभाव (अधिक विशिष्ट मान) के लिए समग्र सूचकांक में स्तंभों की व्यवस्था करने का एक तर्क सूचकांक कुंजी संपीड़न के लिए है।

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

सूचकांक के आंकड़ों के अनुसार, पहला सूचकांक अधिक संकुचित है।

एक और है कि कैसे आपके प्रश्नों में सूचकांक का उपयोग किया जाता है। यदि आपके प्रश्नों का उपयोग ज्यादातर col1,

उदाहरण के लिए, यदि आपके प्रश्न हैं जैसे-

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

    -इसके index(col1,col2)बाद बेहतर प्रदर्शन करेंगे।

    यदि आपके प्रश्नों का उपयोग ज्यादातर col2,

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

    -इसके index(col2,col1)बाद बेहतर प्रदर्शन करेंगे। यदि आपके सभी प्रश्न हमेशा दोनों स्तंभों को निर्दिष्ट करते हैं, तो इससे कोई फर्क नहीं पड़ता कि समग्र सूचकांक में कौन सा कॉलम पहले आता है।

    अंत में, समग्र सूचकांक के स्तंभ क्रम में प्रमुख विचार सूचकांक कुंजी संपीड़न हैं और आप अपने प्रश्नों में इस सूचकांक का उपयोग कैसे करने जा रहे हैं।

    संदर्भ:

  • सूचकांक में स्तंभ क्रम
  • यह एक सूचकांक (दाएं) में कम कार्डिनैलिटी अग्रणी कॉलम है करने के लिए कम कुशल है?
  • इंडेक्स स्किप स्कैन - क्या इंडेक्स कॉलम ऑर्डर मैटर को और अधिक करता है? (चेतावनी का संकेत)


  • 3

    सबसे पहले चयनात्मक केवल तब उपयोगी होता है जब यह कॉलम वास्तविक WHERE क्लॉज में होता है।

    जब SELECT एक बड़े समूह (कम चयनात्मक) द्वारा होता है, और फिर संभवतः अन्य, गैर-अनुक्रमित मानों के साथ, कम चयनात्मक स्तंभों वाला एक सूचकांक अभी भी उपयोगी हो सकता है (यदि कोई कारण नहीं है कि एक और बना हो)।

    यदि कोई तालिका ADDRESS है, तो

    देश की नागरिकता, कुछ और ...

    STREET, CITY, COUNTRY अनुक्रमण एक सड़क के नाम के साथ सबसे तेज प्रश्नों का उत्पादन करेगा। लेकिन एक शहर की सभी सड़कों को क्वेरी करते हुए, इंडेक्स बेकार हो जाएगा, और क्वेरी संभवतः एक पूर्ण टेबल स्कैन करेगी।

    इंडेक्सिंग COUNTRY, CITY, STREET व्यक्तिगत सड़कों के लिए थोड़ा धीमा हो सकता है, लेकिन इंडेक्स का उपयोग अन्य प्रश्नों के लिए किया जा सकता है, केवल देश और / या शहर का चयन करके।


    3

    इंडेक्स कॉलम ऑर्डर चुनते समय, चिंता का विषय है:

    क्या मेरे सवालों में इस कॉलम के खिलाफ (समानता) भविष्यवाणी है?

    यदि स्तंभ कभी किसी खंड में प्रकट नहीं होता है, तो यह अनुक्रमण के लायक नहीं है (1)

    ठीक है, इसलिए आपको प्रत्येक स्तंभ के खिलाफ एक तालिका और क्वेरीज़ मिल गई हैं। कभी-कभी एक से अधिक।

    आप कैसे तय करेंगे कि सूचकांक क्या है?

    आइए एक उदाहरण देखें। यहां एक टेबल है जिसमें तीन कॉलम हैं। एक 10 मान रखता है, दूसरा 1,000, अंतिम 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     

    ये संख्याएं हैं जो शून्य से गद्देदार हैं। यह बाद में संपीड़न के बारे में बात करने में मदद करेगा।

    तो आपको तीन सामान्य प्रश्न मिले हैं:

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

    आप क्या सूचकांक करते हैं?

    कुछ ही अंतराल पर एक सूचकांक केवल एक पूर्ण तालिका स्कैन की तुलना में थोड़ा बेहतर है:

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

    तो यह अपने आप ही अनुक्रमण के लायक होने की संभावना नहीं है। लॉट_ अंतराल पर क्वेरी कुछ पंक्तियाँ लौटाती हैं (इस मामले में सिर्फ 1)। तो यह निश्चित रूप से अनुक्रमण के लायक है।

    लेकिन दोनों स्तंभों के खिलाफ प्रश्नों के बारे में क्या?

    क्या आपको सूचकांक करना चाहिए:

    ( few_vals, lots_vals )

    या

    ( lots_vals, few_vals )

    चतुर सवाल!

    इसका उत्तर न तो है।

    यकीन है कि कुछ अंतराल एक लंबी स्ट्रिंग है। तो आप इसे से अच्छा संपीड़न प्राप्त कर सकते हैं। और आपको (हो सकता है) एक इंडैक्स स्किप स्कैन का उपयोग करके क्वेरीज़ (थोड़े से अंतराल, बहुत से अंतराल) का इस्तेमाल करना पड़े, जो केवल बहुत सारे अंतरालों पर आधारित हो। लेकिन मैं यहाँ नहीं है, भले ही यह एक पूर्ण स्कैन की तुलना में बेहतर प्रदर्शन करता है:

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

    क्या आपको जुआ पसंद है? (2)

    तो आपको अभी भी अग्रणी स्तंभ के रूप में lot_vals एक सूचकांक की आवश्यकता है। और कम से कम इस मामले में कंपाउंड इंडेक्स (कुछ, बहुत सारे) एक ही काम करता है जैसे एक (बहुत सारे)

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

    ऐसे मामले होंगे जहां यौगिक सूचकांक आपको 1-2 IOs बचाता है। लेकिन क्या इस बचत के लिए दो सूचकांक होना जरूरी है?

    और समग्र सूचकांक के साथ एक और समस्या है। 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    

    ध्यान दें कि some_lots के लिए क्लस्टरिंग कारक लॉट और लॉट_फ्यू की तुलना में 10x अधिक है! और यह एक डेमो तालिका में है जिसमें शुरुआत करने के लिए सही क्लस्टरिंग है। वास्तविक विश्व डेटाबेस में प्रभाव के बदतर होने की संभावना है।

    तो इसमें इतना बुरा क्या है?

    क्लस्टरिंग फैक्टर प्रमुख चालकों में से एक है जो यह निर्धारित करता है कि सूचकांक कितना "आकर्षक" है। यह जितना अधिक होगा, ऑप्टिमाइज़र के चयन की संभावना उतनी ही कम होगी। विशेष रूप से अगर लॉट_अल्वा वास्तव में अद्वितीय नहीं हैं, लेकिन फिर भी सामान्य रूप से प्रति मूल्य कुछ पंक्तियाँ हैं। यदि आप अशुभ हैं, तो यह आशावादी बनाने के लिए पर्याप्त हो सकता है कि एक पूर्ण स्कैन सस्ता है ...

    ठीक है, इसलिए कुछ और अंतरालों वाले लॉट इंडेलेज़ को केवल बढ़त मामले में लाभ होता है।

    कुछ प्रश्नों को फ़िल्टर करने के बारे में क्या है?

    सिंगल कॉलम इंडेक्स केवल छोटे लाभ देते हैं। लेकिन संयुक्त उन्होंने कुछ मूल्य वापस कर दिए। इसलिए एक समग्र सूचकांक एक अच्छा विचार है। लेकिन कौन सा रास्ता गोल?

    यदि आप कुछ पहले रखते हैं, तो अग्रणी कॉलम को संपीड़ित करने से वह छोटा हो जाएगा

    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      

    अग्रणी स्तंभ में कम भिन्न मूल्यों के साथ बेहतर संपीड़ित करता है। इसलिए इस सूचकांक को पढ़ने के लिए थोड़ा कम काम है। लेकिन केवल थोड़ा। और दोनों पहले से ही मूल (25% आकार में कमी) की तुलना में एक अच्छा हिस्सा हैं।

    और आप आगे जा सकते हैं और पूरे सूचकांक को संकुचित कर सकते हैं!

    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   

    अब दोनों सूचकांक एक ही आकार में वापस आ गए हैं। ध्यान दें कि यह इस तथ्य का लाभ उठाता है कि कुछ और कई के बीच एक संबंध है। फिर इसकी संभावना नहीं है कि आप वास्तविक दुनिया में इस तरह का लाभ देखेंगे।

    अब तक हमने केवल समानता जांच के बारे में बात की है। अक्सर कम्पोजिट इंडेक्स के साथ आपको कॉलम में से एक के खिलाफ असमानता होगी। उदाहरण के लिए जैसे कि "पिछले दिनों में एक ग्राहक के लिए आदेश / शिपमेंट / चालान प्राप्त करें"।

    यदि आपके पास इस प्रकार के प्रश्न हैं, तो आप सूचकांक के पहले कॉलम के खिलाफ समानता चाहते हैं:

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

    ध्यान दें कि वे विपरीत सूचकांक का उपयोग कर रहे हैं।

    टी एल; डॉ

    • समानता की स्थिति वाले स्तंभों को पहले सूचकांक में जाना चाहिए।
    • यदि आपकी क्वेरी में समानता के साथ कई कॉलम हैं, तो सबसे अलग मूल्यों को सबसे पहले रखने से सबसे अच्छा संपीड़न लाभ मिलेगा
    • हालांकि इंडेक्स स्किप स्कैन संभव है, आपको आश्वस्त होने की जरूरत है कि यह भविष्य के लिए एक व्यवहार्य विकल्प रहेगा
    • निकट-अद्वितीय स्तंभों सहित समग्र सूचकांक न्यूनतम लाभ देते हैं। सुनिश्चित करें कि आपको वास्तव में 1-2 IOs को बचाने की आवश्यकता है

    1: कुछ मामलों में यह एक इंडेक्स में एक कॉलम सहित शामिल हो सकता है यदि इसका मतलब है कि आपकी क्वेरी के सभी कॉलम इंडेक्स में हैं। यह एक सूचकांक को केवल स्कैन करने में सक्षम बनाता है, इसलिए आपको तालिका तक पहुंचने की आवश्यकता नहीं है।

    2: यदि आपको डायग्नोस्टिक्स और ट्यूनिंग के लिए लाइसेंस प्राप्त है, तो आप योजना को SQL योजना प्रबंधन के साथ स्कैन को छोड़ सकते हैं

    ADDEDNDA

    PS - आपके द्वारा उद्धृत डॉक्स 9i से हैं। यह बहुत पुराना है। मैं हाल ही में कुछ के साथ रहना चाहता हूँ


    क्या select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )वास्तव में सामान्य के साथ एक क्वेरी है ? क्या ओरेकल वाक्यविन्यास की अनुमति नहीं देता है select count (distinct few_vals, many_vals, lots_vals )- जो किसी भी स्ट्रिंग संयोजन को नहीं करता है, पाठ प्रकार के कॉलम की आवश्यकता नहीं है और :चरित्र की अनुपस्थिति पर भरोसा नहीं करता है ?
    ypercube y

    @ ypercube y आप count ( distinct x, y, z )Oracle में नहीं कर सकते । तो आपको एक अलग उपश्रेणी करने की जरूरत है और परिणाम या एक उपर्युक्त की गणना करें। मैंने इसे केवल टेबल एक्सेस (इंडेक्स ओनली स्कैन के बजाय) के लिए मजबूर किया और परिणाम में सिर्फ एक पंक्ति है
    क्रिस सैक्सन

    1

    कंपोजिट इंडेक्स की शुरुआत और कॉलम की चयनात्मकता के अलावा क्या होना चाहिए, इस पर अंतिम निर्णय के लिए क्वेरी के अधिक तत्व योगदान करते हैं।

    उदाहरण के लिए:

    1. किस प्रकार के क्वेरी ऑपरेटर का उपयोग किया जा रहा है: यदि प्रश्नों में
      ">,> =, <, <=" जैसे ऑपरेटर हैं
    2. क्वेरी के परिणामस्वरूप कितनी वास्तविक पंक्तियों की अपेक्षा की जाती है: क्या क्वेरी परिणाम तालिका से अधिकांश पंक्तियों का होने वाला है।
    3. क्या खंड के दौरान किसी भी फ़ंक्शन का उपयोग तालिका स्तंभ पर किया जा रहा है: यदि क्वेरी में कोई फ़ंक्शन UPPER, LOWER, TRIM है, तो उस स्थिति में उपयोग किए जा रहे स्तंभ पर उपयोग किए जा रहे SUBSTRING।

    अभी भी बातचीत को प्रासंगिक बनाए रखने के लिए मेरा निम्न उत्तर निम्न स्थिति पर लागू होता है:

    1. "किसी दिए गए टेबल पर 90% प्रकार के प्रश्नों में ऑपरेटर के साथ WHERE क्लॉज है ="
    2. "अधिकांश क्वेरी में परिणाम के रूप में तालिका में कुल पंक्तियों का 10% वापस आ रहा है"
    3. "WHERE क्लॉज में टेबल कॉलम पर किसी भी प्रकार के फ़ंक्शन का उपयोग नहीं किया जा रहा है"
    4. "WHERE क्लॉज में ज्यादातर समय कॉलम ज्यादातर टाइप नंबर,
      स्ट्रिंग के होते हैं"

    मेरे अनुभव में, यह दोनों डीबीए के बारे में दिमाग होना चाहिए।

    आइए कल्पना करें कि केवल एक नियम लागू किया जा रहा है:

    1) अगर मैं सबसे पहले चुनिंदा कॉलम के साथ इंडेक्स बनाता हूं, लेकिन उस कॉलम का वास्तव में उस तालिका के अधिकांश प्रश्नों द्वारा उपयोग नहीं किया जाता है, तो यह डीबी इंजन के लिए कोई उपयोग नहीं है।

    2) अगर मैं किसी इंडेक्स में सबसे व्यापक रूप से उपयोग किए जाने वाले कॉलम के साथ एक इंडेक्स बनाता हूं, लेकिन कॉलम में कम चयनात्मकता है, तो मेरी क्वेरी का प्रदर्शन भी अच्छा नहीं है।

    मैं उन कॉलमों को सूचीबद्ध करूँगा जिनका उपयोग ज्यादातर 90% तालिका प्रश्नों में किया जाता है। फिर उन लोगों को केवल सबसे अधिक कार्डिनैलिटी के लिए कम से कम कार्डिनैलिटी के क्रम में रखें।

    हम रीड क्वेरी प्रदर्शन को बेहतर बनाने के लिए इंडेक्स का उपयोग करते हैं और उस वर्कफ़्लो (एक रीड क्वेरी के प्रकार) को केवल इंडेक्स निर्माण को चलाना चाहिए। वास्तव में जैसे-जैसे डेटा बढ़ता है (अरबों पंक्तियों) संपीड़ित सूचकांक भंडारण को बचा सकता है, लेकिन निश्चित रूप से पढ़ा क्वेरी प्रदर्शन को चोट पहुंचा सकता है।


    1

    सिद्धांत रूप में सबसे चयनात्मक स्तंभ सबसे तेजी से खोज करता है। लेकिन काम पर मैं सिर्फ एक स्थिति पर ठोकर खाई, जहां हमारे पास पहले सबसे अधिक चयनात्मक भाग के साथ 3 भागों का एक संयुक्त सूचकांक है। (दिनांक, लेखक, प्रकाशन कंपनी कहती है, उस क्रम में, टेबल पोस्ट्स पर अंगूठे की निगरानी करता है) और मेरे पास एक क्वेरी है जो 3 भागों का उपयोग करती है। मेरीक्ले ने लेखक के ऑनलिनी इंडेक्स को कंपोजिट इंडेक्स युक्त कंपनी और तारीख का उपयोग करने के लिए डिफॉल्ट किया, बावजूद इसके कि वे मेरी क्वेरी में मौजूद थे। मैंने कंपोजिट का उपयोग करने के लिए बल सूचकांक का उपयोग किया और क्वेरी वास्तव में धीमी गति से चली। ऐसा क्यों हुआ? मैं आपको बताता हूँ:

    मैं तारीख पर एक सीमा का चयन कर रहा था, इसलिए तिथि अत्यधिक चयनात्मक होने के बावजूद, हम इसे स्कैन रेंज के लिए उपयोग कर रहे हैं (भले ही सीमा अपेक्षाकृत कम हो, 6 महीने के 6 महीने के डेटा में से) समग्र को हानिकारक बना दिया माई एसक्यूएल। उस विशेष मामले में समग्र का उपयोग करने के लिए, mysql को नए साल के बाद से लिखे गए सभी लेखों को हथियाना होगा, फिर लेखक कौन होगा, और यह देखते हुए कि लेखक ने यह नहीं लिखा है कि कई लेख अन्य लेखकों की तुलना में हैं, mysql सिर्फ उस लेखक को ढूंढना पसंद करते हैं ।

    एक अन्य मामले में क्वेरी समग्र पर बहुत तेजी से चली, मामला तब था जब एक लेखक बेहद लोकप्रिय था और अधिकांश अभिलेखों के स्वामित्व वाले थे, तिथि के आधार पर छांटे गए। लेकिन mysql ने उस केस का पता नहीं लगाया, मुझे इंडेक्स को बाध्य करना पड़ा ... तो आप जानते हैं, यह भिन्न होता है। रेंज स्कैन आपके चुनिंदा कॉलम को बेकार कर सकता है। डेटा का वितरण ऐसे मामले बना सकता है जहां कॉलम विभिन्न रिकॉर्ड के लिए अधिक चयनात्मक हैं ...

    मैं अलग से क्या करूंगा तारीख को शिफ्ट (जो फिर से, सिद्धांत में सबसे अधिक चयनात्मक है) दाईं ओर, क्योंकि मुझे पता है कि मैं अब इस पर एक रेंज स्कैन कर रहा हूं और इससे फर्क पड़ता है।


    1
    यदि आपकी क्वेरी कुछ ऐसी थी, WHERE (date BETWEEN @x AND @y) AND (author = @a) AND (publishing company = @p)तो उस पर (author, publishing_company, date)या उस पर एक इंडेक्स (publishing_company, author, date)बेहतर होगा और इसका उपयोग किया जाएगा - बिना मजबूर किए।
    ypercube y

    -2

    विभिन्न स्थितियों के लिए अलग-अलग मामले। अपने लक्ष्य को जानें; फिर अपनी अनुक्रमणिका बनाएं और प्रत्येक के लिए स्पष्टीकरण योजनाएं चलाएं और आपकी स्थिति के लिए आपके पास सबसे अच्छा जवाब होगा।


    -2

    टॉम से पूछो पर सूचकांक में कॉलम के आदेश से :

    तो, आपकी अनुक्रमणिका में स्तंभों का क्रम इस बात पर निर्भर करता है कि कैसे आपके प्रश्न लिखे गए हैं। आप अनुक्रमणिका का उपयोग उतने प्रश्नों के लिए कर सकते हैं जितना आप कर सकते हैं (ताकि आपके पास मौजूद सभी अनुक्रमणिकाओं की संख्या में कटौती हो सके) - जो स्तंभों के क्रम को चलाएंगे। और कुछ नहीं (एक बी की चयनात्मकता बिल्कुल भी नहीं गिनती है)।

    सहमत हों, कि हमें क्लॉज के आधार पर कॉलम ऑर्डर करना है, लेकिन स्टेटमेंट "(a या b की चॉइस की गिनती बिल्कुल भी सही नहीं है)" "सही नहीं है।" "। सबसे सिलेक्टिव कॉलम को लीड करना चाहिए, यदि वह पहली भूमिका से संतुष्ट हो। ("कहां कारण")

    हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
    Licensed under cc by-sa 3.0 with attribution required.