ओरेकल एक लंबी कुंजी के लिए एक अद्वितीय सूचकांक का उपयोग नहीं कर रहा है


16

मेरे पास मेरे परीक्षण डेटाबेस में 250K पंक्तियों के साथ एक तालिका है। (उत्पादन में कुछ सौ मिलियन हैं, हम वहां एक ही मुद्दे का निरीक्षण कर सकते हैं।) तालिका में एक अद्वितीय सूचकांक के साथ nvarchar2 (50) स्ट्रिंग पहचानकर्ता, शून्य नहीं है (यह पीके नहीं है)।

पहचानकर्ता पहले भाग से बने होते हैं, जिसमें मेरे परीक्षण डेटाबेस में 8 अलग-अलग मान होते हैं (और उत्पादन में लगभग एक हजार), फिर एक @ चिह्न, और अंत में एक संख्या, 1 से 6 अंक लंबा होता है। उदाहरण के लिए 50 हजार पंक्तियाँ हो सकती हैं जो 'ABCD_BGX1741F_2006_13_20110808.xml @' से शुरू होती हैं, और इसके बाद 50 हजार अलग-अलग संख्याएँ होती हैं।

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

परीक्षण के रूप में, मैंने उसी डीडीएल और ठीक उसी सामग्री के साथ तालिका (एक ही स्कीमा + टेबलस्पेस में) की नकल की। मैंने अच्छे माप के लिए पहली तालिका में अद्वितीय सूचकांक को फिर से बनाया, और क्लोन तालिका पर सटीक एक ही सूचकांक बनाया। मैंने ए DBMS_STATS.GATHER_SCHEMA_STATS('schemaname',estimate_percent=>100,cascade=>true);। आप यह भी देख सकते हैं कि सूचकांक के नाम लगातार हैं। तो अब दोनों तालिकाओं के बीच एकमात्र अंतर यह है कि पहले एक लंबे समय की अवधि में यादृच्छिक क्रम में लोड किया गया था, डिस्क पर बिखरे हुए ब्लॉकों के साथ (एक टेबलस्पेस में कई अन्य बड़ी तालिकाओं के साथ), दूसरे को एक बैच के रूप में लोड किया गया था सम्मिलित करें-का चयन करें। इसके अलावा, मैं किसी भी अंतर की कल्पना नहीं कर सकता। (मूल तालिका पिछले बड़ी विलोपन के बाद से सिकुड़ गई है, और उसके बाद एक भी डिलीट नहीं हुई है।)

यहां बीमारों और क्लोन तालिका के लिए क्वेरी योजनाएं हैं (काले ब्रश के नीचे के तार तस्वीर पर सभी समान हैं, और वे ग्रे ब्रश के नीचे भी हैं।)

क्वेरी की योजना

(इस उदाहरण में, 1867 पंक्तियाँ हैं जो पहचानकर्ता के साथ शुरू होती हैं जो काला ब्रश है। 2-पंक्ति क्वेरी 1867 * 2 की कार्डिनैलिटी का उत्पादन करती है, एक 3-पंक्ति क्वेरी 1867 * 3 की कार्डिनैलिटी पैदा करती है, आदि। संयोग की बात है, ओरेकल को पहचानकर्ताओं के अंत की परवाह नहीं है।)

इस व्यवहार का क्या कारण हो सकता है? जाहिर है उत्पादन में तालिका को फिर से बनाना बहुत महंगा होगा।

USER_TABLES: http://i.stack.imgur.com/nDWze.jpg USER_INDEXES: http://i.stack.imgur.com/DG9um.jpg मैंने केवल स्कीमा और तालिकाओं का नाम बदल दिया है। आप देख सकते हैं कि टेबल और इंडेक्स नाम क्वेरी प्लान स्क्रीनशॉट पर समान हैं।

जवाबों:


7

(यह हिस्टोग्राम अलग क्यों हैं, इस बारे में अन्य प्रश्न का उत्तर देता है ।)

