SQL: यदि CPU या IO नहीं है तो INSERTs को धीमा कर रहा है?


19

हमारे पास एक उत्पाद के लिए एक डेटाबेस है जो लेखन-भारी है। हमने मदद करने के लिए SSD के साथ एक नया सर्वर मशीन खरीदा। हमारे आश्चर्य के लिए, हमारे धीमी मशीन के भंडारण के साथ सम्मिलन तेज नहीं थे। बेंचमार्किंग के दौरान हमने देखा कि SQL सर्वर प्रक्रिया द्वारा प्रदर्शित IO दर बहुत कम थी।

उदाहरण के लिए, मैंने इस पृष्ठ पर पाई गई स्क्रिप्ट को चलाया , इसके अलावा मैंने पाश के चारों ओर एक BEGIN TRAN और COMMIT जोड़ा। सबसे अच्छा मैं डिस्क का उपयोग 7Mb / s तक पहुंच सकता था, जबकि सीपीयू ने मुश्किल से 5% को छुआ था। सर्वर में 64Gb इंस्टॉल है और 10 का उपयोग कर रहा है। बाद के कॉल के लिए पहले कॉल डाउन करने में कुल रन समय 2 मिनट 15 सेकंड था। डेटाबेस सरल पुनर्प्राप्ति पर है और परीक्षण के दौरान निष्क्रिय था। मैंने प्रत्येक कॉल के बीच तालिका को गिरा दिया।

इतनी सरल स्क्रिप्ट इतनी धीमी क्यों है? हार्डवेयर का बमुश्किल उपयोग किया जा रहा है। समर्पित डिस्क बेंचमार्किंग टूल और एसक्यूआईओ दोनों संकेत देते हैं कि एसएसडी पढ़ने और लिखने दोनों के लिए 500Mb / s की गति के साथ सही ढंग से कार्य करता है। मैं समझता हूं कि यादृच्छिक लेखन क्रमिक लेखन की तुलना में धीमा है, लेकिन मैं इस तरह की सरल प्रविष्टि की उम्मीद करूंगा, बिना किसी अनुक्रमित तालिका के, बहुत तेज़ी से हो।

अंततः हमारा परिदृश्य बहुत अधिक जटिल है, लेकिन मुझे लगता है कि मुझे पहले एक साधारण मामले को समझने की आवश्यकता है। संक्षेप में हमारा एप्लिकेशन पुराने डेटा को हटा देता है, फिर SqlBulkopy का उपयोग करके स्टैगिंग टेबल पर नए डेटा की प्रतिलिपि बनाता है, कुछ फ़िल्टरिंग करता है, और अंत में डेटा को अंतिम तालिकाओं में कॉपी करने के लिए मामलों के आधार पर MERGE और / या INSERT INTO का उपयोग करता है।

-> EDIT 1: मैंने मार्टिन स्मिथ द्वारा लिंक की गई प्रक्रिया का पालन किया, और मुझे निम्नलिखित परिणाम मिले:

[Wait Type]  [Wait Count] [Total Wait (ms)] [T. Resource Wait (ms)] [T. Signal Wait (ms)]
NETWORK_IO          5008              46735                 46587        148
LOGBUFFER           901               5994                  5977         17
PAGELATCH_UP        40                866                   865          1
SOS_SCHEDULER_YIELD 53279             219                   121          98
WRITELOG            5                 145                   145          0
PAGEIOLATCH_UP      4                 58                    58           0
LATCH_SH            5                 0                     0            0

मुझे यह अजीब लगता है कि NETWORK_IO को अधिकांश समय लगता है, यह प्रदर्शित करने के लिए कोई परिणाम नहीं है और SQL फ़ाइलों के अलावा कहीं भी स्थानांतरित करने के लिए कोई डेटा नहीं है। क्या NETWORK_IO प्रकार में सभी IO शामिल हैं?

