अस्थायी अनुमानों को कम करने के लिए पंक्ति अनुमानों को कैसे बेहतर बनाया जा सकता है


11

मुझे लगता है कि जब वहाँ अस्थायी घटनाओं (धीमी क्वेरी के कारण) है कि अक्सर पंक्ति अनुमान एक विशेष रूप से शामिल होने के लिए बंद हैं। मैंने देखा है कि स्पिल की घटनाएं मर्ज और हैश जॉइन के साथ होती हैं और वे अक्सर रनटाइम 3x को बढ़ाकर 10x कर देते हैं। यह सवाल चिंता का विषय है कि इस अनुमान के तहत पंक्ति अनुमानों को कैसे बेहतर बनाया जाए कि इससे स्पिल घटनाओं की संभावना कम हो जाए।

पंक्तियों की वास्तविक संख्या 40k।

इस क्वेरी के लिए, योजना खराब पंक्ति अनुमान (11.3 पंक्तियाँ) दिखाती है:

select Value
  from Oav.ValueArray
 where ObjectId = (select convert(bigint, Value) NodeId
                     from Oav.ValueArray
                    where PropertyId = 3331  
                      and ObjectId = 3540233
                      and Sequence = 2)
   and PropertyId = 2840
option (recompile);

इस प्रश्न के लिए, योजना अच्छी पंक्ति अनुमान (56k पंक्तियाँ) दिखाती है:

declare @a bigint = (select convert(bigint, Value) NodeId
                       from Oav.ValueArray
                      where PropertyId = 3331
                        and ObjectId = 3540233
                        and Sequence = 2);

select Value
  from Oav.ValueArray
 where ObjectId = @a               
   and PropertyId = 2840
option (recompile);

क्या पहले मामले के लिए पंक्ति अनुमानों को बेहतर बनाने के लिए आंकड़े या संकेत जोड़े जा सकते हैं? मैंने विशेष फ़िल्टर मानों (संपत्ति = 2840) के साथ आँकड़े जोड़ने की कोशिश की, लेकिन या तो संयोजन सही नहीं हो सका या शायद इसे अनदेखा किया जा रहा है क्योंकि ObjectId संकलन समय पर अज्ञात है और यह सभी ObjectIds पर औसत का चयन कर सकता है।

क्या कोई ऐसा मोड है जहां यह पहले जांच क्वेरी करता है और फिर पंक्ति अनुमानों का निर्धारण करने के लिए इसका उपयोग करता है या इसे नेत्रहीन उड़ना चाहिए?

इस विशेष संपत्ति में कुछ वस्तुओं पर कई मूल्य (40k) हैं और विशाल बहुमत पर शून्य है। मुझे एक संकेत से खुशी होगी जहां एक दिए गए जॉइन के लिए पंक्तियों की अधिकतम अपेक्षित संख्या निर्दिष्ट की जा सकती है। यह आम तौर पर परेशान करने वाली समस्या है क्योंकि कुछ मापदंडों को गतिशील रूप से जुड़ने के हिस्से के रूप में निर्धारित किया जा सकता है या एक दृश्य के भीतर रखा जाएगा (चर के लिए कोई समर्थन नहीं)।

क्या कोई पैरामीटर हैं जो टेम्पर्ड (जैसे प्रति मिनट मेमोरी प्रति मिनट) फैल की संभावना को कम करने के लिए समायोजित किया जा सकता है? रोबस्ट प्लान का अनुमान पर कोई प्रभाव नहीं पड़ा।

2013.11.06 को संपादित करें : टिप्पणियों का जवाब और अतिरिक्त जानकारी:

यहाँ क्वेरी प्लान इमेज हैं। चेतावनी कार्डिनलिटी के बारे में है / कन्वर्ट के साथ विधेय चाहते हैं ():

यहाँ छवि विवरण दर्ज करें यहाँ छवि विवरण दर्ज करें

