क्या यह ओवरलोड सर्वर का लक्षण है?


12

मैं एक आवेदन में धीमी गति से निदान करने की कोशिश कर रहा हूँ। इसके लिए मैंने SQL सर्वर विस्तारित घटनाओं को लॉग इन किया है ।

  • इस सवाल के लिए मैं एक विशेष संग्रहित प्रक्रिया को देख रहा हूं।
  • लेकिन एक दर्जन संग्रहीत प्रक्रियाओं का एक कोर सेट है जो समान रूप से सेब-से-सेब जांच के रूप में उपयोग किया जा सकता है
  • और जब भी मैं मैन्युअल रूप से संग्रहीत प्रक्रियाओं में से एक को चलाता हूं, तो यह हमेशा तेज चलती है
  • और यदि कोई उपयोगकर्ता फिर से प्रयास करता है: तो यह तेजी से चलेगा।

संग्रहीत प्रक्रिया का निष्पादन समय बेतहाशा भिन्न होता है। इस संग्रहीत कार्यविधि के बहुत सारे निष्पादन <1s में वापस आते हैं:

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

और उस "तेज" बाल्टी के लिए, यह 1s से बहुत कम है। यह वास्तव में लगभग 90 एमएस है:

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

लेकिन उपयोगकर्ताओं की एक लंबी पूंछ है, जिन्हें 2s, 3s, 4s सेकंड इंतजार करना पड़ता है। कुछ को १२, १३, १४ का इंतजार करना पड़ता है। फिर वास्तव में गरीब आत्माएं हैं जिन्हें 22, 23, 24 के दशक तक इंतजार करना पड़ता है।

और 30 के बाद, क्लाइंट एप्लिकेशन को छोड़ देता है, क्वेरी को रद्द कर देता है, और उपयोगकर्ता को 30 सेकंड इंतजार करना पड़ता था ।

करणीय खोजने के लिए सहसंबंध

इसलिए मैंने सहसंबंध बनाने की कोशिश की:

  • अवधि बनाम तार्किक रीड
  • अवधि बनाम शारीरिक रीड
  • अवधि बनाम सीपीयू समय

और कोई भी कोई संबंध नहीं देता है; कोई भी कारण नहीं लगता है

  • अवधि बनाम तार्किक पढ़ता है : चाहे थोड़ा, या बहुत तार्किक पढ़ता हो, अवधि में अभी भी बेतहाशा वृद्धि होती है :

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

  • अवधि बनाम शारीरिक रीड : भले ही कैश से क्वेरी की सेवा नहीं की गई थी, और बहुत अधिक शारीरिक रीड की आवश्यकता थी, यह अवधि को प्रभावित नहीं करता है:

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

  • अवधि बनाम सीपीयू समय : क्या क्वेरी सीपीयू समय के 0s, या सीपीयू समय का एक पूर्ण 2.5s लिया, अवधि समान परिवर्तनशीलता है:

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

बोनस : मैंने देखा है कि Duration v Physical Reads और Duration v CPU time बहुत समान दिखते हैं। यह साबित होता है अगर मैं भौतिक समय के साथ सीपीयू समय को सहसंबंधित करने की कोशिश करता हूं:

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

बहुत सारे CPU उपयोग I / O से आते हैं। किसे पता था!

इसलिए यदि निष्पादन समय में अंतरों के लिए क्वेरी को निष्पादित करने के अधिनियम के बारे में कुछ भी नहीं है , तो क्या इसका मतलब यह है कि यह सीपीयू या हार्ड ड्राइव से असंबंधित कुछ है?

यदि सीपीयू या हार्ड ड्राइव अड़चन थी; यह अड़चन नहीं होगी?

अगर हम परिकल्पना करते हैं कि यह सीपीयू था जो अड़चन था; इस सर्वर के लिए सीपीयू अंडर-पावर्ड है:

  • तब अधिक CPU समय का उपयोग करते हुए निष्पादन में अधिक समय नहीं लगेगा?
  • चूंकि उन्हें ओवरलोड सीपीयू का उपयोग करके दूसरों के साथ पूरा करना है?

इसी तरह हार्ड-ड्राइव के लिए। अगर हम अनुमान लगाते हैं कि हार्ड-ड्राइव एक अड़चन थी; हार्ड-ड्राइव में इस सर्वर के लिए पर्याप्त रैंडम-पुट नहीं है:

  • फिर अधिक भौतिक रीड्स का उपयोग करने में अधिक समय नहीं लगेगा?
  • चूंकि उन्हें दूसरों के साथ ओवरलोड हार्ड ड्राइव I / O का उपयोग करके पूरा करना है?