-> EDIT 2: मैंने 20Gb RAM डिस्क बनाई और वहां से एक डेटाबेस माउंट किया। एसएसडी पर मेरे पास सबसे अच्छा समय 48 का है, रैम डिस्क के साथ यह 37 सेकंड तक नीचे चला गया। NETWORK_IO अभी भी सबसे बड़ी प्रतीक्षा है। रैम डिस्क में अधिकतम लिखने की गति लगभग 250Mb / s थी, जबकि यह प्रति सेकंड मल्टी गीगाबाइट करने में सक्षम है। यह अभी भी बहुत सीपीयू का उपयोग नहीं कर रहा था, इसलिए एसक्यूएल को क्या रखा गया है?



3
NETWORK_IO3 लाख "1 पंक्ति (यों) प्रभावित" संदेशों को वापस भेजे जाने से हो सकता है। क्या आपने SET NOCOUNT ONस्क्रिप्ट में जोड़ने की कोशिश की ?
मार्टिन स्मिथ

हां, मैंने NOCOUNT को जोड़ा है।
जोफ

2
अजीब। मैं तब नेटवर्क गतिविधि के तरीके से बहुत उम्मीद नहीं करता। क्या आपने रनों के बीच पुरानी विस्तारित ईवेंट फ़ाइलों को हटा दिया है? स्क्रिप्ट जो उन्हें पढ़ती है वह एक जंगली कार्ड का उपयोग करती है EE_WaitStats*.xelताकि पुराने आपके परिणामों को दूषित करेंगे।
मार्टिन स्मिथ

अच्छा कॉल, मैं परिणामों को अपडेट करूंगा टॉमोरो।
Djof

जवाबों:


9

मुझे पता है कि यह एक पुराना प्रश्न है, लेकिन यह अभी भी खोजकर्ताओं की मदद कर सकता है और यह एक समस्या है जो हर अब और फिर से पॉप अप होती है।

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

मेरे मामले में, 3 मिलियन पंक्तियों को सम्मिलित करने में 36 सेकंड लगते हैं। अर्थात प्रति पंक्ति 36/30000000 = 0.000012 सेकंड। यह बहुत तेज है। मेरे सिस्टम पर, आवश्यक सभी चरणों के माध्यम से जाने के लिए बस 0.000012 लगते हैं।

इसे तेजी से पूरा करने का एकमात्र तरीका समानांतर में दूसरा सत्र शुरू करना है।

अगर मैं 15 मिलियन आवेषण कर समानांतर में 2 सत्र शुरू करते हैं। दोनों 18 सेकंड में खत्म करते हैं। मैं अधिक पैमाना बना सकता था, लेकिन मेरा वर्तमान परीक्षण सेटअप दो समानांतर सत्रों के साथ 95% सीपीयू मार रहा है, इसलिए 3 परिणाम करने से मैं सीपीयू की अड़चन मारूंगा।

अगर मैं 3 समानांतर पंक्तियों को सम्मिलित करते हुए 2 समानांतर सत्र शुरू करता हूं, तो वे दोनों 39 सेकंड में समाप्त हो जाते हैं। ऐसा है कि अब 39 सेकंड में 6 मिलियन पंक्तियाँ हैं।

ठीक है, जो अभी भी हमें NETWORK_IO प्रतीक्षा दिखाने के साथ छोड़ देता है।

NETWORK_IO प्रतीक्षा को इस तथ्य से जोड़ा जाता है कि आप उन्हें ट्रेस करने के लिए विस्तारित घटनाओं का उपयोग कर रहे हैं। मेरे मामले में सम्मिलित 36 सेकंड (avg पर) लेता है। विस्तारित घटना के तरीके का उपयोग करते समय (ऊपर की कड़ी में पहली टिप्पणी से) यह वही है जो पंजीकृत है:

Wait Type             Wait Count  Total Wait Time (ms) Total Resource Wait Time (ms) Total Signal Wait Time (ms)
NETWORK_IO            3455        68808                68802                         6
PAGEIOLATCH_SH        3           64                   64                            0
PAGEIOLATCH_UP        12          58                   58                            0
WRITE_COMPLETION      8           15                   15                            0
WRITELOG              3           9                    9                             0
PAGELATCH_UP          2           4                    4                             0
SOS_SCHEDULER_YIELD   32277       1                    0                             1
IO_COMPLETION         8           0                    0                             0
LATCH_SH              3           0                    0                             0
LOGBUFFER             1           0                    0                             0

