मुझे यह समझने में कठिन समय हो रहा है कि एसक्यूएल सर्वर एक अनुमान के साथ क्यों आएगा जो आंकड़ों के साथ असंगत साबित हो सकता है।
संगति
स्थिरता की कोई सामान्य गारंटी नहीं है। अनुमान विभिन्न (लेकिन तार्किक रूप से समतुल्य) अलग-अलग समय पर अलग-अलग सांख्यिकीय विधियों का उपयोग करके गणना की जा सकती है।
तर्क के साथ कुछ भी गलत नहीं है जो कहता है कि एक समान उत्पाद का उत्पादन करने के लिए उन दो समान उपप्रकारों में शामिल होना चाहिए, लेकिन यह कहने के लिए समान रूप से कुछ भी नहीं है कि तर्क का विकल्प किसी भी अन्य की तुलना में अधिक ध्वनि है।
प्रारंभिक अनुमान
आपके विशिष्ट मामले में, जुड़ने के लिए प्रारंभिक कार्डिनलिटी अनुमान दो समान उपप्रकारों पर नहीं किया जाता है । उस समय पेड़ का आकार होता है:
LogOp_Join
LogOp_GbAgg
LogOp_LeftOuterJoin
LogOp_Get TBL: ar
LogOp_Select
LogOp_Get TBL: tcr
ScaOp_Comp x_cmpEq
ScaOp_Identifier [tcr] .rId
ScaOp_Const मान = 508
ScaOp_Logical x_lopAnd
ScaOp_Comp x_cmpEq
ScaOp_Identifier [ar] .fId
ScaOp_Identifier [tcr] .fId
ScaOp_Comp x_cmpEq
ScaOp_Identifier [ar] .bId
ScaOp_Identifier [tcr] .bId
AncOp_PrjList
AncOp_PrjEl Expr1003
ScaOp_AggFunc stopMax
ScaOp_Convert int
ScaOp_Identifier [tcr] .isS
LogOp_Select
LogOp_GbAgg
LogOp_LeftOuterJoin
LogOp_Get TBL: ar
LogOp_Select
LogOp_Get TBL: tcr
ScaOp_Comp x_cmpEq
ScaOp_Identifier [tcr] .rId
ScaOp_Const मान = 508
ScaOp_Logical x_lopAnd
ScaOp_Comp x_cmpEq
ScaOp_Identifier [ar] .fId
ScaOp_Identifier [tcr] .fId
ScaOp_Comp x_cmpEq
ScaOp_Identifier [ar] .bId
ScaOp_Identifier [tcr] .bId
AncOp_PrjList
AncOp_PrjEl Expr1006
ScaOp_AggFunc रोकें
ScaOp_Convert int
ScaOp_Identifier [ar] .isT
AncOp_PrjEl Expr1007
ScaOp_AggFunc stopMax
ScaOp_Convert int
ScaOp_Identifier [tcr] .isS
ScaOp_Comp x_cmpEq
ScaOp_Identifier Expr1006
ScaOp_Const मान = 1
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [ar] .fId
ScaOp_Identifier QCOL: [ar] .fId
पहले ज्वाइन इनपुट में एक अनप्रोजेक्ट एग्रीगेट सरलीकृत किया गया है, और दूसरा ज्वाइन इनपुट उसके t.isT = 1
नीचे प्रेडिकेटेट है, जहां t.isT
है MIN(CONVERT(INT, ar.isT))
। इसके बावजूद, isT
विधेय के लिए चयनात्मकता CSelCalcColumnInInterval
एक हिस्टोग्राम पर उपयोग करने में सक्षम है :
CSelCalcColumnInInterval
कॉलम: COL: Expr1006
कॉलम QCOL के लिए लोड किया गया हिस्टोग्राम: [३] आईडी ३ के साथ आँकड़ों से
चयनात्मकता: 4.85248e-005
आँकड़े संग्रह उत्पन्न:
CStCollFilter (ID = 11, CARD = 1)
CStCollGroupBy (आईडी = 10, कार्ड = 20608)
CStCollOuterJoin (ID = 9, CARD = 20608 x_jtLeftOuter)
CStCollBaseTable (ID = 3, CARD = 20608 TBL: ar)
CStCollFilter (ID = 8, CARD = 1)
CStCollBaseTable (ID = 4, CARD = 28 TBL: tcr)
(सही) उम्मीद इस विधेय द्वारा 20,608 पंक्तियों को 1 पंक्ति तक कम करने के लिए है।
अनुमान में शामिल हों
अब सवाल यह है कि कैसे दूसरे जॉइन इनपुट से 20,608 पंक्तियाँ इस एक पंक्ति के साथ मेल खाएँगी:
LogOp_Join
CStCollGroupBy (ID = 7, CARD = 20608)
CStCollOuterJoin (ID = 6, CARD = 20608 x_jtLeftOuter)
...
CStCollFilter (ID = 11, CARD = 1)
CStCollGroupBy (आईडी = 10, कार्ड = 20608)
...
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [ar] .fId
ScaOp_Identifier QCOL: [ar] .fId
सामान्य रूप से जुड़ने का अनुमान लगाने के कई अलग-अलग तरीके हैं। हम कर सकते हैं, उदाहरण के लिए:
- प्रत्येक उपप्रकार में प्रत्येक योजना ऑपरेटर पर नए हिस्टोग्राम्स को सम्मिलित करें, उन्हें शामिल होने (आवश्यक रूप से चरण मानों को प्रक्षेपित) पर संरेखित करें, और देखें कि वे कैसे मेल खाते हैं; या
- हिस्टोग्राम्स का एक सरल 'मोटे' संरेखण करें (न्यूनतम और अधिकतम मूल्यों का उपयोग करते हुए, चरण-दर-चरण नहीं); या
- अकेले शामिल होने वाले स्तंभों के लिए अलग-अलग चयन की गणना करें (आधार तालिका से, और बिना किसी फ़िल्टरिंग के), फिर गैर-सम्मिलित विधेयकों (ओं) की चयनात्मकता प्रभाव में जोड़ें।
- ...
उपयोग में कार्डिनैलिटी अनुमानक, और कुछ अनुमानों के आधार पर, उनमें से किसी (या भिन्नता) का उपयोग किया जा सकता है। अधिक के लिए Microsoft व्हाइट पेपर SQL सर्वर 2014 कार्डिनैलिटी एस्टीमेटर के साथ अपनी क्वेरी योजनाओं का अनुकूलन देखें ।
बग?
अब, जैसा कि प्रश्न में कहा गया है, इस मामले में 'सरल' सिंगल-कॉलम जॉइन (ऑन fId
) CSelCalcExpressionComparedToExpression
कैलकुलेटर का उपयोग करता है :
गणना के लिए योजना:
CSelCalcExpressionComparedToExpression [ar] .fId x_cmpE [[] .fId
कॉलम QCOL के लिए लोड किया गया हिस्टोग्राम: [ar] .b 2 आईडी वाले आंकड़ों से
कॉलम QCOL के लिए लोड किए गए हिस्टोग्राम: आईडी 1 के साथ आँकड़ों से .fId
चयनात्मकता: 0
यह गणना मानती है कि 1 फ़िल्टर्ड पंक्ति के साथ 20,608 पंक्तियों में शामिल होने पर एक शून्य चयनात्मकता होगी: कोई पंक्तियाँ मेल नहीं खाएंगी (अंतिम योजनाओं में एक पंक्ति के रूप में रिपोर्ट की गई)। क्या यह गलत है? हाँ, शायद यहाँ नए CE में एक बग है। कोई यह तर्क दे सकता है कि 1 पंक्ति सभी पंक्तियों या किसी से मेल नहीं खाएगी, इसलिए परिणाम उचित हो सकता है, लेकिन अन्यथा विश्वास करने का कारण है।
विवरण वास्तव में मुश्किल हैं, लेकिन फ़िल्टर fId
की चयनात्मकता द्वारा संशोधित अनफ़िल्टर्ड हिस्टोग्राम्स के आधार पर अनुमान की अपेक्षा , 20608 * 20608 * 4.85248e-005 = 20608
पंक्तियों को देना बहुत ही उचित है।
इस गणना के बाद कैलकुलेटर का उपयोग कर का मतलब होगा CSelCalcSimpleJoinWithDistinctCounts
की बजाय CSelCalcExpressionComparedToExpression
। ऐसा करने के लिए कोई प्रलेखित तरीका नहीं है, लेकिन यदि आप उत्सुक हैं, तो आप अनअस्पोज़ेड ट्रेस ध्वज 9479 को सक्षम कर सकते हैं:
नोट अंतिम जुड़ाव दो एकल-पंक्ति इनपुट से 20,608 पंक्तियों का उत्पादन करता है, लेकिन यह एक आश्चर्य नहीं होना चाहिए। यह TF 9481 के तहत मूल CE द्वारा निर्मित एक ही योजना है।
मैंने उल्लेख किया कि विवरण मुश्किल (और समय लेने वाली जांच करने के लिए) हैं, लेकिन जहां तक मैं बता सकता हूं, समस्या का मूल कारण विधेय से संबंधित है rId = 508
, एक शून्य चयनात्मकता के साथ। यह शून्य अनुमान सामान्य तरीके से एक पंक्ति में उठाया जाता है, जो उस प्रश्न में शामिल होने पर शून्य चयनात्मकता अनुमान में योगदान करने के लिए प्रकट होता है जब यह इनपुट ट्री में कम विधेयकों के लिए खाता है (इसलिए लोडिंग आँकड़े bId
)।
बाहरी जोड़ को एक शून्य-पंक्ति इनर-साइड अनुमान (एक पंक्ति को बढ़ाने के बजाय) रखने के लिए अनुमति देना (इसलिए सभी बाहरी पंक्तियाँ अर्हता प्राप्त करती हैं) या तो कैलकुलेटर के साथ एक 'बग-मुक्त' सम्मिलित अनुमान देती हैं। यदि आप इसे तलाशने में रुचि रखते हैं, तो अविभाजित ट्रेस ध्वज 9473 (अकेला) है:
CSelCalcExpressionComparedToExpression
साथ कार्डिनैलिटी अनुमान के व्यवहार को भी एक अन्य अनिर्दिष्ट रूपांतर झंडे (9494) के साथ `` bId 'के लिए खाता नहीं होने के लिए संशोधित किया जा सकता है। मैं इन सभी का उल्लेख करता हूं क्योंकि मुझे पता है कि आपको ऐसी चीजों में रुचि है; इसलिए नहीं कि वे एक समाधान प्रस्तुत करते हैं। जब तक आप Microsoft को समस्या की रिपोर्ट करते हैं, और वे इसे संबोधित करते हैं (या नहीं), क्वेरी को अलग तरीके से व्यक्त करना संभवतः आगे बढ़ने का सबसे अच्छा तरीका है। भले ही व्यवहार जानबूझकर हो या न हो, उन्हें प्रतिगमन के बारे में सुनने के लिए दिलचस्पी होनी चाहिए।
अंत में, प्रजनन स्क्रिप्ट में उल्लिखित एक और बात को साफ करने के लिए: प्रश्न योजना में फ़िल्टर की अंतिम स्थिति लागत-आधारित अन्वेषण का परिणाम है GbAggAfterJoinSel
जो कुल मिलाकर और फ़िल्टर को ज्वाइन से ऊपर ले जाता है, क्योंकि जॉइन आउटपुट में इतनी छोटी है पंक्तियों की संख्या। फ़िल्टर शुरू में नीचे की ओर था, जैसा कि आपने अपेक्षा की थी।