संग्रहीत प्रक्रिया न तो प्रदर्शन करती है, न ही आवश्यकता होती है, कोई भी लिखता है।

  • आमतौर पर यह 0 पंक्तियों (90%) को वापस करता है।
  • कभी-कभी यह 1 पंक्ति (7%) लौटाएगा।
  • शायद ही कभी यह 2 पंक्तियों (1.4%) को वापस करेगा।
  • और सबसे बुरे मामलों में यह 2 से अधिक पंक्तियों (एक बार 12 पंक्तियों की वापसी) लौटा है

इसलिए ऐसा नहीं है कि यह डेटा की एक पागल मात्रा वापस कर रहा है।

सर्वर CPU उपयोग

सर्वर का प्रोसेसर उपयोग औसत लगभग 1.8% है, कभी-कभी स्पाइक के साथ 18% तक - इसलिए ऐसा नहीं लगता है कि सीपीयू लोड एक मुद्दा है:

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

इसलिए सर्वर CPU अतिभारित नहीं लगता है।

लेकिन सर्वर है आभासी ...

ब्रह्मांड के बाहर कुछ?

केवल एक चीज जो मैं सोच सकता हूं वह कुछ है जो सर्वर के ब्रह्मांड के बाहर मौजूद है।

  • अगर यह तार्किक नहीं है
  • और यह शारीरिक रीड नहीं है
  • और यह सीपीयू उपयोग नहीं है
  • और यह सीपीयू लोड नहीं है

और ऐसा नहीं है कि यह संग्रहीत कार्यविधि के पैरामीटर है (क्योंकि उसी क्वेरी को मैन्युअल रूप से जारी करना और इसमें 27 सेकंड नहीं लगते हैं - यह ~ 0 सेकंड लेता है)।

एक ही संकलित संग्रहीत कार्यविधि को चलाने के लिए सर्वर को कभी-कभी 30 सेकंड लेने के बजाय 0 सेकंड के लिए क्या हो सकता है।

  • चौकियों?

यह एक वर्चुअल सर्वर है

  • होस्ट ओवरलोडेड है?
  • उसी मेजबान पर एक और वीएम?

सर्वर के विस्तारित घटनाओं के माध्यम से जाना; विशेष रूप से तब और कुछ नहीं होता है जब किसी क्वेरी को अचानक 20 सेकंड लगते हैं। यह ठीक चलता है, फिर ठीक नहीं चलने का फैसला करता है:

  • 2 सेकेंड
  • 1 सेकेंड
  • 30 सेकंड
  • तीन सेकंड
  • 2 सेकेंड

और वहाँ कोई अन्य particuarly ज़ोरदार आइटम मुझे मिल सकता है। यह हर 2 घंटे के लेनदेन लॉग बैकअप के दौरान नहीं है।

और क्या हो सकता है?

क्या मैं इसके अलावा कुछ भी कह सकता हूं: "सर्वर" ?

संपादित करें : दिन के समय तक सहसंबंध

मुझे एहसास हुआ कि मैंने सब कुछ करने के लिए अवधि को सहसंबद्ध किया है:

  • तार्किक पढ़ता है
  • भौतिक पढ़ता है
  • सि पि यु का उपयोग

लेकिन एक बात जो मैंने इसे नहीं बताया वह थी दिन का समय । शायद हर-2 घंटे की लेन-देन लॉग बैकअप है एक समस्या।

या शायद मंदी करते चौकियों दौरान chucks में होते हैं?

नहीं:

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

इंटेल Xeon गोल्ड क्वाड-कोर 6142।

संपादित करें - लोग क्वेरी निष्पादन योजना की परिकल्पना कर रहे हैं

लोग क्वेरी निष्पादन योजना की परिकल्पना कर रहे हैं "तेज" और "धीमी" के बीच अलग होना चाहिए। वो नहीं हैं।

और हम इसे निरीक्षण से तुरंत देख सकते हैं।

हम जानते हैं कि लंबी अवधि "खराब" निष्पादन योजना के कारण नहीं है:

  • एक जिसने अधिक तार्किक रीड लिया
  • एक जो अधिक CPU से जुड़ता है और अधिक जुड़ाव और महत्वपूर्ण लुकअप करता है