हिस्टोग्राम को डिफ़ॉल्ट रूप से स्तंभ तिरछा और के आधार पर बनाया जाता है क्या स्तंभ का उपयोग प्रासंगिक विधेय में किया गया था। डीडीएल और डेटा की प्रतिलिपि बनाना पर्याप्त नहीं है, कार्यभार की जानकारी भी महत्वपूर्ण है।

प्रदर्शन ट्यूनिंग गाइड के अनुसार :

जब आप एक तालिका ड्रॉप करते हैं, तो ऑटो-हिस्टोग्राम एकत्रित करने की सुविधा द्वारा उपयोग की जाने वाली कार्यभार जानकारी और सहेजे गए आँकड़ों के इतिहास का उपयोग RESTORE _ * _ STATS प्रक्रियाओं द्वारा किया जाता है। इस डेटा के बिना, ये सुविधाएँ ठीक से काम नहीं करती हैं।

उदाहरण के लिए, यहां तिरछी डेटा वाली एक तालिका है, लेकिन कोई हिस्टोग्राम नहीं है:

drop table test1;
create table test1(a date);
insert into test1 select date '2000-01-01'+level from dual connect by level <= 10;
insert into test1 select date '2000-01-01' from dual connect by level <= 1000;
begin
    dbms_stats.gather_table_stats(user, 'TEST1');
end;
/
select histogram from user_tab_columns where table_name = 'TEST1';

HISTOGRAM
---------
NONE

एक ही चीज़ चलाना, लेकिन आँकड़ों को इकट्ठा करने से पहले एक क्वेरी के साथ, हिस्टोग्राम उत्पन्न करेगा।

drop table test1;
create table test1(a date);
insert into test1 select date '2000-01-01'+level from dual connect by level <= 10;
insert into test1 select date '2000-01-01' from dual connect by level <= 1000;
select count(*) from test1 where a = sysdate; --Only new line
begin
    dbms_stats.gather_table_stats(user, 'TEST1');
end;
/
select histogram from user_tab_columns where table_name = 'TEST1';

HISTOGRAM
---------
FREQUENCY

2
शानदार ढंग से सरल उदाहरण। क्या आपके पास कोई विचार है कि सीबीओ सिर्फ 1 मानने के बजाय एक अद्वितीय स्कैन पर कार्डिनैलिटी अनुमानों के लिए हिस्टोग्राम का उपयोग क्यों कर रहा था?
जैक का कहना है कि टॉप्सनवर्स की कोशिश करें ।xyz

धन्यवाद! मैंने अपने ब्लॉग पर अपने तरह के डेटा और प्रश्नों के साथ एक पूर्ण पुनर्विचार किया
fejesjoco

@ जेक मुझे लगता है कि यह आलस्य है। ओरेकल इंजीनियरों ने यह पता लगाया होगा कि एक अद्वितीय सूचकांक के आंकड़ों में पंक्तियों के समान भिन्न मान होंगे, इसलिए 1 कार्डिनैलिटी धारणा को कठोर नहीं किया जाता है, लेकिन केवल आंकड़ों से उपयोग किया जाता है, जैसा कि किसी अन्य मामले में है। इसके अलावा, एक सामान्य मामले के रूप में, हिस्टोग्राम के ट्रम्प सरल आँकड़े हैं। केवल लंबी कुंजियों के कारण मेरा मामला बहुत ही विशेष प्रतीत होता है, लेकिन मेरा मानना ​​है कि यह बहुत अच्छी तरह से काम करता है।
फेजेसजोको

@ फैजेसजोको मुझे लगता है कि जेएल की व्याख्या अधिक संभावना है, क्योंकि हिस्टोग्राम भी एक ही लुकअप (बिना in) के मामले में सामान्य आँकड़ों को रौंद देगा, है ना? मुझे लगता है कि CBO कार्डिनैलिटी 1 धारणा बनाता है, लेकिन केवल सबसे सरल मामले में। मुझे लगता है कि आप एक बड़े का उपयोग करके पूरे काम कर UNION ALLसकते हैं, लेकिन ऐसा नहीं करने के अन्य कारण हो सकते हैं और जेएल ने लिंक किए गए ब्लॉग पोस्ट में अन्य संभावित वर्कअराउंड का उल्लेख किया है।
जैक का कहना है कि topanswers.xyz

