XML पाठकों के साथ योजनाओं का अनुकूलन


34

डिफ़ॉल्ट विस्तारित ईवेंट सत्र से गतिरोध घटनाओं को खींचने के लिए क्वेरी को यहां से निष्पादित करना

SELECT CAST (
    REPLACE (
        REPLACE (
            XEventData.XEvent.value ('(data/value)[1]', 'varchar(max)'),
            '<victim-list>', '<deadlock><victim-list>'),
        '<process-list>', '</victim-list><process-list>')
    AS XML) AS DeadlockGraph
FROM (SELECT CAST (target_data AS XML) AS TargetData
    FROM sys.dm_xe_session_targets st
    JOIN sys.dm_xe_sessions s ON s.address = st.event_session_address
    WHERE [name] = 'system_health') AS Data
CROSS APPLY TargetData.nodes ('//RingBufferTarget/event') AS XEventData (XEvent)
    WHERE XEventData.XEvent.value('@name', 'varchar(4000)') = 'xml_deadlock_report';

मेरी मशीन पर पूरा होने में लगभग 20 मिनट लगते हैं। बताए गए आंकड़े हैं

Table 'Worktable'. Scan count 0, logical reads 68121, physical reads 0, read-ahead reads 0, 
         lob logical reads 25674576, lob physical reads 0, lob read-ahead reads 4332386.

 SQL Server Execution Times:
   CPU time = 1241269 ms,  elapsed time = 1244082 ms.

स्लो प्लान एक्सएमएल

समानांतर

यदि मैं WHEREक्लॉज को हटाता हूं तो यह एक दूसरी रिटर्निंग 3,782 पंक्तियों से कम में पूरा होता है।

इसी तरह अगर मैं OPTION (MAXDOP 1)मूल क्वेरी में जोड़ता हूं जो चीजों को गति देता है तो अब आँकड़े बहुत कम लोब पढ़ता है।

Table 'Worktable'. Scan count 0, logical reads 15, physical reads 0, read-ahead reads 0,
                lob logical reads 6767, lob physical reads 0, lob read-ahead reads 6076.

 SQL Server Execution Times:
   CPU time = 639 ms,  elapsed time = 693 ms.

तेज़ योजना एक्सएमएल

धारावाहिक

तो मेरा सवाल है

क्या कोई समझा सकता है कि क्या चल रहा है? मूल योजना इतनी भयावह क्यों है और समस्या से बचने का कोई विश्वसनीय तरीका है?

इसके अलावा:

मैंने यह भी पाया है कि INNER HASH JOINचीजों को कुछ हद तक सुधारने के लिए क्वेरी को बदलना (लेकिन इसमें अभी भी> 3 मिनट लगते हैं) क्योंकि DMV के परिणाम इतने छोटे हैं कि मुझे संदेह है कि ज्वाइन प्रकार स्वयं ही जिम्मेदार है और मान लें कि कुछ और बदल गया है। उसके लिए आँकड़े

Table 'Worktable'. Scan count 0, logical reads 30294, physical reads 0, read-ahead reads 0, 
          lob logical reads 10741863, lob physical reads 0, lob read-ahead reads 4361042.

 SQL Server Execution Times:
   CPU time = 200914 ms,  elapsed time = 203614 ms.

(और)

विस्तारित घटनाओं को भरने के बाद रिंग बफर ( 4,880,045 बाइट्स DATALENGTHमें से XMLथा और इसमें 1,448 इवेंट थे।) और MAXDOPसंकेत के बिना मूल क्वेरी के कट डाउन संस्करण का परीक्षण करना ।

SELECT COUNT(*)
FROM   (SELECT CAST (target_data AS XML) AS TargetData
        FROM   sys.dm_xe_session_targets st
               JOIN sys.dm_xe_sessions s
                 ON s.address = st.event_session_address
        WHERE  [name] = 'system_health') AS Data
       CROSS APPLY TargetData.nodes ('//RingBufferTarget/event') AS XEventData (XEvent)
WHERE  XEventData.XEvent.value('@name', 'varchar(4000)') = 'xml_deadlock_report'

SELECT*
FROM   sys.dm_db_task_space_usage
WHERE  session_id = @@SPID 