@Aaron बर्ट्रैंड की टिप्पणी के अनुसार, मैंने परीक्षण के रूप में कन्वर्ट () को बदलने की कोशिश की:

create table Oav.SeekObject (
       LookupId bigint not null primary key,
       ObjectId bigint not null
);

insert into Oav.SeekObject (
   LookupId, ObjectId
) VALUES (
   1, 3540233
) 

select Value
  from Oav.ValueArray
 where ObjectId = (select ObjectId 
                     from Oav.SeekObject 
                    where LookupId = 1)
   and PropertyId = 2840
option (recompile);

यहाँ छवि विवरण दर्ज करें

ब्याज के एक विषम लेकिन सफल बिंदु के रूप में, यह भी शॉर्ट सर्किट देखने की अनुमति देता है:

select Value
  from Oav.ValueArray
 where ObjectId = (select ObjectId 
                     from Oav.ValueArray
                    where PropertyId = 2840
                      and ObjectId = 3540233
                      and Sequence = 2)
   and PropertyId = 2840
option (recompile);

यहाँ छवि विवरण दर्ज करें

इन दोनों की सूची एक उचित कुंजी लुकअप है लेकिन केवल पहले वाले ObjectId के "आउटपुट" को सूचीबद्ध करते हैं। मुझे लगता है कि यह दर्शाता है कि दूसरा वास्तव में कम परिचालित है?

क्या कोई यह सत्यापित कर सकता है कि क्या एकल-पंक्ति जांच कभी पंक्ति अनुमानों की सहायता से की जाती है? यह केवल हिस्टोग्राम अनुमानों के लिए अनुकूलन को सीमित करने के लिए गलत लगता है जब एक एकल-पंक्ति पीके लुकअप हिस्टोग्राम में लुकअप की सटीकता में सुधार कर सकता है (विशेषकर यदि स्पिल क्षमता या इतिहास है)। जब एक वास्तविक क्वेरी में इनमें से 10 उप-जोड़ होते हैं, तो आदर्श रूप से वे समानांतर में हो रहे होंगे।

एक साइड नोट, चूंकि sql_variant अपने आधार प्रकार (SQL_VARIANT_PROPERTY = BaseType) को फ़ील्ड के भीतर संग्रहीत करता है, मैं एक कन्वर्ट () को लगभग इतना महंगा होने की उम्मीद करूंगा जब तक कि यह "सीधे" परिवर्तनीय (जैसे दशमलव के लिए स्ट्रिंग नहीं है) int या हो सकता है int to bigint)। चूँकि यह संकलन समय पर ज्ञात नहीं है, लेकिन उपयोगकर्ता द्वारा जाना जा सकता है, शायद sql_variants के लिए एक "AssumeType (प्रकार, ...)" फ़ंक्शन उन्हें अधिक पारदर्शी तरीके से व्यवहार करने की अनुमति देगा।


1
पहला अनुमान यह होगा कि बिगिन्ट में कनवर्ट आपके अनुमानों को बंद कर रहा है (क्वेरी प्लान में SQL Server 2012 में इस बारे में चेतावनी होगी) लेकिन दूसरी ओर, आपकी उप-क्वेरी 0 या 1 पंक्तियों के अलावा कभी भी वापस नहीं लौट सकती है। एक सफल क्वेरी के लिए। यह आपके लिए क्वेरी योजनाओं को देखना दिलचस्प होगा। शायद XML संस्करण के लिंक के रूप में।
मिकेल एरिकसन

2
उपकुंजी इनलाइन होने से आपको क्या हासिल होता है? मेरा सुझाव है कि इसे अलग-अलग खींचना समग्र रूप से स्पष्ट है, और चूंकि यह बेहतर अनुमान लगाता है, इसलिए केवल उस पद्धति का उपयोग क्यों न करें?
हारून बर्ट्रेंड

