क्यों आशावादी द्वारा तलाश नहीं की जाती है
टीएल: डीआर विस्तारित कम्प्यूटेड कॉलम परिभाषा शुरू में पुन: जुड़ने के लिए ऑप्टिमाइज़र की क्षमता के साथ हस्तक्षेप करती है। एक अलग शुरुआती बिंदु के साथ, लागत-आधारित अनुकूलन ऑप्टिमाइज़र के माध्यम से एक अलग रास्ता लेता है, और एक अलग अंतिम योजना विकल्प के साथ समाप्त होता है।
विवरण
सभी के लिए लेकिन सबसे सरल प्रश्नों में से, ऑप्टिमाइज़र संभव योजनाओं के पूरे स्थान की तरह कुछ भी तलाशने का प्रयास नहीं करता है। इसके बजाय, यह एक उचित दिखने वाला शुरुआती बिंदु चुनता है , फिर एक या एक से अधिक खोज चरणों में, तार्किक और भौतिक विविधताओं की खोज के लिए एक बजटीय राशि खर्च करता है, जब तक कि यह एक उचित योजना नहीं मिलती है।
दो मामलों के लिए आपको विभिन्न योजनाओं (विभिन्न अंतिम लागत अनुमानों) के साथ मुख्य कारण यह है कि अलग - अलग शुरुआती बिंदु हैं। एक अलग जगह से शुरू होने पर, अनुकूलन एक अलग जगह (इसके अन्वेषण और कार्यान्वयन पुनरावृत्तियों की सीमित संख्या के बाद) पर समाप्त होता है। मुझे उम्मीद है कि यह यथोचित सहज ज्ञान युक्त है।
मैंने जो शुरुआती बिंदु का उल्लेख किया है, वह कुछ हद तक क्वेरी के शाब्दिक प्रतिनिधित्व पर आधारित है, लेकिन आंतरिक ट्री प्रतिनिधित्व में परिवर्तन किया जाता है क्योंकि यह क्वेरी संकलन के पार्सिंग, बाइंडिंग, सामान्यीकरण और सरलीकरण चरणों से गुजरता है।
महत्वपूर्ण रूप से, सटीक प्रारंभिक बिंदु ऑप्टिमाइज़र द्वारा चयनित प्रारंभिक ज्वाइन ऑर्डर पर बहुत अधिक निर्भर करता है । यह विकल्प आंकड़े लोड होने से पहले किया जाता है, और इससे पहले कि किसी भी कार्डिनैलिटी का अनुमान लगाया गया हो। प्रत्येक तालिका में कुल कार्डिनैलिटी (पंक्तियों की संख्या) हालांकि ज्ञात है, सिस्टम मेटाडेटा से प्राप्त की गई है।
इसलिए प्रारंभिक ज्वाइनिंग ऑर्डर ह्यूरिस्टिक्स पर आधारित है । उदाहरण के लिए, ऑप्टिमाइज़र पेड़ को फिर से लिखने की कोशिश करता है जैसे कि छोटे टेबल बड़े लोगों के साथ जुड़ जाते हैं, और आंतरिक जुड़ाव बाहरी जुड़ने से पहले आते हैं (और क्रॉस जॉन्स)।
गणना किए गए कॉलम की उपस्थिति इस प्रक्रिया में हस्तक्षेप करती है, विशेष रूप से बाहरी पेड़ को जोड़ने के लिए ऑप्टिमाइज़र की क्षमता के साथ सबसे विशेष रूप से क्वेरी ट्री के नीचे मिलती है। ऐसा इसलिए होता है क्योंकि पुनरावर्ती जुड़ने से पहले गणना किए गए स्तंभ को उसकी अंतर्निहित अभिव्यक्ति में विस्तारित किया जाता है, और एक जटिल अभिव्यक्ति में शामिल होने से आगे बढ़ना एक साधारण स्तंभ संदर्भ के अतीत की तुलना में अधिक कठिन होता है।
इसमें शामिल पेड़ काफी बड़े हैं, लेकिन वर्णन करने के लिए, गैर-गणना किए गए स्तंभ प्रारंभिक क्वेरी ट्री के साथ शुरू होता है: (शीर्ष पर दो बाहरी जुड़ावों पर ध्यान दें)
LogOp_Select
LogOp_Apply (x_jtLeftOuter)
LogOp_LeftOuterJoin
LogOp_NAryJoin
LogOp_LeftAntiSemiJoin
LogOp_NAryJoin
LogOp_Get TBL: dbo.table1 (अन्य नाम TBL: a4)
LogOp_Select
LogOp_Get TBL: dbo.table6 (अन्य नाम TBL: a3)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a3] .col18
ScaOp_Const TI (varchar 53256, Var, Trim, ML = 16)
LogOp_Select
LogOp_Get TBL: dbo.table1 (अन्य नाम TBL: a1)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a1] .col2
ScaOp_Const TI (varchar 53256, Var, Trim, ML = 16)
LogOp_Select
LogOp_Get TBL: dbo.table5 (अन्य नाम TBL: a2)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a2] .col2
ScaOp_Const TI (varchar 53256, Var, Trim, ML = 16)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a4] .col2
ScaOp_Identifier QCOL: [a3] .col19
LogOp_Select
LogOp_Get TBL: dbo.table7 (अन्य नाम TBL: a7)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a7] .col22
ScaOp_Const TI (varchar 53256, Var, Trim, ML = 16)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a4] .col2
ScaOp_Identifier QCOL: [a7] .col23
LogOp_Select
LogOp_Get TBL: table1 (अन्य नाम TBL: cdc)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [cdc] .col6
ScaOp_Const TI (स्मॉलिंट, ML = 2) XVAR (स्मॉलिंट, नॉट ओम्ड, वैल्यू = 4)
LogOp_Get TBL: dbo.table5 (अन्य नाम TBL: a5)
LogOp_Get TBL: table2 (अन्य नाम TBL: cdt)
ScaOp_Logical x_lopAnd
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a5] .col2
ScaOp_Identifier QCOL: [cdc] .col2
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a4] .col2
ScaOp_Identifier QCOL: [cdc] .col2
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [cdt] .col1
ScaOp_Identifier QCOL: [cdc] .col1
LogOp_Get TBL: टेबल 3 (अन्य नाम TBL: ahcr)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [ahcr] .col9
ScaOp_Identifier QCOL: [cdt] .col1
गणना किए गए कॉलम क्वेरी का एक ही टुकड़ा है: (ध्यान दें कि बाहरी बहुत नीचे से जुड़ें, विस्तृत गणना किए गए कॉलम की परिभाषा, और (भीतरी) में कुछ अन्य सूक्ष्म अंतर ऑर्डरिंग में शामिल हों)
LogOp_Select
LogOp_Apply (x_jtLeftOuter)
LogOp_NAryJoin
LogOp_LeftAntiSemiJoin
LogOp_NAryJoin
LogOp_Get TBL: dbo.table1 (अन्य नाम TBL: a4)
LogOp_Select
LogOp_Get TBL: dbo.table6 (अन्य नाम TBL: a3)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a3] .col18
ScaOp_Const TI (varchar 53256, Var, Trim, ML = 16)
LogOp_Select
LogOp_Get TBL: dbo.table1 (अन्य नाम TBL: a1
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a1] .col2
ScaOp_Const TI (varchar 53256, Var, Trim, ML = 16)
LogOp_Select
LogOp_Get TBL: dbo.table5 (अन्य नाम TBL: a2)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a2] .col2
ScaOp_Const TI (varchar 53256, Var, Trim, ML = 16)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a4] .col2
ScaOp_Identifier QCOL: [a3] .col19
LogOp_Select
LogOp_Get TBL: dbo.table7 (अन्य नाम TBL: a7)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a7] .col22
ScaOp_Const TI (varchar 53256, Var, Trim, ML = 16)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a4] .col2
ScaOp_Identifier QCOL: [a7] .col23
LogOp_Project
LogOp_LeftOuterJoin
LogOp_Join
LogOp_Select
LogOp_Get TBL: table1 (अन्य नाम TBL: cdc)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [cdc] .col6
ScaOp_Const TI (स्मॉलिंट, ML = 2) XVAR (स्मॉलिंट, नॉट ओम्ड, वैल्यू = 4)
LogOp_Get TBL: table2 (अन्य नाम TBL: cdt)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [cdc] .col1
ScaOp_Identifier QCOL: [cdt] .col1
LogOp_Get TBL: टेबल 3 (अन्य नाम TBL: ahcr)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [ahcr] .col9
ScaOp_Identifier QCOL: [cdt] .col1
AncOp_PrjList
AncOp_PrjEl QCOL: [cdc] .col7
ScaOp_Convert char collate 53256, Null, Trim, ML = 6
ScaOp_IIF varchar 53256, Null, Var, Trim, ML = 6 से टकराते हैं
ScaOp_Comp x_cmpEq
ScaOp_Intrinsic isnumeric
ScaOp_Intrinsic सही
ScaOp_Identifier QCOL: [cdc] .col4
ScaOp_Const TI (int, ML = 4) XVAR (int, स्वामित्व नहीं, मान = 4)
ScaOp_Const TI (int, ML = 4) XVAR (int, स्वामित्व नहीं, मान = 0)
ScaOp_Const TI (varchar 53256, Var, Trim, ML = 1) XVAR (varchar, Owned, Value = Len, Data = (0,))
ScaOp_Intrinsic सबस्ट्रिंग
ScaOp_Const TI (int, ML = 4) XVAR (int, स्वामित्व नहीं, मान = 6)
ScaOp_Const TI (int, ML = 4) XVAR (int, स्वामित्व नहीं, मूल्य = 1)
ScaOp_Identifier QCOL: [cdc] .col4
LogOp_Get TBL: dbo.table5 (अन्य नाम TBL: a5)
ScaOp_Logical x_lopAnd
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a5] .col2
ScaOp_Identifier QCOL: [cdc] .col2
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a4] .col2
ScaOp_Identifier QCOL: [cdc] .col2
आँकड़े लोड किए जाते हैं और प्रारंभिक जुड़ने का क्रम निर्धारित होने के ठीक बाद पेड़ पर एक प्रारंभिक कार्डिनलिटी अनुमान लगाया जाता है। अलग-अलग आदेशों में जुड़ने से इन अनुमानों पर भी असर पड़ता है, और इसलिए बाद में लागत-आधारित अनुकूलन के दौरान एक दस्तक पर प्रभाव पड़ता है।
अंत में इस खंड के लिए, पेड़ के बीच में अटका हुआ एक बाहरी जोड़ होने से लागत-आधारित अनुकूलन के दौरान कुछ और पुन: जुड़ने वाले नियमों से जुड़ने से रोका जा सकता है।
एक योजना गाइड (या, समान रूप से एक USE PLAN
संकेत - आपकी क्वेरी के लिए उदाहरण ) का उपयोग करके खोज की रणनीति को और अधिक लक्ष्य-उन्मुख दृष्टिकोण में बदल जाता है, जो सामान्य आकार और आपूर्ति किए गए टेम्पलेट की विशेषताओं द्वारा निर्देशित होता है। यह बताता है कि क्यों ऑप्टिमाइज़र कंप्यूटेड और नॉन-कंप्यूटेड कॉलम स्कीमा दोनों के खिलाफ एक ही तलाश योजना पा सकता हैtable1
, जब एक योजना गाइड या संकेत का उपयोग किया जाता है।
क्या हम चाहने के लिए कुछ अलग कर सकते हैं
यह वह चीज है जिसके बारे में आपको केवल चिंता करने की जरूरत है, अगर आशावादी को अपने आप में स्वीकार्य प्रदर्शन विशेषताओं के साथ कोई योजना नहीं मिलती है।
सभी सामान्य ट्यूनिंग उपकरण संभावित रूप से लागू होते हैं। उदाहरण के लिए, आप सरल भागों में क्वेरी को तोड़ सकते हैं, उपलब्ध इंडेक्सिंग की समीक्षा और सुधार कर सकते हैं, नए आंकड़े बना सकते हैं ... अपडेट कर सकते हैं ... इत्यादि।
ये सभी चीजें कार्डिनैलिटी के अनुमानों को प्रभावित कर सकती हैं, कोड को ऑप्टिमाइज़र के माध्यम से लिया जाता है, और सूक्ष्म तरीकों से लागत आधारित निर्णयों को प्रभावित करता है।
आप अंततः संकेत (या एक योजना गाइड) का उपयोग करने का सहारा ले सकते हैं, लेकिन यह आमतौर पर आदर्श समाधान नहीं है।
टिप्पणियों से अतिरिक्त प्रश्न
मैं सहमत हूं कि क्वेरी आदि को सरल बनाना सबसे अच्छा है, लेकिन क्या ऑप्टिमाइज़र को ऑप्टिमाइज़ेशन के साथ जारी रखने और उसी परिणाम तक पहुंचने के लिए एक तरीका (ट्रेस ध्वज) है?
नहीं, संपूर्ण खोज करने के लिए कोई ट्रेस ध्वज नहीं है, और आप एक नहीं चाहते हैं। संभावित खोज स्थान विशाल और संकलन समय है जो ब्रह्मांड की आयु से अधिक है, अच्छी तरह से प्राप्त नहीं होगा। इसके अलावा, अनुकूलक हर संभव तार्किक परिवर्तन (कोई भी नहीं करता है) नहीं जानता है।
इसके अलावा, जटिल विस्तार की आवश्यकता क्यों है, क्योंकि स्तंभ कायम है? ऑप्टिमाइज़र इसे विस्तारित करने से क्यों नहीं बच सकता है, इसे एक नियमित कॉलम की तरह व्यवहार करें, और एक ही शुरुआती बिंदु पर पहुंचें?
अतिरिक्त अनुकूलन अवसरों को सक्षम करने के लिए कम्प्यूटेड कॉलम का विस्तार किया जाता है (जैसे विचार हैं)। विस्तार वापस हो सकता है उदाहरण के लिए एक स्थायी स्तंभ या अनुक्रमणिका बाद में प्रक्रिया में, लेकिन प्रारंभिक जुड़ने का क्रम तय होने के बाद ऐसा होता है।