आप देख सकते हैं कि NETWORK_IO का 68 सेकंड पंजीकृत है। लेकिन जब से डालने का पाश एक पिरोया कार्रवाई है कि 36 सेकंड लिया, यह नहीं हो सकता है। (हां, कई थ्रेड्स का उपयोग किया जाता है, लेकिन ऑपरेशन धारावाहिक हैं, कभी समानांतर में नहीं होते हैं, इसलिए आप क्वेरी की कुल अवधि की तुलना में अधिक प्रतीक्षा समय नहीं कर सकते हैं)

अगर मैं विस्तारित घटनाओं का उपयोग नहीं करता हूं, लेकिन एक शांत उदाहरण पर सिर्फ प्रतीक्षा डीएमवी का उपयोग करें (बस मुझे डालने के साथ) मैं इसे प्राप्त करता हूं:

Wait Type                   Wait Count  Total Wait Time (ms)  Total Resource Wait Time (ms) Signal Resource Wait Time (ms)
SOS_SCHEDULER_YIELD             8873                 0.21                                    0.01                                    0.20
PAGEIOLATCH_UP                  3                    0.02                                    0.02                                    0.00
PREEMPTIVE_OS_AUTHENTICATIONOPS 17                   0.02                                    0.02                                    0.00
PAGEIOLATCH_SH                  1                    0.00                                    0.00                                    0.00

तो जिस NETWORK_IO को आप विस्तारित ईवेंट लॉग में देख रहे थे, वह आपके सम्मिलित लूप से संबंधित नहीं था। (यदि आप nocount चालू नहीं करेंगे, तो आपके पास बड़े पैमाने पर async नेटवर्क IO प्रतीक्षा, +1 मार्टिन होगा)

हालाँकि मुझे नहीं पता कि NETWORK_IO विस्तारित घटना ट्रेस में क्यों दिखाई देता है। यकीन है कि घटनाओं के एक async फ़ाइल लक्ष्य के लिए लेखन ASYNC_NETWORK_IO जमा करता है, लेकिन निश्चित रूप से यह एक अलग SPID पर किया जाता है, तो हम जिस पर फ़िल्टर कर रहे हैं। मैं इसे स्वयं एक नया प्रश्न मान सकता हूं)


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

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

9

आमतौर पर आप sys.dm_exec_requestsविशेष रूप से और अपने INSERT अनुरोध के लिए wait_time, को देखकर शुरू करते हैं। यह एक स्पष्ट संकेत देगा कि आपका INSERT क्या अवरुद्ध कर रहा है। परिणाम इंगित करेंगे कि क्या ताला विवाद, फ़ाइल विकास घटनाएं, लॉग फ्लश प्रतीक्षा, आवंटन विवाद (आदि PFS पृष्ठ कुंडी विवाद के रूप में प्रकट होता है) आदि आदि। एक बार जब आप मापते हैं, तो अपने प्रश्न को तदनुसार अपडेट करें। मैं दृढ़ता से आपसे आग्रह करता हूं कि अब आगे बढ़ने से पहले आप रुकने की प्रतीक्षा और कतारों की समस्या निवारण पद्धति को पढ़ें ।wait_typewait_resource


3

मैंने ओपी में BEGIN TRAN / COMMIT के साथ लूप में जुड़े पेज पर परीक्षण स्क्रिप्ट चलाई। मेरी मशीन पर, पहली बार पूरा करने में 1:28 का समय लगा।

फिर मैंने इन दोनों आदेशों को लूप के बाहर स्थानांतरित कर दिया:

SELECT @Random = ROUND(((@Upper - @Lower -1) * RAND() + @Lower), 0)
SET @InsertDate = DATEADD(dd, @Random, GETDATE())