2
SQL सर्वर का क्या संस्करण? क्या आप टेबल के लिए टेबल और इंडेक्स डीडीएल और आँकड़े प्रदान कर सकते हैं (एकल और बहु-स्तंभ) ताकि हम समस्या का विवरण देख सकें? declare @a bigint = आपके द्वारा किए गए क्वेरी को विभाजित करने से मुझे एक प्राकृतिक समाधान लगता है, यह अस्वीकार्य क्यों है?
पॉल व्हाइट 9

2
मुझे लगता है कि आपका डिज़ाइन एक (बहुत ही सरल) ईएवी डिज़ाइन है जो आपको CONVERT()कॉलम में उपयोग करने के लिए मजबूर करता है और फिर उनसे जुड़ता है। यह निश्चित रूप से कुशल नहीं है ज्यादातर मामले हैं। इस विशेष में, इसे परिवर्तित करने के लिए केवल एक ही मूल्य है ताकि यह संभवत: एक मुद्दा न हो लेकिन आपके पास मेज पर क्या अनुक्रमित हैं? ईएवी डिज़ाइन आमतौर पर केवल उचित अनुक्रमण के साथ अच्छा प्रदर्शन करते हैं (जिसका अर्थ है आमतौर पर संकीर्ण तालिकाओं में बहुत सारे अनुक्रमित)।
ypercube y

@ पाओल व्हाइट, जहां तक ​​बंटवारा है ... यह इस मामले के समाधान के रूप में ठीक है। लेकिन अधिक सामान्य / जटिल के लिए मैं ज्यादातर समानांतर और पठनीयता नहीं छोड़ना चाहता। कहो कि मेरे पास इनमें से 10 सब क्वेरीज़ (कुछ अधिक जटिल होने के कारण) एक क्वेरी के भीतर हैं लेकिन बाकी क्वेरी शुरू होने से पहले केवल 5 को "परिपक्व" होने की आवश्यकता है - यह पता लगाने से बचना चाहेंगे कि कौन से 5 हैं।
क्रोकेक

जवाबों:


7

मैं फैल, टेम्पर्ड या संकेत के बारे में कोई टिप्पणी नहीं करूंगा क्योंकि क्वेरी को इस बात पर विचार करने के लिए बहुत सरल लगता है। मुझे लगता है कि SQL-Server के ऑप्टिमाइज़र अपना काम काफी अच्छा करेंगे, अगर क्वेरी के लिए अनुक्रमणिका अनुकूल हैं।

और दो प्रश्नों में आपका विभाजन अच्छा है क्योंकि यह दिखाता है कि अनुक्रमणिका क्या उपयोगी होगी। पहला भाग:

(select convert(bigint, Value) NodeId
 from Oav.ValueArray
 where PropertyId = 3331  
   and ObjectId = 3540233
   and Sequence = 2)

(PropertyId, ObjectId, Sequence)सहित एक सूचकांक की जरूरत है Value। मैं इसे UNIQUEसुरक्षित बनाता हूँ । यदि रनटाइम के दौरान एक से अधिक पंक्तियों को वापस कर दिया गया, तो क्वेरी किसी भी तरह से त्रुटि फेंक देगी, इसलिए यह पहले से सुनिश्चित करना अच्छा है कि ऐसा नहीं होगा, अद्वितीय सूचकांक के साथ:

CREATE UNIQUE INDEX
    PropertyId_ObjectId_Sequence_UQ
  ON Oav.ValueArray
    (PropertyId, ObjectId, Sequence) INCLUDE (Value) ;

क्वेरी का दूसरा भाग:

select Value
  from Oav.ValueArray
 where ObjectId = @a               
   and PropertyId = 2840

(PropertyId, ObjectId)सहित एक सूचकांक की जरूरत है Value:

CREATE INDEX
    PropertyId_ObjectId_IX
  ON Oav.ValueArray
    (PropertyId, ObjectId) INCLUDE (Value) ;