निम्नलिखित परिणाम दिए

+-------------------------------------+------+----------+
|                                     | Fast |   Slow   |
+-------------------------------------+------+----------+
| internal_objects_alloc_page_count   |  616 |  1761272 |
| internal_objects_dealloc_page_count |  616 |  1761272 |
| elapsed time (ms)                   |  428 |   398481 |
| lob logical reads                   | 8390 | 12784196 |
+-------------------------------------+------+----------+

तेजी से दिखाई देने वाले 616पृष्ठों के आवंटन और डील-डौल के साथ टेम्पर्ड आवंटन में स्पष्ट अंतर है। यह उसी तरह के पृष्ठों का उपयोग होता है जब XML को एक चर में भी रखा जाता है।

धीमी योजना के लिए ये पृष्ठ आवंटन संख्या लाखों में हैं। मतदान dm_db_task_space_usageचल रहा है जबकि क्वेरी से पता चलता है कि यह tempdbकिसी भी समय आवंटित किए गए 1,800 और 3,000 पृष्ठों के बीच कहीं भी लगातार पृष्ठों का आवंटन और डीलिंग कर रहा है ।


आप WHEREखंड को XQuery अभिव्यक्ति में स्थानांतरित कर सकते हैं ; तर्क को तेजी से जाने के लिए इसे हटाया नहीं जाना चाहिए TargetData.nodes ('RingBufferTarget[1]/event[@name = "xml_deadlock_report"]'):। उस व्यक्ति ने कहा, मुझे नहीं पता कि आपने जो सवाल किया है, उसका जवाब देने के लिए एक्सएमएल इंटर्नल को अच्छी तरह से पता है।
जॉन सीगल

मार्टिन के लिए @SQLPoolBoy को पेजिंग करते हुए ... उन्होंने यहां टिप्पणियों के माध्यम से जाने का सुझाव दिया जहां उनके पास अधिक कुशल सुझाव हैं (वे ऊपर दिए गए कोड के लिए स्रोत लेख पर आधारित हैं )।
हारून बर्ट्रेंड

जवाबों:


36

निष्पादन अंतर का कारण निष्पादन इंजन में स्केलर अभिव्यक्तियों को कैसे नियंत्रित किया जाता है। इस मामले में, ब्याज की अभिव्यक्ति है:

[Expr1000] = CONVERT(xml,DM_XE_SESSION_TARGETS.[target_data],0)

यह अभिव्यक्ति लेबल एक गणना स्केलर ऑपरेटर (धारावाहिक योजना में नोड 11, समानांतर योजना में नोड 13) द्वारा परिभाषित किया गया है। गणना स्केलर ऑपरेटर अन्य ऑपरेटरों (SQL सर्वर 2005 आगे) से भिन्न होते हैं, जो अभिव्यक्ति (ओं) को परिभाषित करते हैं वे आवश्यक रूप से मूल्यांकन नहीं करते हैं कि वे दृश्य निष्पादन योजना में दिखाई देते हैं; मूल्यांकन तब तक स्थगित किया जा सकता है जब तक कि संगणना के परिणाम के लिए बाद के ऑपरेटर की आवश्यकता न हो।

वर्तमान क्वेरी में, target_dataस्ट्रिंग आमतौर पर बड़ी होती है, जिससे स्ट्रिंग से XMLमहंगी में रूपांतरण होता है । धीमी योजनाओं में, XMLरूपांतरण के लिए स्ट्रिंग को हर बार बाद में ऑपरेटर द्वारा प्रदर्शन किया जाता है जिसके परिणाम की आवश्यकता होती Expr1000है।

रिबाइंडिंग एक नेस्टेड लूप के अंदरूनी हिस्से में होती है जब एक सहसंबंधित पैरामीटर (बाहरी संदर्भ) बदलता है। Expr1000इस निष्पादन योजना में शामिल अधिकांश नेस्टेड छोरों के लिए एक बाहरी संदर्भ है। कई एक्सएमएल रीडर्स, स्ट्रीम एग्रीगेट्स और एक स्टार्ट-अप फ़िल्टर द्वारा कई बार अभिव्यक्ति को संदर्भित किया जाता है। के आकार के आधार पर XML, स्ट्रिंग को XMLलाखों में आसानी से संख्या में परिवर्तित किया जा सकता है।