क्योंकि यदि रीड में वृद्धि, या सीपीयू में वृद्धि, क्वेरी अवधि में वृद्धि का कारण थी, तो हम पहले से ही ऊपर देख चुके होंगे। कोई संबंध नहीं है।

लेकिन सीपीयू-रीड्स एरिया उत्पाद मैट्रिक के खिलाफ अवधि को सहसंबंधित करने की कोशिश करता है:

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

वहाँ भी एक सहसंबंध कम हो जाता है - जो एक विरोधाभास है।


संपादित करें : बड़ी संख्या में मानों के साथ एक्सेल स्कैटर प्लॉट्स में बग को वर्कअराउंड करने के लिए तितर बितर आरेखों को अपडेट करें

अगला कदम

मेरा अगला कदम अवरुद्ध प्रश्नों के लिए सर्वर उत्पन्न करने के लिए किसी को प्राप्त करना होगा - 5 सेकंड के बाद:

EXEC sp_configure 'blocked process threshold', '5';
RECONFIGURE

यह स्पष्ट नहीं होगा कि प्रश्न 4 सेकंड के लिए अवरोधित हैं या नहीं । लेकिन शायद 5 सेकंड के लिए क्वेरी को ब्लॉक करने वाली कोई भी चीज़ 4 सेकंड के लिए भी ब्लॉक हो जाती है।

धीरे चलने वाले

यहाँ दो संग्रहीत कार्यविधियों को निष्पादित किया जा रहा है:

  • `EXECUTE FindFrob @CustomerID = 7383, @StartDate = '20190725 04: 00: 00.000', @EndDate = '20190726 04: 00: 00.000'
  • `EXECUTE FindFrob @CustomerID = 7383, @StartDate = '20190725 04: 00: 00.000', @EndDate = '20190726 04: 00: 00.000'

समान मापदंडों के साथ एक ही संग्रहित प्रक्रिया, बैक टू बैक चलती है:

| Duration (us) | CPU time (us) | Logical reads | Physical reads | 
|---------------|---------------|---------------|----------------|
|    13,984,446 |        47,000 |         5,110 |            771 |
|     4,603,566 |        47,000 |         5,126 |            740 |

कॉल 1:

|--Nested Loops(Left Semi Join, OUTER REFERENCES:([Contoso2].[dbo].[Frobs].[FrobGUID]) OPTIMIZED)
    |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]))
    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[RowNumber]) OPTIMIZED)
    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
    |    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
    |    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[TransactionPatronInfo].[IX_TransactionPatronInfo_CustomerID_TransactionGUID] AS [tpi]), SEEK:([tpi].[CustomerID]=[@CustomerID]) ORDERED FORWARD)
    |    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[Transactions].[IX_Transactions_TransactionGUIDTransactionDate]), SEEK:([Contoso2].[dbo].[Transactions].[TransactionGUID]=[Contoso2].[dbo
    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions2_MoneyAppearsOncePerTransaction]), SEEK:([Contoso2].[dbo].[FrobTransactions].[TransactionGUID]=[Contos
    |    |    |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions_RowNumber]), SEEK:([Contoso2].[dbo].[FrobTransactions].[RowNumber]=[Contoso2].[dbo].[Fin
    |    |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[Frobs].[PK_Frobs_FrobGUID]), SEEK:([Contoso2].[dbo].[Frobs].[FrobGUID]=[Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]),  WHERE:([Contos
    |--Filter(WHERE:([Expr1009]>(1)))
     |--Compute Scalar(DEFINE:([Expr1009]=CONVERT_IMPLICIT(int,[Expr1012],0)))
          |--Stream Aggregate(DEFINE:([Expr1012]=Count(*)))
           |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactins_OnFrobGUID]), SEEK:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]=[Contoso2].[dbo].[Frobs].[LC

बुलाओ २

|--Nested Loops(Left Semi Join, OUTER REFERENCES:([Contoso2].[dbo].[Frobs].[FrobGUID]) OPTIMIZED)
    |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]))
    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[RowNumber]) OPTIMIZED)
    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
    |    |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
    |    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[TransactionPatronInfo].[IX_TransactionPatronInfo_CustomerID_TransactionGUID] AS [tpi]), SEEK:([tpi].[CustomerID]=[@CustomerID]) ORDERED FORWARD)
    |    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[Transactions].[IX_Transactions_TransactionGUIDTransactionDate]), SEEK:([Contoso2].[dbo].[Transactions].[TransactionGUID]=[Contoso2].[dbo
    |    |    |    |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions2_MoneyAppearsOncePerTransaction]), SEEK:([Contoso2].[dbo].[FrobTransactions].[TransactionGUID]=[Contos
    |    |    |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions_RowNumber]), SEEK:([Contoso2].[dbo].[FrobTransactions].[RowNumber]=[Contoso2].[dbo].[Fin
    |    |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[Frobs].[PK_Frobs_FrobGUID]), SEEK:([Contoso2].[dbo].[Frobs].[FrobGUID]=[Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]),  WHERE:([Contos
    |--Filter(WHERE:([Expr1009]>(1)))
     |--Compute Scalar(DEFINE:([Expr1009]=CONVERT_IMPLICIT(int,[Expr1012],0)))
          |--Stream Aggregate(DEFINE:([Expr1012]=Count(*)))
           |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactins_OnFrobGUID]), SEEK:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]=[Contoso2].[dbo].[Frobs].[LC

यह योजनाओं के समान होने के लिए समझ में आता है; यह एक ही संग्रहीत कार्यविधि को निष्पादित कर रहा है, एक ही पैरामीटर के साथ।


2
क्या आप क्वेरी योजनाओं को पोस्ट कर सकते हैं - अच्छा रन बनाम खराब रन?
परिजन शाह

4
यहाँ से मेरा पहला अनुमान अवरुद्ध होगा ...
टिबोर काराज़ी

3
इसे किसने उतारा? यह बहुत ही अचंभित, पूरी तरह से शोधित प्रश्न है, भले ही इसमें क्वेरी योजनाओं की कमी हो! मुझ से +1!
वेरेस

4
आप इस निष्कर्ष पर कैसे पहुंचे हैं कि क्वेरी प्लान "समान" हैं? क्या आपके कहने का मतलब है कि उनका आकार एक जैसा है? उन्हें कहीं पोस्ट करें ताकि हम भी तुलना कर सकें। बस हमें बता रहे हैं कि वे समान हैं इसका मतलब यह नहीं है कि वे समान हैं।
हारून बर्ट्रेंड

3
PasteThePlan का उपयोग करके अक्यूट निष्पादन योजनाओं को जोड़ना हमें एक विचार दे सकता है कि क्वेरी का क्या इंतजार था।
रैंडी वर्टॉन्गेन

जवाबों:


2

Wait_stats पर एक नज़र डालें और यह दिखाएगा कि आपके SQL सर्वर पर सबसे बड़ी अड़चनें क्या हैं।

मुझे हाल ही में एक समस्या का सामना करना पड़ा जहां एक बाहरी अनुप्रयोग रुक-रुक कर धीमी गति से चल रहा था। सर्वर पर संग्रहीत कार्यविधियाँ चलाना हमेशा तेज़ था, हालाँकि।

प्रदर्शन की निगरानी ने SQL कैश या RAM के उपयोग और सर्वर पर IO के बारे में चिंतित होने के लिए कुछ भी नहीं दिखाया।

जांच को संकुचित करने में जो मदद मिली, वह एसक्यूएल द्वारा एकत्र किए गए प्रतीक्षा आंकड़ों को क्वेरी कर रही थी sys.dm_os_wait_stats

SQLSkills वेबसाइट पर उत्कृष्ट स्क्रिप्ट आपको वे दिखाएगी जो आप सबसे अधिक अनुभव कर रहे हैं। फिर आप कारणों की पहचान करने के लिए अपनी खोज को छोटा कर सकते हैं।

एक बार जब आपको पता चल जाता है कि कौन से इंतजार बड़े मुद्दे हैं तो यह स्क्रिप्ट किस सत्र / डेटाबेस का इंतजार कर रही है, इसे कम करने में मदद मिलेगी:

SELECT OSW.session_id,
       OSW.wait_duration_ms,
       OSW.wait_type,
       DB_NAME(EXR.database_id) AS DatabaseName
FROM sys.dm_os_waiting_tasks OSW
INNER JOIN sys.dm_exec_sessions EXS ON OSW.session_id = EXS.session_id
INNER JOIN sys.dm_exec_requests EXR ON EXR.session_id = OSW.session_id
OPTION(Recompile);

उपरोक्त क्वेरी और विस्तृत विवरण MSSQLTips वेबसाइट से है

sp_BlitzFirstब्रेंट ओजर की वेबसाइट की स्क्रिप्ट आपको यह भी दिखाएगी कि मंदी का कारण क्या है।

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