यदि दक्षता में सुधार नहीं हुआ है या इन इंडेक्सों का उपयोग नहीं किया गया है या अभी भी पंक्ति अनुमानों में अंतर दिखाई दे रहे हैं, तो इस क्वेरी में आगे देखने की आवश्यकता होगी।

उस स्थिति में, रूपांतरण (ईएवी डिज़ाइन से और एक ही कॉलम में विभिन्न डेटाटाइप्स के भंडारण के लिए आवश्यक) एक संभावित कारण है और आपके विभाजन के समाधान (@AAron बर्ट्रेंड और @Paul व्हाइट टिप्पणी के रूप में) दो भागों में प्रश्न स्वाभाविक लगता है। और जाने का रास्ता। उनके संबंधित स्तंभों में अलग-अलग डेटाटाइप के लिए एक नया स्वरूप एक और हो सकता है।


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

5

आंकड़ों में सुधार पर स्पष्ट प्रश्न के आंशिक उत्तर के रूप में ...

ध्यान दें कि अलग से मामले के लिए भी पंक्ति का अनुमान अभी भी 10X (4k बनाम अपेक्षित 40k) से दूर है।

आँकड़ों के हिस्टोग्राम की संभावना उस संपत्ति के लिए बहुत पतली थी, क्योंकि यह एक लंबी (ऊर्ध्वाधर), 3.5M पंक्तियों की तालिका है और यह विशेष गुण अत्यंत विरल है।

विरल संपत्ति के लिए अतिरिक्त आँकड़े (IX आँकड़ों के साथ कुछ हद तक बेमानी) बनाएँ:

create statistics [STAT_ValueArray_ObjPropValue_WhereProp2840] ON [Oav].[ValueArray](ObjectId, PropertyId, Value)
where PropertyId = 2840

मूलभूत:

यहाँ छवि विवरण दर्ज करें यहाँ छवि विवरण दर्ज करें

कन्वर्ट () हटाया (उचित) के साथ:

यहाँ छवि विवरण दर्ज करें

कन्वर्ट () हटाए गए (शॉर्ट-सर्किट) के साथ:

यहाँ छवि विवरण दर्ज करें

अभी भी ~ 2X संभावना से दूर है क्योंकि> 99.9% वस्तुओं के पास संपत्ति 2840 उन पर परिभाषित नहीं है। वास्तव में सिर्फ इस परीक्षण के मामले में संपत्ति 3.5 एम पंक्ति तालिका के 200k अलग-अलग वस्तुओं में से 1 पर मौजूद है। यह आश्चर्यजनक है कि यह वास्तव में बंद हो गया। फ़िल्टर को कम ObjectIds में समायोजित करना,

create statistics [STAT_ValueArray_ObjPropValue_WhereProp2840] ON [Oav].[ValueArray](ObjectId, PropertyId, Value)
where PropertyId = 2840 and ObjectId >= 3540000 and ObjectId < 3541000

create statistics [STAT_ValueArray_ObjPropValue_WhereProp2840] ON [Oav].[ValueArray](ObjectId, PropertyId, Value)
where PropertyId = 2840 and ObjectId = 3540233;

हम्म, कोई बदलाव नहीं ... आंकड़ों के अंत के लिए "पूर्ण स्कैन के साथ" जोड़ा गया है कि पिछले दो काम नहीं किया और हो सकता है हाँ:

create statistics [STAT_ValueArray_ObjPropValue_WhereProp2840] ON [Oav].[ValueArray](ObjectId, PropertyId, Value)
where PropertyId = 2840 with full scan;

यहाँ छवि विवरण दर्ज करें

वाह। मोटे तौर पर IX को कवर करने के साथ एक उच्च ऊर्ध्वाधर तालिका में, अतिरिक्त फ़िल्टर किए गए आंकड़े जोड़ना एक महान सुधार प्रतीत होता है (विशेष रूप से विरल लेकिन अत्यधिक भिन्न कुंजी संयोजनों के लिए)।


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