1
विचार करने के लिए एक और मामूली रहस्य - यह हिस्टोग्राम पहली जगह में कैसे बना? ओरेकल केवल एक कॉलम पर विचार करने के लिए लगता है अगर यह डुप्लिकेट है, तो जाहिर है कि आपके अद्वितीय कॉलम में नहीं हो सकता है। क्या किसी ने जानबूझकर इस हिस्टोग्राम (असंभावित) का निर्माण किया है, या किसी ने गैर-अनुशंसित के साथ आँकड़े एकत्र किए हैं method_opt=>'for all indexed columns'?
जॉन हेलर

8

मैंने हल ढूंढ लिया! यह बहुत सुंदर है और मैंने वास्तव में ओरेकल के बारे में बहुत कुछ सीखा है।

एक शब्द में: हिस्टोग्राम।

मैंने बहुत पढ़ना शुरू किया कि ओरेकल का सीबीओ कैसे काम करता है और मैं हिस्टोग्राम पर ठोकर खाई। मुझे पूरी तरह से समझ में नहीं आया इसलिए मैंने USER_HISTOGRAMS तालिका, और voilá पर एक नज़र डाली। बीमार मेज के लिए कई पंक्तियाँ थीं, और व्यावहारिक रूप से क्लोन तालिका के लिए कुछ भी नहीं था। बीमार तालिका के लिए, प्रत्येक 8 अलग-अलग पहचानकर्ता-शुरुआती-भागों के लिए एक पंक्ति थी। और यह कुंजी है: वे 32 अक्षरों से कट गए थे, @ चिह्न से पहले। जैसा कि मैंने कहा, चाबियों का पहला भाग अत्यधिक दोहराव वाला है, वे @ चिह्न के बाद अलग हो जाते हैं।

ऐसा लगता है कि हिस्टोग्राम सरल तथ्य से अधिक शक्तिशाली हो सकता है कि एक अद्वितीय सूचकांक में हमेशा दिए गए मूल्य के लिए 0 या 1 की कार्डिनैलिटी होती है। जब मैं 2+ पंक्तियों के लिए क्वेरी कर रहा था, तो ओरेकल ने हिस्टोग्राम को देखा, यह सोचा कि उस पहचानकर्ता-शुरुआती-भाग के लिए दसियों हजार मूल्य हो सकते हैं, और इसने सीबीओ को बंद कर दिया।

मैंने पुराने कॉलम में उस कॉलम के लिए हिस्टोग्राम को हटा दिया और समस्या दूर हो गई!

अधिक पढ़ने: https://blogs.oracle.com/optimizer/entry/how_do_i_drop_an_existing_histogram_on_a_column_and_stop_the_auto_stats_gathit_job_from_creating


2
मैंने उल्लेख किया कि हमारे चैट रूम में :) chat.stackexchange.com/transcript/message/12987649#12987649
Philᵀᴹ

मैंने वह नहीं देखा :)। तो केवल अजीब बात यह है कि पहली तालिका में हिस्टोग्राम क्यों थे और क्लोन में नहीं था, मैंने सोचा कि इकट्ठा_केम_स्टेट्स ने सब कुछ अपडेट किया, जाहिरा तौर पर नहीं।
फेलेजजोको

6

मैंने इस बारे में जोनाथन लुईस को ईमेल किया और बहुत उपयोगी उत्तर मिला:

गणना में विषमता वर्ण-आधारित हिस्टोग्राम पर सीमाओं का एक परिणाम है, विशेष रूप से देखें:

http://jonathanlewis.wordpress.com/2010/10/13/frequency-histogram-5/ http://jonathanlewis.wordpress.com/2010/10/19/frequency-histograms-6/

उदाहरण को देखते हुए, क्वेरी एक IN सूची के लिए है, एक पंक्ति के लिए नहीं, इसलिए मेरा प्रारंभिक अनुमान यह होगा कि ऑप्टिमाइज़र ने एक विशेष कोड का कोड होने के बजाय बहु-पंक्ति चयनात्मकता की गणना के लिए एक सामान्य रणनीति का उपयोग किया है प्राथमिक कुंजी पर सूची। मुझे लगता है कि इस मामले को पहचानना उनके लिए बहुत कठिन नहीं होगा, लेकिन डेवलपर्स ने शायद इसे प्रयास के लायक नहीं माना है।

मैंने उनके द्वारा लिंक की गई ब्लॉग पोस्टों को पढ़ने की अत्यधिक अनुशंसा की, वे आपके द्वारा चलाए जा रहे हिस्टोग्राम्स की सीमा का विस्तार से वर्णन करते हैं, जैसे:

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


अफसोस की बात है कि हिस्टोग्राम्स एक छोटी ज्ञात विशेषता है, मुझे लगता है कि यह इसलिए है क्योंकि यह एक एसक्यूएल डेवलपर के लिए बहुत गहरा है और ज्यादातर समय वे बस काम करते हैं, लेकिन यह जानना अच्छा है कि इसके बारे में कई संसाधन हैं, मैं अभी नहीं देख रहा था सही जगह :)। यह बहुत बुरा है कि ओरेकल 32 बाइट्स में कटौती करता है और उसी के आधार पर विनाशकारी निर्णय लेता है। सौभाग्य से, मुझे किसी भी ट्विकिंग की आवश्यकता नहीं है, हिस्टोग्राम को छोड़ना एक सही समाधान है। मुख्य मूल्य अद्वितीय हैं, मैं हमेशा एक समय में 20 मूल्यों की तलाश करता हूं, यह केवल एक सूचकांक के साथ ठीक काम करता है, और यह निर्धारक है। लेकिन मैं अगली बार लंबी कुंजियों का उपयोग नहीं करूंगा, यह सुनिश्चित करने के लिए है।
जेजेस्कोको

हिस्टोग्राम बहुत अच्छी तरह से डीबीए के बीच जाना जाता है;) मुझे इस तथ्य से प्यार है कि आप गहरी चीजें सीखने के लिए उत्सुक हैं और वास्तव में आपको लगता है कि आपको जेएल की पुस्तक को पढ़ना चाहिए यह बहुत अच्छा है। सीबीओ आम तौर पर एक महान काम करता है: हमेशा ऐसे किनारे मामले होंगे जिनकी जांच की आवश्यकता है लेकिन यह ध्यान में रखने योग्य है कि कट ऑफ के बिना भी, अनुमान हमेशा सिर्फ अनुमान होते हैं।
जैक का कहना है कि topanswers.xyz

1
यदि आप एक नियमित आँकड़े की नौकरी चलाते हैं (जैसे कि एक क्लीन इंस्टॉल पर डिफ़ॉल्ट रूप से ओरेकल चलता है ), तो आप हिस्टोग्राम को फिर से देख सकते हैं, आपको इसे रोकने के तरीके पर ध्यान देने की आवश्यकता हो सकती है (जैसे कि LOCK_TABLE_STATS शायद
जैक कहते हैं कि टॉपसेंसर की कोशिश करें। xyz

मैंने अपने उत्तर में एक ब्लॉग पोस्ट का उल्लेख किया, एक स्तंभ के लिए हिस्टोग्राम को कैसे रोका जाए, इस पर निर्देश हैं।
जेजेस्कोको

1
@ जैक डगलस, जे। लुईस को शामिल करने और वापस रिपोर्टिंग के लिए धन्यवाद!
दिमित्रे रादौलोव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.