स्कैन किए गए संगणित कॉलम को जारी रखा


9

एक नियमित रूप से कॉलम को एक सुसंगत गणना कॉलम में परिवर्तित करने के कारण यह क्वेरी इंडेक्स सीक करने में सक्षम नहीं है। क्यों?

2016 SP1 CU1 सहित कई SQL सर्वर संस्करणों पर परीक्षण किया गया।

Repros

मुसीबत के साथ है table1, col7

टेबल और क्वेरी मूल का एक आंशिक (और सरलीकृत) संस्करण हैं। मुझे पता है कि क्वेरी को अलग तरीके से फिर से लिखा जा सकता है, और किसी कारण से समस्या से बचें, लेकिन हमें कोड को छूने से बचने की आवश्यकता है, और सवाल यह है कि table1अभी भी खड़ा क्यों नहीं किया जा सकता है।

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

समस्याग्रस्त भाग को स्पष्ट करने के लिए, खराब निष्पादन योजना में यहां प्रासंगिक स्कैन है:

योजना

जवाबों:


12

क्यों आशावादी द्वारा तलाश नहीं की जाती है


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


विवरण

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

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

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

महत्वपूर्ण रूप से, सटीक प्रारंभिक बिंदु ऑप्टिमाइज़र द्वारा चयनित प्रारंभिक ज्वाइन ऑर्डर पर बहुत अधिक निर्भर करता है । यह विकल्प आंकड़े लोड होने से पहले किया जाता है, और इससे पहले कि किसी भी कार्डिनैलिटी का अनुमान लगाया गया हो। प्रत्येक तालिका में कुल कार्डिनैलिटी (पंक्तियों की संख्या) हालांकि ज्ञात है, सिस्टम मेटाडेटा से प्राप्त की गई है।

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

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

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

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 , जब एक योजना गाइड या संकेत का उपयोग किया जाता है।

क्या हम चाहने के लिए कुछ अलग कर सकते हैं

यह वह चीज है जिसके बारे में आपको केवल चिंता करने की जरूरत है, अगर आशावादी को अपने आप में स्वीकार्य प्रदर्शन विशेषताओं के साथ कोई योजना नहीं मिलती है।

सभी सामान्य ट्यूनिंग उपकरण संभावित रूप से लागू होते हैं। उदाहरण के लिए, आप सरल भागों में क्वेरी को तोड़ सकते हैं, उपलब्ध इंडेक्सिंग की समीक्षा और सुधार कर सकते हैं, नए आंकड़े बना सकते हैं ... अपडेट कर सकते हैं ... इत्यादि।

ये सभी चीजें कार्डिनैलिटी के अनुमानों को प्रभावित कर सकती हैं, कोड को ऑप्टिमाइज़र के माध्यम से लिया जाता है, और सूक्ष्म तरीकों से लागत आधारित निर्णयों को प्रभावित करता है।

आप अंततः संकेत (या एक योजना गाइड) का उपयोग करने का सहारा ले सकते हैं, लेकिन यह आमतौर पर आदर्श समाधान नहीं है।


टिप्पणियों से अतिरिक्त प्रश्न

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

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

इसके अलावा, जटिल विस्तार की आवश्यकता क्यों है, क्योंकि स्तंभ कायम है? ऑप्टिमाइज़र इसे विस्तारित करने से क्यों नहीं बच सकता है, इसे एक नियमित कॉलम की तरह व्यवहार करें, और एक ही शुरुआती बिंदु पर पहुंचें?

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

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