यह उसके बाद 28 सेकंड में पूरा हुआ।

मुझे यकीन नहीं है कि क्या हो रहा है, लेकिन मुझे लगता है कि RAND()कोड में किसी तरह की नींद हो सकती है , शायद एल्गोरिथ्म के हिस्से के रूप में वे एन्ट्रापी (बेहतर यादृच्छिक संख्या) उत्पन्न करने के लिए उपयोग कर रहे हैं।

FWIW, SSDs हमेशा राइट-हैवी ऐप्स के लिए सबसे अच्छी तकनीक नहीं हैं। सर्वश्रेष्ठ प्रदर्शन के लिए, सुनिश्चित करें कि आपका DB लॉग DB डेटा से अलग ड्राइव लेटर पर है, लॉग फाइल अपने अधिकतम आकार में पहले से बढ़ी हुई है, और लॉग को कभी छोटा नहीं करें।


आपके इनपुट के लिए धन्यवाद कोड को लूप से बाहर ले जाने से मुझे तेजी से परिणाम नहीं मिला। रुको मैंने अवलोकन किया है कि यदि आप इसे कई बार चलाते हैं तो यह तेज हो जाता है, यही वह हो सकता है जिसे आपने अनुभव किया हो। मुझे पता है कि एसएसडी सिल्वर बुलेट नहीं हैं, लेकिन मुझे अभी भी ऐसा लगता है कि प्रदर्शन ऐसा नहीं है।
जोफ

1

एक और DMV जिसका उपयोग मैं धीमेपन की पहचान करने के लिए करता हूं वह sysinos_os_waiting_tasks है । यदि आपकी क्वेरी CPU गहन नहीं है, तो आप इस DMV से प्रतीक्षा के बारे में अधिक जानकारी प्राप्त कर सकते हैं।


0

मैं sql 2008 के लिए प्रतीक्षा की घटनाओं की सूची देख रहा हूँ और मैं NETWORK_IO को सूचीबद्ध नहीं देखता: http://technet.microsoft.com/en-us/library/ms179984(v=sql.100).aspx

मुझे लगा कि NETWORK_IO अब सिर्फ ASYNC_NETWORK_IO के रूप में सूचीबद्ध है, इसलिए मैं पूछना चाहता था कि क्या आप अपने SQL के संस्करण को फिर से देख सकते हैं, क्योंकि मैं बस इस बात के लिए उत्सुक हूं कि इस संस्करण के लिए वह इंतजार क्यों / कैसे कर रहा है।

जैसा कि नेटवर्क प्रतीक्षा के लिए बिल्कुल दिखाई दे रहा है, हाँ, यह तब भी हो सकता है जब आप एक स्टैंडअलोन सर्वर पर काम कर रहे हों। क्या आपने अपने नेटवर्क कार्ड के लिए सेटिंग्स की जाँच की है? मुझे आश्चर्य है कि अगर वे एक मुद्दा हैं।

दिन के अंत में केवल कुछ संसाधन बाधाएं संभव हैं: मेमोरी, सीपीयू, डिस्क I / O, नेटवर्क और लॉकिंग। आपने संकेत दिया है कि CPU और I / O समस्या नहीं है, और आपके पास NETWORK_IO की प्रतीक्षा घटना है, इसलिए मेरा सुझाव है कि आप पहले उन NIC कार्डों को देखें।


1
NETWORK_IOक्योंकि ओपी विस्तारित घटनाओं उपयोग कर रहा है दिखाया गया है। यह कभी भी अपडेट नहीं हुआsys.dm_xe_map_values
मार्टिन स्मिथ

मैं वही SQLRockstar सोच रहा हूँ, बस क्या हो सकता है। मैंने नेटवर्क कार्ड को पूरी तरह से अक्षम करने का प्रयास किया। मार्टिन ने कहा कि कुछ पुरानी फाइलें अभी भी हो सकती हैं मैं परिणाम टॉमोरो को अपडेट करूंगा कि क्या यह कुछ भी बदलता है।
जोफ

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