इंडेक्स कॉलम ऑर्डर चुनते समय, चिंता का विषय है:
क्या मेरे सवालों में इस कॉलम के खिलाफ (समानता) भविष्यवाणी है?
यदि स्तंभ कभी किसी खंड में प्रकट नहीं होता है, तो यह अनुक्रमण के लायक नहीं है (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 से हैं। यह बहुत पुराना है। मैं हाल ही में कुछ के साथ रहना चाहता हूँ