नीचे दिए गए कॉल स्टैक्स target_dataस्ट्रिंग के उदाहरण दिखाते हैं XML( ConvertStringToXMLForES- जहां ES अभिव्यक्ति की सेवा है ):

स्टार्ट-अप फ़िल्टर

स्टार्ट-अप फ़िल्टर कॉल स्टैक

XML रीडर (टीवीएफ स्ट्रीम आंतरिक रूप से)

TVF स्ट्रीम कॉल स्टैक

स्ट्रीम एग्रीगेट

स्ट्रीम एग्रीगेट कॉल स्टैक

XMLप्रत्येक बार स्ट्रिंग को परिवर्तित करने से इनमें से कोई भी ऑपरेटर रिबंड नेस्टेड लूप प्लान के साथ देखे गए प्रदर्शन अंतर को स्पष्ट करता है। यह इस बात की परवाह किए बिना है कि समानता का उपयोग किया जाता है या नहीं। यह सिर्फ इतना होता है कि जब MAXDOP 1संकेत निर्दिष्ट किया जाता है , तो आशावादी एक हैश ज्वाइन करता है। यदि MAXDOP 1, LOOP JOINनिर्दिष्ट किया गया है, तो प्रदर्शन केवल डिफ़ॉल्ट समानांतर योजना (जहां ऑप्टिमाइज़र नेस्टेड लूप चुनते हैं) के साथ खराब है।

हैश जॉइन के साथ कितना प्रदर्शन बढ़ता है यह इस बात पर निर्भर करता है कि Expr1000ऑपरेटर के निर्माण या जांच पक्ष पर क्या दिखाई देता है। निम्नलिखित प्रश्न जांच पक्ष पर अभिव्यक्ति का पता लगाता है:

SELECT CAST (
    REPLACE (
        REPLACE (
            XEventData.XEvent.value ('(data/value)[1]', 'varchar(max)'),
            '<victim-list>', '<deadlock><victim-list>'),
        '<process-list>', '</victim-list><process-list>')
    AS XML) AS DeadlockGraph
FROM (SELECT CAST (target_data AS XML) AS TargetData
    FROM sys.dm_xe_sessions s
    INNER HASH JOIN sys.dm_xe_session_targets st ON s.address = st.event_session_address
    WHERE [name] = 'system_health') AS Data
CROSS APPLY TargetData.nodes ('//RingBufferTarget/event') AS XEventData (XEvent)
WHERE XEventData.XEvent.value('@name', 'varchar(4000)') = 'xml_deadlock_report';

मैंने प्रश्न में दिखाए गए संस्करण से जोड़ों के लिखित आदेश को उलट दिया है, क्योंकि संकेत ( INNER HASH JOINऊपर) शामिल होने से पूरे क्वेरी के लिए आदेश भी बाध्य होता है, जैसे कि FORCE ORDERनिर्दिष्ट किया गया था। यह सुनिश्चित करने के लिए आवश्यक है कि Expr1000जांच पक्ष पर प्रकट हो। निष्पादन योजना का दिलचस्प हिस्सा है:

संकेत १

जांच पक्ष पर परिभाषित अभिव्यक्ति के साथ, मान कैश किया गया है:

हैश कैश

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

कैशे का पुन: उपयोग

जब ज्वाइन ऑर्डर को मजबूर किया जाता है Expr1000, तो हैश की बिल्ड साइड पर होने वाली परिभाषा जुड़ती है, तो स्थिति अलग होती है:

SELECT CAST (
    REPLACE (
        REPLACE (
            XEventData.XEvent.value ('(data/value)[1]', 'varchar(max)'),
            '<victim-list>', '<deadlock><victim-list>'),
        '<process-list>', '</victim-list><process-list>')
    AS XML) AS DeadlockGraph
FROM (SELECT CAST (target_data AS XML) AS TargetData
    FROM sys.dm_xe_session_targets st 
    INNER HASH JOIN sys.dm_xe_sessions s ON s.address = st.event_session_address
    WHERE [name] = 'system_health') AS Data
