विलंबित स्थायित्व SQL सर्वर 2014 में एक देर से तोड़ने वाली लेकिन दिलचस्प विशेषता है; सुविधा का उच्च-स्तरीय एलिवेटर पिच काफी सरल है:
- "प्रदर्शन के लिए व्यापार स्थायित्व।"
कुछ पृष्ठभूमि पहले। डिफ़ॉल्ट रूप से, SQL सर्वर राइट-फ़ॉरवर्ड लॉग (WAL) का उपयोग करता है, जिसका अर्थ है कि परिवर्तन किए जाने से पहले लॉग में परिवर्तन लिखे जाते हैं। उन प्रणालियों में जहां लेन-देन लॉग लिखना अड़चन बन जाता है, और जहां डेटा हानि के लिए एक मध्यम सहनशीलता होती है , अब आपके पास लॉग फ्लश और पावती की प्रतीक्षा करने की आवश्यकता को अस्थायी रूप से निलंबित करने का विकल्प है। कम से कम डेटा के एक छोटे से हिस्से के लिए (इस पर बाद में और अधिक)।
आप पहले से ही यह बलिदान कर चुके हैं। पूर्ण पुनर्प्राप्ति मोड में, डेटा हानि का हमेशा कुछ जोखिम होता है, इसे केवल आकार के बजाय समय के संदर्भ में मापा जाता है। उदाहरण के लिए, यदि आप हर पांच मिनट में लेन-देन लॉग का बैक अप लेते हैं, तो कुछ विनाशकारी होने पर आप केवल 5 मिनट से कम डेटा खो सकते हैं। मैं यहां साधारण फेलओवर की बात नहीं कर रहा हूं, लेकिन मान लें कि सर्वर में आग लग जाती है या कोई व्यक्ति पावर कॉर्ड पर ट्रिप करता है - डेटाबेस बहुत अच्छी तरह से अप्राप्य हो सकता है और आपको अंतिम लॉग बैकअप के समय में वापस जाना पड़ सकता है . और यह मान रहा है कि आप अपने बैकअप को कहीं पुनर्स्थापित करके उनका परीक्षण भी कर रहे हैं - एक गंभीर विफलता की स्थिति में आपके पास पुनर्प्राप्ति बिंदु नहीं हो सकता है जो आपको लगता है कि आपके पास है। बेशक, हम इस परिदृश्य के बारे में नहीं सोचते हैं, क्योंकि हम कभी भी बुरी चीज़ों™ . की उम्मीद नहीं करते हैं होने वाला।
यह कैसे काम करता है
विलंबित स्थायित्व लेखन लेनदेन को चालू रखने में सक्षम बनाता है जैसे कि लॉग को डिस्क पर फ़्लश किया गया था; वास्तव में, डिस्क पर लिखने को समूहीकृत और स्थगित कर दिया गया है, जिसे पृष्ठभूमि में संभाला जाना है। लेन-देन आशावादी है; यह मानता है कि लॉग फ्लश होगा होना। सिस्टम लॉग बफर के 60KB खंड का उपयोग करता है, और जब यह 60KB ब्लॉक भर जाता है तो लॉग को डिस्क पर फ्लश करने का प्रयास करता है (नवीनतम में - यह उससे पहले हो सकता है और अक्सर होगा)। आप इस विकल्प को डेटाबेस स्तर पर, व्यक्तिगत लेनदेन स्तर पर, या - इन-मेमोरी ओएलटीपी में मूल रूप से संकलित प्रक्रियाओं के मामले में - प्रक्रिया स्तर पर सेट कर सकते हैं। संघर्ष की स्थिति में डेटाबेस सेटिंग जीत जाती है; उदाहरण के लिए, यदि डेटाबेस को अक्षम करने के लिए सेट किया गया है, तो विलंबित विकल्प का उपयोग करके लेनदेन करने का प्रयास केवल बिना किसी त्रुटि संदेश के अनदेखा कर दिया जाएगा। साथ ही, कुछ लेनदेन हमेशा पूरी तरह से टिकाऊ होते हैं, डेटाबेस सेटिंग्स या प्रतिबद्ध सेटिंग्स की परवाह किए बिना; उदाहरण के लिए, सिस्टम लेनदेन, क्रॉस-डेटाबेस लेनदेन, और फाइलटेबल, चेंज ट्रैकिंग, चेंज डेटा कैप्चर और प्रतिकृति से जुड़े ऑपरेशन।
डेटाबेस स्तर पर, आप इसका उपयोग कर सकते हैं:
ALTER DATABASE dbname SET DELAYED_DURABILITY = DISABLED | ALLOWED | FORCED;
यदि आप इसे ALLOWED
पर सेट करते हैं , इसका मतलब है कि कोई भी व्यक्तिगत लेनदेन विलंबित स्थायित्व का उपयोग कर सकता है; FORCED
इसका मतलब है कि सभी लेन-देन जो विलंबित स्थायित्व का उपयोग कर सकते हैं (उपरोक्त अपवाद इस मामले में अभी भी प्रासंगिक हैं)। आप संभवतः ALLOWED
. का उपयोग करना चाहेंगे के बजाय FORCED
- लेकिन बाद वाला मौजूदा एप्लिकेशन के मामले में उपयोगी हो सकता है जहां आप इस विकल्प का उपयोग पूरे समय करना चाहते हैं और कोड की मात्रा को भी कम करना चाहते हैं जिसे छुआ जाना है। ALLOWED
के बारे में ध्यान देने योग्य एक महत्वपूर्ण बात यह है कि पूरी तरह से टिकाऊ लेन-देन को अधिक समय तक इंतजार करना पड़ सकता है, क्योंकि वे पहले किसी भी विलंबित टिकाऊ लेनदेन के फ्लश को मजबूर करेंगे।
लेन-देन के स्तर पर, आप कह सकते हैं:
COMMIT TRANSACTION WITH (DELAYED_DURABILITY = ON);
और एक इन-मेमोरी OLTP मूल रूप से संकलित प्रक्रिया में, आप निम्न विकल्प को BEGIN ATOMIC
में जोड़ सकते हैं ब्लॉक करें:
BEGIN ATOMIC WITH (DELAYED_DURABILITY = ON, ...)
एक सामान्य प्रश्न यह है कि लॉकिंग और आइसोलेशन सेमेन्टिक्स के साथ क्या होता है। वास्तव में कुछ भी नहीं बदलता है। लॉकिंग और ब्लॉकिंग अभी भी होती है, और लेन-देन उसी तरह और समान नियमों के साथ किया जाता है। अंतर केवल इतना है कि, लॉग को डिस्क पर फ्लश करने के लिए प्रतीक्षा किए बिना प्रतिबद्धता को होने की अनुमति देकर, किसी भी संबंधित लॉक को बहुत जल्द जारी किया जाता है।
आपको इसका उपयोग कब करना चाहिए
लॉग राइट होने की प्रतीक्षा किए बिना लेन-देन को आगे बढ़ने की अनुमति देने से आपको मिलने वाले लाभ के अलावा, आपको बड़े आकार के कम लॉग राइट भी मिलते हैं। यह बहुत अच्छी तरह से काम कर सकता है यदि आपके सिस्टम में लेनदेन का उच्च अनुपात है जो वास्तव में 60 केबी से छोटा है, और विशेष रूप से जब लॉग डिस्क धीमी है (हालांकि मुझे एसएसडी और पारंपरिक एचडीडी पर समान लाभ मिलते हैं)। यदि आपके लेन-देन अधिकांश भाग के लिए 60KB से बड़े हैं, यदि वे आम तौर पर लंबे समय से चल रहे हैं, या यदि आपके पास उच्च थ्रूपुट और उच्च संगामिति है तो यह इतनी अच्छी तरह से काम नहीं करता है। यहां क्या हो सकता है कि आप फ्लश खत्म होने से पहले पूरे लॉग बफर को भर सकते हैं, जिसका मतलब है कि आपकी प्रतीक्षा को एक अलग संसाधन में स्थानांतरित करना और अंततः, एप्लिकेशन के उपयोगकर्ताओं द्वारा कथित प्रदर्शन में सुधार नहीं करना।
दूसरे शब्दों में, यदि आपका लेन-देन लॉग वर्तमान में कोई अड़चन नहीं है, तो इस सुविधा को चालू न करें। आप कैसे बता सकते हैं कि आपका लेन-देन लॉग वर्तमान में एक अड़चन है? पहला संकेतक उच्च होगा WRITELOG
प्रतीक्षा करता है, खासकर जब PAGEIOLATCH_**
. के साथ मिलकर . पॉल रान्डल (@PaulRandal) के पास लेन-देन लॉग समस्याओं की पहचान करने के साथ-साथ इष्टतम प्रदर्शन के लिए कॉन्फ़िगर करने पर एक महान चार-भाग श्रृंखला है:
- लेन-देन लॉग फैट को ट्रिम करना
- अधिक ट्रांजेक्शन लॉग फैट को ट्रिम करना
- लेन-देन लॉग कॉन्फ़िगरेशन समस्याएं
- लेन-देन लॉग मॉनिटरिंग
Kimberly Tripp (@KimberlyLTripp), 8 स्टेप्स टू बेटर ट्रांजैक्शन लॉग थ्रूपुट, और SQL CAT टीम के ब्लॉग पोस्ट, डायग्नोसिस ट्रांजैक्शन लॉग परफॉर्मेंस इश्यूज एंड लिमिट्स ऑफ लॉग मैनेजर की इस ब्लॉग पोस्ट को भी देखें।
यह जांच आपको इस निष्कर्ष पर ले जा सकती है कि विलंबित स्थायित्व देखने लायक है; यह नहीं हो सकता है। अपने कार्यभार का परीक्षण निश्चित रूप से जानने का सबसे विश्वसनीय तरीका होगा। SQL सर्वर के हाल के संस्करणों में कई अन्य परिवर्धन की तरह (*cough* Hekaton ), यह सुविधा हर एक कार्यभार को सुधारने के लिए नहीं बनाई गई है - और जैसा कि ऊपर उल्लेख किया गया है, यह वास्तव में कुछ कार्यभार को बदतर बना सकती है। कुछ अन्य प्रश्नों के लिए साइमन हार्वे द्वारा यह ब्लॉग पोस्ट देखें, आपको यह निर्धारित करने के लिए अपने कार्यभार के बारे में खुद से पूछना चाहिए कि बेहतर प्रदर्शन प्राप्त करने के लिए कुछ स्थायित्व का त्याग करना संभव है या नहीं।
डेटा हानि की संभावना
मैं कई बार इसका उल्लेख करने जा रहा हूं, और हर बार जब मैं करता हूं तो जोर देता हूं:आपको डेटा हानि के प्रति सहनशील होने की आवश्यकता है . एक अच्छी तरह से प्रदर्शन करने वाली डिस्क के तहत, आपको एक आपदा में खोने की अधिकतम उम्मीद करनी चाहिए - या यहां तक कि एक योजनाबद्ध और सुंदर शटडाउन - एक पूर्ण ब्लॉक (60 केबी) तक है। हालाँकि, उस स्थिति में जहाँ आपका I/O सबसिस्टम नहीं रख सकता है, यह संभव है कि आप पूरे लॉग बफ़र (~7MB) जितना खो सकते हैं।
स्पष्ट करने के लिए, दस्तावेज़ीकरण से (जोर मेरा):
विलंबित स्थायित्व के लिए, अनपेक्षित शटडाउन और SQL सर्वर के अपेक्षित शटडाउन/पुनरारंभ में कोई अंतर नहीं है . विनाशकारी घटनाओं की तरह, आपको डेटा हानि की योजना बनानी चाहिए . नियोजित शटडाउन/पुनरारंभ में कुछ लेन-देन जो डिस्क पर नहीं लिखे गए हैं, पहले डिस्क पर सहेजे जा सकते हैं, लेकिन आपको इस पर योजना नहीं बनानी चाहिए। योजना इस प्रकार है जैसे कि शटडाउन/पुनरारंभ, चाहे नियोजित हो या अनियोजित, डेटा को एक भयावह घटना के समान खो देता है।इसलिए यह बहुत महत्वपूर्ण है कि आप अपने डेटा हानि जोखिम को लेन-देन लॉग प्रदर्शन समस्याओं को कम करने की आवश्यकता के साथ तौलें। यदि आप एक बैंक चलाते हैं या पैसे से संबंधित कुछ भी करते हैं, तो आपके लिए इस सुविधा का उपयोग करके पासा रोल करने की तुलना में अपने लॉग को तेज डिस्क पर ले जाना अधिक सुरक्षित और अधिक उपयुक्त हो सकता है। यदि आप अपने वेब गेमरज़ चैट रूम एप्लिकेशन में प्रतिक्रिया समय में सुधार करने का प्रयास कर रहे हैं, तो शायद जोखिम कम गंभीर है।
डेटा हानि के अपने जोखिम को कम करने के लिए आप इस व्यवहार को कुछ हद तक नियंत्रित कर सकते हैं। आप सभी विलंबित टिकाऊ लेन-देन को दो तरीकों में से एक में डिस्क पर फ़्लश करने के लिए बाध्य कर सकते हैं:
- कोई भी पूरी तरह से टिकाऊ लेन-देन करें।
- कॉल करें
sys.sp_flush_log
मैन्युअल रूप से।
यह आपको आकार के बजाय समय के संदर्भ में डेटा हानि को नियंत्रित करने के लिए वापस जाने की अनुमति देता है; उदाहरण के लिए, आप हर 5 सेकंड में फ्लश शेड्यूल कर सकते हैं। लेकिन आप यहां अपनी प्यारी जगह ढूंढना चाहेंगे; अक्सर फ्लशिंग विलंबित स्थायित्व लाभ को पहले स्थान पर ऑफसेट कर सकता है। किसी भी मामले में, आपको अभी भी डेटा हानि के प्रति सहनशील रहने की आवश्यकता होगी , भले ही यह केवल
आपको लगता होगा कि CHECKPOINT
यहाँ मदद कर सकता है, लेकिन यह ऑपरेशन वास्तव में तकनीकी रूप से गारंटी नहीं देता है कि लॉग डिस्क पर फ़्लश हो जाएगा।
HA/DR के साथ सहभागिता
आपको आश्चर्य हो सकता है कि विलंबित स्थायित्व HA/DR सुविधाओं जैसे लॉग शिपिंग, प्रतिकृति और उपलब्धता समूहों के साथ कैसे कार्य करता है। इनमें से अधिकांश के साथ यह अपरिवर्तित काम करता है। लॉग शिपिंग और प्रतिकृति हार्ड किए गए लॉग रिकॉर्ड को फिर से चलाएगी, इसलिए डेटा हानि की समान संभावना वहां मौजूद है। एसिंक्रोनस मोड में एजी के साथ, हम वैसे भी माध्यमिक स्वीकृति की प्रतीक्षा नहीं कर रहे हैं, इसलिए यह आज जैसा ही व्यवहार करेगा। हालांकि, सिंक्रोनस के साथ, हम प्राथमिक पर तब तक प्रतिबद्ध नहीं हो सकते जब तक कि लेन-देन प्रतिबद्ध न हो और दूरस्थ लॉग में कठोर न हो जाए। उस परिदृश्य में भी हमें स्थानीय लॉग लिखने के लिए प्रतीक्षा न करने से स्थानीय रूप से कुछ लाभ हो सकता है, फिर भी हमें दूरस्थ गतिविधि की प्रतीक्षा करनी होगी। तो उस परिदृश्य में कम लाभ है, और संभावित रूप से कोई नहीं; शायद दुर्लभ परिदृश्य को छोड़कर जहां प्राथमिक की लॉग डिस्क वास्तव में धीमी है और माध्यमिक की लॉग डिस्क वास्तव में तेज़ है। मुझे संदेह है कि समान शर्तें सिंक/एसिंक मिररिंग के लिए सही हैं, लेकिन आपको मुझसे कोई आधिकारिक प्रतिबद्धता नहीं मिलेगी कि एक चमकदार नई सुविधा बहिष्कृत के साथ कैसे काम करती है। :-)
प्रदर्शन अवलोकन
अगर मैं कुछ वास्तविक प्रदर्शन अवलोकन नहीं दिखाता तो यह यहां एक पोस्ट नहीं होगा। मैंने निम्नलिखित विशेषताओं के साथ दो अलग-अलग कार्यभार पैटर्न के प्रभावों का परीक्षण करने के लिए 8 डेटाबेस स्थापित किए:
- पुनर्प्राप्ति मॉडल:सरल बनाम पूर्ण
- लॉग लोकेशन:एसएसडी बनाम एचडीडी
- स्थायित्व:विलंबित बनाम पूरी तरह से टिकाऊ
मैं वास्तव में, वास्तव में, वास्तव में <स्ट्राइक>आलसीस्ट्राइक> . हूं इस तरह की चीज के बारे में कुशल। चूंकि मैं प्रत्येक डेटाबेस में एक ही ऑपरेशन को दोहराने से बचना चाहता हूं, इसलिए मैंने निम्न तालिका को अस्थायी रूप से model
में बनाया है :
USE model; GO CREATE TABLE dbo.TheTable ( TheID INT IDENTITY(1,1) PRIMARY KEY, TheDate DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, RowGuid UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() );
फिर मैंने इन 8 डेटाबेस को बनाने के लिए डायनेमिक SQL कमांड का एक सेट बनाया, न कि व्यक्तिगत रूप से डेटाबेस बनाने और फिर सेटिंग्स के साथ मिलाने के लिए:
-- C and D are SSD, G is HDD DECLARE @sql NVARCHAR(MAX) = N''; ;WITH l AS (SELECT l FROM (VALUES('D'),('G')) AS l(l)), r AS (SELECT r FROM (VALUES('FULL'),('SIMPLE')) AS r(r)), d AS (SELECT d FROM (VALUES('FORCED'),('DISABLED')) AS d(d)), x AS (SELECT l.l, r.r, d.d, n = CONVERT(CHAR(1),ROW_NUMBER() OVER (ORDER BY d.d DESC, l.l)) FROM l CROSS JOIN r CROSS JOIN d) SELECT @sql += N' CREATE DATABASE dd' + n + ' ON ' + '(name = ''dd' + n + '_data'',' + ' filename = ''C:\SQLData\dd' + n + '.mdf'', size = 1024MB) LOG ON (name = ''dd' + n + '_log'',' + ' filename = ''' + l + ':\SQLLog\dd' + n + '.ldf'', size = 1024MB); ALTER DATABASE dd' + n + ' SET RECOVERY ' + r + '; ALTER DATABASE dd' + n + ' SET DELAYED_DURABILITY = ' + d + ';' FROM x ORDER BY d, l; PRINT @sql; -- EXEC sp_executesql @sql;
इस कोड को स्वयं चलाने के लिए स्वतंत्र महसूस करें (EXEC
. के साथ) अभी भी टिप्पणी की) यह देखने के लिए कि यह विलंबित स्थायित्व के साथ 4 डेटाबेस बनाएगा (दो पूर्ण पुनर्प्राप्ति में, दो SIMPLE में, प्रत्येक में से एक धीमी डिस्क पर लॉग के साथ, और प्रत्येक में से एक SSD पर लॉग के साथ)। विलंबित स्थायित्व के साथ 4 डेटाबेस के लिए उस पैटर्न को दोहराएं - मैंने परीक्षण में कोड को सरल बनाने के लिए ऐसा किया, बजाय यह दर्शाने के लिए कि मैं वास्तविक जीवन में क्या करूंगा (जहां मैं कुछ लेनदेन को महत्वपूर्ण मानता हूं, और कुछ के रूप में, ठीक है, आलोचनात्मक से कम)।
विवेक जाँच के लिए, मैंने यह सुनिश्चित करने के लिए निम्नलिखित क्वेरी चलाई कि डेटाबेस में विशेषताओं का सही मैट्रिक्स था:
SELECT d.name, d.recovery_model_desc, d.delayed_durability_desc, log_disk = CASE WHEN mf.physical_name LIKE N'D%' THEN 'SSD' else 'HDD' END FROM sys.databases AS d INNER JOIN sys.master_files AS mf ON d.database_id = mf.database_id WHERE d.name LIKE N'dd[1-8]' AND mf.[type] = 1; -- log
परिणाम:
नाम | रिकवरी_मॉडल | <थ>विलंबित_स्थायित्व <थ>लॉग_डिस्क||
---|---|---|---|
dd1 | पूर्ण | मजबूर | एसएसडी |
dd2 | सरल | मजबूर | एसएसडी |
dd3 | पूर्ण | मजबूर | एचडीडी |
dd4 | सरल | मजबूर | एचडीडी |
dd5 | पूर्ण | अक्षम | एसएसडी |
dd6 | सरल | अक्षम | एसएसडी |
dd7 | पूर्ण | अक्षम | एचडीडी |
dd8 | सरल | अक्षम | एचडीडी |
8 परीक्षण डेटाबेस का प्रासंगिक विन्यास
मैंने यह सुनिश्चित करने के लिए कई बार सफाई से परीक्षण चलाया कि 1 जीबी डेटा फ़ाइल और 1 जीबी लॉग फ़ाइल समीकरण में किसी भी ऑटोग्रोथ इवेंट को पेश किए बिना वर्कलोड के पूरे सेट को चलाने के लिए पर्याप्त होगी। सर्वोत्तम अभ्यास के रूप में, मैं नियमित रूप से यह सुनिश्चित करने के लिए अपने रास्ते से बाहर जाता हूं कि ग्राहकों के सिस्टम में पर्याप्त आवंटित स्थान (और इसमें निर्मित उचित अलर्ट) हैं ताकि अप्रत्याशित समय पर कोई भी विकास घटना न हो। वास्तविक दुनिया में मुझे पता है कि ऐसा हमेशा नहीं होता है, लेकिन यह आदर्श है।
मैंने SQL संतरी के साथ निगरानी करने के लिए सिस्टम की स्थापना की - यह मुझे उन अधिकांश प्रदर्शन मेट्रिक्स को आसानी से दिखाने की अनुमति देगा जिन्हें मैं हाइलाइट करना चाहता था। लेकिन मैंने बैच मेट्रिक्स को स्टोर करने के लिए एक अस्थायी तालिका भी बनाई है जिसमें sys.dm_io_virtual_file_stats से अवधि और बहुत विशिष्ट आउटपुट शामिल हैं:
SELECT test = 1, cycle = 1, start_time = GETDATE(), * INTO #Metrics FROM sys.dm_io_virtual_file_stats(DB_ID('dd1'), 2) WHERE 1 = 0;
यह मुझे प्रत्येक बैच के प्रारंभ और समाप्ति समय को रिकॉर्ड करने और प्रारंभ समय और समाप्ति समय के बीच DMV में डेल्टा मापने की अनुमति देगा (केवल इस मामले में विश्वसनीय है क्योंकि मुझे पता है कि मैं सिस्टम पर एकमात्र उपयोगकर्ता हूं)।पी>
बहुत सारे छोटे लेन-देन
पहला परीक्षण जो मैं करना चाहता था वह बहुत सारे छोटे लेनदेन थे। प्रत्येक डेटाबेस के लिए, मैं एक ही इंसर्ट के 500,000 अलग-अलग बैचों के साथ समाप्त करना चाहता था:
INSERT #Metrics SELECT 1, 1, GETDATE(), * FROM sys.dm_io_virtual_file_stats(DB_ID('dd1'), 2); GO INSERT dbo.TheTable DEFAULT VALUES; GO 500000 INSERT #Metrics SELECT 1, 2, GETDATE(), * FROM sys.dm_io_virtual_file_stats(DB_ID('dd1'), 2);
याद रखें, मैं <स्ट्राइक>आलसीस्ट्राइक> होने की कोशिश करता हूं इस तरह की चीज के बारे में कुशल। तो सभी 8 डेटाबेस के लिए कोड जनरेट करने के लिए, मैंने इसे चलाया:
;WITH x AS ( SELECT TOP (8) number FROM master..spt_values WHERE type = N'P' ORDER BY number ) SELECT CONVERT(NVARCHAR(MAX), N'') + N' INSERT #Metrics SELECT 1, 1, GETDATE(), * FROM sys.dm_io_virtual_file_stats(DB_ID(''dd' + RTRIM(number+1) + '''), 2); GO INSERT dbo.TheTable DEFAULT VALUES; GO 500000 INSERT #Metrics SELECT 1, 2, GETDATE(), * FROM sys.dm_io_virtual_file_stats(DB_ID(''dd' + RTRIM(number+1) + '''), 2);' FROM x;
मैंने यह परीक्षण चलाया और फिर #Metrics
. को देखा निम्न क्वेरी के साथ तालिका:
SELECT [database] = db_name(m1.database_id), num_writes = m2.num_of_writes - m1.num_of_writes, write_bytes = m2.num_of_bytes_written - m1.num_of_bytes_written, bytes_per_write = (m2.num_of_bytes_written - m1.num_of_bytes_written)*1.0 /(m2.num_of_writes - m1.num_of_writes), io_stall_ms = m2.io_stall_write_ms - m1.io_stall_write_ms, m1.start_time, end_time = m2.start_time, duration = DATEDIFF(SECOND, m1.start_time, m2.start_time) FROM #Metrics AS m1 INNER JOIN #Metrics AS m2 ON m1.database_id = m2.database_id WHERE m1.cycle = 1 AND m2.cycle = 2 AND m1.test = 1 AND m2.test = 1;
इससे निम्नलिखित परिणाम प्राप्त हुए (और मैंने कई परीक्षणों के माध्यम से पुष्टि की कि परिणाम सुसंगत थे):
डेटाबेस | लिखता है | बाइट्स | बाइट्स/लिखें | io_stall_ms | <थ>प्रारंभ_समय <थ>अंत_समय <थ>अवधि (सेकंड)|||
---|---|---|---|---|---|---|---|
dd1 | 8,068 | 261,894,656 | 32,460.91 | 6,232 | 2014-04-26 17:20:00 | 2014-04-26 17:21:08 | 68 |
dd2 | 8,072 | 261,682,688 | 32,418.56 | 2,740 | 2014-04-26 17:21:08 | 2014-04-26 17:22:16 | 68 |
dd3 | 8,246 | 262,254,592 | 31,803.85 | 3,996 | 2014-04-26 17:22:16 | 2014-04-26 17:23:24 | 68 |
dd4 | 8,055 | 261,688,320 | 32,487.68 | 4,231 | 2014-04-26 17:23:24 | 2014-04-26 17:24:32 | 68 |
dd5 | 500,012 | 526,448,640 | 1,052.87 | 35,593 | 2014-04-26 17:24:32 | 2014-04-26 17:26:32 | 120 |
dd6 | 500,014 | 525,870,080 | 1,051.71 | 35,435 | 2014-04-26 17:26:32 | 2014-04-26 17:28:31 | 119 |
dd7 | 500,015 | 526,120,448 | 1,052.20 | 50,857 | 2014-04-26 17:28:31 | 2014-04-26 17:30:45 | 134 |
dd8 | 500,017 | 525,886,976 | 1,051.73 | 49,680 | 133 |
छोटे लेन-देन:sys.dm_io_virtual_file_stats से अवधि और परिणाम
निश्चित रूप से यहाँ कुछ दिलचस्प अवलोकन:
- विलंबित टिकाऊपन डेटाबेस (पारंपरिक के लिए ~60X) के लिए व्यक्तिगत लेखन कार्यों की संख्या बहुत कम थी।
- विलंबित स्थायित्व का उपयोग करके लिखी गई बाइट्स की कुल संख्या को आधा कर दिया गया था (मुझे लगता है क्योंकि पारंपरिक मामले में सभी लेखन में बहुत अधिक जगह बर्बाद होती है)।
- विलंबित स्थायित्व के लिए प्रति लेखन बाइट्स की संख्या बहुत अधिक थी। यह बहुत आश्चर्यजनक नहीं था, क्योंकि फीचर का पूरा उद्देश्य बड़े बैचों में एक साथ राइट्स को बंडल करना है।
- I/O स्टालों की कुल अवधि अस्थिर थी, लेकिन विलंबित स्थायित्व के लिए मोटे तौर पर परिमाण का एक कम क्रम था। पूरी तरह टिकाऊ लेनदेन के तहत स्टॉल डिस्क के प्रकार के प्रति अधिक संवेदनशील थे।
- अगर किसी बात ने आपको अब तक आश्वस्त नहीं किया है, तो अवधि कॉलम बहुत कुछ बता रहा है। दो मिनट या उससे अधिक समय लेने वाले पूरी तरह से टिकाऊ बैच लगभग आधे में कट जाते हैं।
प्रारंभ/समाप्ति समय कॉलम ने मुझे उस सटीक अवधि के लिए प्रदर्शन सलाहकार डैशबोर्ड पर ध्यान केंद्रित करने की अनुमति दी जहां ये लेनदेन हो रहे थे, जहां हम बहुत सारे अतिरिक्त दृश्य संकेतक आकर्षित कर सकते हैं:
SQL संतरी डैशबोर्ड - बड़ा करने के लिए क्लिक करें
आगे के अवलोकन यहां:
- कई ग्राफ़ पर, आप स्पष्ट रूप से देख सकते हैं कि बैच के गैर-विलंबित स्थायित्व वाले हिस्से ने कब कार्यभार संभाला (~5:24:32 PM)।
- Delayed Durability का उपयोग करते समय CPU या मेमोरी पर कोई प्रभाव नहीं पड़ता है।
- आप SQL सर्वर गतिविधि के तहत पहले ग्राफ़ में प्रति सेकंड बैचों/लेनदेनों पर जबरदस्त प्रभाव देख सकते हैं।
- एसक्यूएल सर्वर पूरी तरह से टिकाऊ लेन-देन शुरू होने पर छत के माध्यम से प्रतीक्षा करता है। इनमें लगभग विशेष रूप से
WRITELOG
. शामिल थेPAGEIOLOATCH_EX
. की एक छोटी संख्या के साथ प्रतीक्षारत औरPAGEIOLATCH_UP
अच्छे उपाय की प्रतीक्षा कर रहा है। - विलंबित स्थायित्व संचालन के दौरान लॉग फ्लश की कुल संख्या काफी कम थी (कम 100s/सेकंड), जबकि पारंपरिक व्यवहार के लिए यह 4,000/सेकंड से अधिक हो गया (और परीक्षण की HDD अवधि के लिए थोड़ा कम)।उल>
कम, बड़े लेन-देन
अगले परीक्षण के लिए, मैं देखना चाहता था कि क्या होगा यदि हम कम संचालन करते हैं, लेकिन यह सुनिश्चित करते हैं कि प्रत्येक कथन बड़ी मात्रा में डेटा को प्रभावित करे। मैं चाहता था कि यह बैच प्रत्येक डेटाबेस के विरुद्ध चले:
CREATE TABLE dbo.Rnd ( batch TINYINT, TheID INT ); INSERT dbo.Rnd SELECT TOP (1000) 1, TheID FROM dbo.TheTable ORDER BY NEWID(); INSERT dbo.Rnd SELECT TOP (10) 2, TheID FROM dbo.TheTable ORDER BY NEWID(); INSERT dbo.Rnd SELECT TOP (300) 3, TheID FROM dbo.TheTable ORDER BY NEWID(); GO INSERT #Metrics SELECT 1, GETDATE(), * FROM sys.dm_io_virtual_file_stats(DB_ID('dd1'), 2); GO UPDATE t SET TheDate = DATEADD(MINUTE, 1, TheDate) FROM dbo.TheTable AS t INNER JOIN dbo.Rnd AS r ON t.TheID = r.TheID WHERE r.batch = 1; GO 10000 UPDATE t SET RowGuid = NEWID() FROM dbo.TheTable AS t INNER JOIN dbo.Rnd AS r ON t.TheID = r.TheID WHERE r.batch = 2; GO 10000 DELETE dbo.TheTable WHERE TheID IN (SELECT TheID FROM dbo.Rnd WHERE batch = 3); DELETE dbo.TheTable WHERE TheID IN (SELECT TheID+1 FROM dbo.Rnd WHERE batch = 3); DELETE dbo.TheTable WHERE TheID IN (SELECT TheID-1 FROM dbo.Rnd WHERE batch = 3); GO INSERT #Metrics SELECT 2, GETDATE(), * FROM sys.dm_io_virtual_file_stats(DB_ID('dd1'), 2);
इसलिए फिर से मैंने इस स्क्रिप्ट की 8 प्रतियाँ बनाने के लिए आलसी विधि का उपयोग किया, एक प्रति डेटाबेस:
;WITH x AS (SELECT TOP (8) number FROM master..spt_values WHERE type = N'P' ORDER BY number) SELECT N' USE dd' + RTRIM(Number+1) + '; GO CREATE TABLE dbo.Rnd ( batch TINYINT, TheID INT ); INSERT dbo.Rnd SELECT TOP (1000) 1, TheID FROM dbo.TheTable ORDER BY NEWID(); INSERT dbo.Rnd SELECT TOP (10) 2, TheID FROM dbo.TheTable ORDER BY NEWID(); INSERT dbo.Rnd SELECT TOP (300) 3, TheID FROM dbo.TheTable ORDER BY NEWID(); GO INSERT #Metrics SELECT 2, 1, GETDATE(), * FROM sys.dm_io_virtual_file_stats(DB_ID(''dd' + RTRIM(number+1) + ''', 2); GO UPDATE t SET TheDate = DATEADD(MINUTE, 1, TheDate) FROM dbo.TheTable AS t INNER JOIN dbo.rnd AS r ON t.TheID = r.TheID WHERE r.cycle = 1; GO 10000 UPDATE t SET RowGuid = NEWID() FROM dbo.TheTable AS t INNER JOIN dbo.rnd AS r ON t.TheID = r.TheID WHERE r.cycle = 2; GO 10000 DELETE dbo.TheTable WHERE TheID IN (SELECT TheID FROM dbo.rnd WHERE cycle = 3); DELETE dbo.TheTable WHERE TheID IN (SELECT TheID+1 FROM dbo.rnd WHERE cycle = 3); DELETE dbo.TheTable WHERE TheID IN (SELECT TheID-1 FROM dbo.rnd WHERE cycle = 3); GO INSERT #Metrics SELECT 2, 2, GETDATE(), * FROM sys.dm_io_virtual_file_stats(DB_ID(''dd' + RTRIM(number+1) + '''), 2);' FROM x;
मैंने इस बैच को चलाया, फिर
#Metrics
. के विरुद्ध क्वेरी बदल दी पहले के बजाय दूसरे टेस्ट को देखने के लिए ऊपर। परिणाम:डेटाबेस लिखता है बाइट्स बाइट्स/लिखें io_stall_ms <थ>प्रारंभ_समय <थ>अंत_समय <थ>अवधि (सेकंड)dd1 20,970 1,271,911,936 60,653.88 12,577 2014-04-26 17:41:21 2014-04-26 17:43:46 145 dd2 20,997 1,272,145,408 60,587.00 14,698 2014-04-26 17:43:46 2014-04-26 17:46:11 145 dd3 20,973 1,272,982,016 60,696.22 12,085 2014-04-26 17:46:11 2014-04-26 17:48:33 142 dd4 20,958 1,272,064,512 60,695.89 11,795 2014-04-26 17:48:33 2014-04-26 17:50:56 143 dd5 30,138 1,282,231,808 42,545.35 7,402 2014-04-26 17:50:56 2014-04-26 17:53:23 147 dd6 30,138 1,282,260,992 42,546.31 7,806 2014-04-26 17:53:23 2014-04-26 17:55:53 150 dd7 30,129 1,281,575,424 42,536.27 9,888 2014-04-26 17:55:53 2014-04-26 17:58:25 152 dd8 30,130 1,281,449,472 42,530.68 11,452 2014-04-26 17:58:25 2014-04-26 18:00:55 150 बड़ा लेन-देन:sys.dm_io_virtual_file_stats से अवधि और परिणाम
इस बार, विलंबित स्थायित्व का प्रभाव बहुत कम ध्यान देने योग्य है। हम लिखने के संचालन की थोड़ी छोटी संख्या देखते हैं, प्रति लेखन बाइट्स की थोड़ी बड़ी संख्या में, कुल बाइट्स लगभग समान लिखे गए हैं। इस मामले में हम वास्तव में देखते हैं कि I/O स्टॉल विलंबित स्थायित्व के लिए अधिक हैं, और यह इस तथ्य के लिए संभावित कारण है कि अवधि भी लगभग समान थी।
प्रदर्शन सलाहकार डैशबोर्ड से, हम पिछले परीक्षण के साथ कुछ समानताएं रखते हैं, और कुछ स्पष्ट अंतर भी:
SQL संतरी डैशबोर्ड - बड़ा करने के लिए क्लिक करेंयहां इंगित करने के लिए बड़े अंतरों में से एक यह है कि प्रतीक्षा आँकड़ों में डेल्टा पिछले परीक्षण की तरह स्पष्ट नहीं है - अभी भी
WRITELOG
की बहुत अधिक आवृत्ति है पूरी तरह से टिकाऊ बैचों की प्रतीक्षा करता है, लेकिन कहीं भी छोटे लेनदेन के साथ देखे गए स्तरों के आसपास नहीं है। एक और चीज जो आप तुरंत देख सकते हैं, वह यह है कि बैचों और प्रति सेकंड लेनदेन पर पहले देखा गया प्रभाव अब मौजूद नहीं है। और अंत में, जबकि देरी होने की तुलना में पूरी तरह से टिकाऊ लेनदेन के साथ अधिक लॉग फ्लश होते हैं, यह असमानता छोटे लेनदेन की तुलना में बहुत कम स्पष्ट होती है।
निष्कर्ष
यह स्पष्ट होना चाहिए कि कुछ कार्यभार प्रकार हैं जो विलंबित स्थायित्व से बहुत लाभान्वित हो सकते हैं - बशर्ते, कि आपके पास डेटा हानि के लिए सहनशीलता हो . यह सुविधा इन-मेमोरी OLTP तक सीमित नहीं है, SQL सर्वर 2014 के सभी संस्करणों पर उपलब्ध है, और इसे बिना किसी कोड परिवर्तन के लागू किया जा सकता है। यह निश्चित रूप से एक शक्तिशाली तकनीक हो सकती है यदि आपका कार्यभार इसका समर्थन कर सकता है। लेकिन फिर से, आपको यह सुनिश्चित करने के लिए अपने कार्यभार का परीक्षण करने की आवश्यकता होगी कि यह इस सुविधा से लाभान्वित होगा, और यह भी दृढ़ता से विचार करें कि क्या यह डेटा हानि के जोखिम के लिए आपके जोखिम को बढ़ाता है।
एक तरफ, यह SQL सर्वर भीड़ को एक नए नए विचार की तरह लग सकता है, लेकिन वास्तव में Oracle ने इसे 2006 में "एसिंक्रोनस कमिट" के रूप में पेश किया (देखें COMMIT WRITE ... NOWAIT
जैसा कि यहां प्रलेखित है और 2007 में ब्लॉग किया गया था)। और यह विचार लगभग 3 दशकों से है; हैल बेरेनसन के इतिहास का संक्षिप्त इतिहास देखें।
अगली बार
एक विचार जिस पर मैंने ध्यान दिया है, वह है tempdb
. के प्रदर्शन को बेहतर बनाने का प्रयास करना विलंबित स्थायित्व को मजबूर करके। tempdb
. की एक विशेष संपत्ति जो इसे इतना आकर्षक उम्मीदवार बनाता है कि यह स्वभाव से क्षणिक है - tempdb
. में कुछ भी सिस्टम घटनाओं की एक विस्तृत विविधता के मद्देनजर, स्पष्ट रूप से, टॉस करने योग्य होने के लिए डिज़ाइन किया गया है। मैं यह अब बिना किसी विचार के कह रहा हूं कि क्या कोई कार्यभार आकार है जहां यह अच्छी तरह से काम करेगा; लेकिन मैं इसे आजमाने की योजना बना रहा हूं, और अगर मुझे कुछ दिलचस्प लगता है, तो आप सुनिश्चित हो सकते हैं कि मैं इसके बारे में यहां पोस्ट करूंगा।