CROSS APPLY TargetData.nodes ('//RingBufferTarget/event') AS XEventData (XEvent)
WHERE XEventData.XEvent.value('@name', 'varchar(4000)') = 'xml_deadlock_report'

हश २

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

धीमी पहुँच

निम्नलिखित धीमे पहुंच पथ के अधिक विवरण दिखाता है:

धीमा विवरण

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

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

संदेश यह है कि XMLआज के अनुकूलन के लिए हेरफेर मुश्किल चीजें हो सकती हैं। XMLकफन से पहले एक चर या अस्थायी तालिका में लिखना ऊपर दिखाए गए किसी भी चीज़ की तुलना में बहुत अधिक ठोस समाधान है। ऐसा करने का एक तरीका है:

DECLARE @data xml =
        CONVERT
        (
            xml,
            (
            SELECT TOP (1)
                dxst.target_data
            FROM sys.dm_xe_sessions AS dxs 
            JOIN sys.dm_xe_session_targets AS dxst ON
                dxst.event_session_address = dxs.[address]
            WHERE 
                dxs.name = N'system_health'
                AND dxst.target_name = N'ring_buffer'
            )
        )

SELECT XEventData.XEvent.value('(data/value)[1]', 'varchar(max)')
FROM @data.nodes ('./RingBufferTarget/event[@name eq "xml_deadlock_report"]') AS XEventData (XEvent)
WHERE XEventData.XEvent.value('@name', 'varchar(4000)') = 'xml_deadlock_report';

अंत में, मैं बस मार्टिन के बहुत अच्छे ग्राफिक को नीचे दी गई टिप्पणियों से जोड़ना चाहता हूं:

मार्टिन का ग्राफिक


महान व्याख्या, धन्यवाद। मैंने आपके लेख को कंप्यूट स्केलर पर भी पढ़ा था लेकिन दो और दो को एक साथ नहीं रखा।
मार्टिन स्मिथ 12

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

2
हाँ स्क्रीनशॉट विजुअल स्टूडियो 2012 प्रोफाइलर से कॉल ट्री व्यू रिपोर्ट है । मुझे लगता है कि विधि नाम आपके आउटपुट में बहुत स्पष्ट दिखते हैं, हालांकि रहस्यमय तरीके से @@IEAAXPEA_Kप्रकट नहीं होते हैं।
मार्टिन स्मिथ

10

यह मूल रूप से यहां पोस्ट किए गए मेरे लेख का कोड है:

http://www.sqlservercentral.com/articles/deadlock/65658/

यदि आप उन टिप्पणियों को पढ़ते हैं, तो आपको कुछ ऐसे विकल्प मिलेंगे, जिनमें प्रदर्शन की समस्याएं नहीं हैं, जिन्हें आप अनुभव कर रहे हैं, एक उस मूल क्वेरी के संशोधन का उपयोग कर रहा है, और दूसरा एक वेरिएबल का उपयोग करके XML को संसाधित करने से पहले पकड़ सकता है जो कि काम करता है। बेहतर। (पृष्ठ 2 पर मेरी टिप्पणी देखें) XML को DMV से संसाधित करने में धीमा हो सकता है, क्योंकि फ़ाइल लक्ष्य के लिए DMF से XML को पार्स कर सकता है जो अक्सर डेटा को एक अस्थायी तालिका में पढ़ने और फिर इसे संसाधित करने से बेहतर होता है। .NET या SQLCLR जैसी चीजों के उपयोग की तुलना में SQL में XML धीमा है।


1
धन्यवाद! यही चाल चली। चर के बिना एक 600ms और 6341 पढ़ता है और चर के साथ 303 msऔर 3249 lob reads। 2012 में मुझे and target_name='ring_buffer'उस संस्करण में भी जोड़ने की जरूरत थी क्योंकि ऐसा लगता है कि अभी दो लक्ष्य हैं। मैं अभी भी एक मानसिक छवि प्राप्त करने की कोशिश कर रहा हूं कि यह वास्तव में 20 मिनट के संस्करण में क्या कर रहा है।
मार्टिन स्मिथ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.