परिचय
न्यूनतम लॉगिंग प्राप्त करना INSERT...SELECT
. के साथ एक जटिल व्यवसाय हो सकता है। डेटा लोडिंग प्रदर्शन गाइड में सूचीबद्ध विचार अभी भी बहुत व्यापक हैं, हालांकि किसी को भी SQL सर्वर 2016 को पढ़ने की जरूरत है, SQL सर्वर टाइगर टीम के परीक्षित सवजानी द्वारा अद्यतन चित्र प्राप्त करने के लिए SQL सर्वर 2016, न्यूनतम लॉगिंग और बल्क लोड संचालन में बैच का प्रभाव SQL सर्वर 2016 और बाद में, जब क्लस्टर्ड रोस्टोर टेबल में बल्क लोड हो रहा है। उस ने कहा, यह लेख पूरी तरह से नए विवरण प्रदान करने से संबंधित है न्यूनतम लॉगिंग . के बारे में जब बल्क लोडिंग पारंपरिक ("मेमोरी-ऑप्टिमाइज़्ड" नहीं) INSERT...SELECT
का उपयोग करके टेबल को हीप करें . बी-ट्री क्लस्टर इंडेक्स वाली तालिकाएं इस श्रृंखला के भाग दो में अलग से कवर की गई हैं।
हीप टेबल
INSERT...SELECT
. का उपयोग करके पंक्तियों को सम्मिलित करते समय बिना क्लस्टर इंडेक्स वाले ढेर में, दस्तावेज़ीकरण सार्वभौमिक रूप से बताता है कि ऐसे इंसर्ट न्यूनतम लॉग किए जाएंगे जब तक एक TABLOCK
. है संकेत मौजूद है। यह डेटा लोडिंग प्रदर्शन मार्गदर्शिका में शामिल सारांश तालिकाओं में दिखाई देता है और टाइगर टीम पोस्ट। अनुक्रमणिका के बिना हीप तालिकाओं के लिए सारांश पंक्तियाँ दोनों दस्तावेज़ों में समान हैं (SQL सर्वर 2016 के लिए कोई परिवर्तन नहीं):
एक स्पष्ट TABLOCK
टेबल-लेवल लॉकिंग की आवश्यकता को पूरा करने के लिए केवल संकेत ही एकमात्र तरीका नहीं है . हम ‘बल्क लोड पर टेबल लॉक’ . भी सेट कर सकते हैं sp_tableoption
. का उपयोग करके लक्ष्य तालिका के लिए विकल्प या प्रलेखित ट्रेस फ्लैग 715 को सक्षम करके। (नोट:INSERT...SELECT
का उपयोग करते समय न्यूनतम लॉगिंग को सक्षम करने के लिए ये विकल्प पर्याप्त नहीं हैं। क्योंकि INSERT...SELECT
बल्क अपडेट लॉक का समर्थन नहीं करता)।
“समवर्ती संभव” सारांश में कॉलम केवल INSERT...SELECT
. के अलावा अन्य बल्क लोडिंग विधियों पर लागू होता है . एक हीप तालिका का समवर्ती लोडिंग संभव नहीं है INSERT...SELECT
. के साथ . जैसा कि डेटा लोडिंग प्रदर्शन मार्गदर्शिका में बताया गया है , थोक लोड हो रहा है INSERT...SELECT
. के साथ एक अनन्य लेता है X
टेबल पर लॉक करें, न कि बल्क अपडेट BU
समवर्ती बल्क लोड के लिए लॉक आवश्यक है।
वह सब एक तरफ - और यह मानते हुए कि TABLOCK
के साथ एक अनइंडेक्स किए गए ढेर को थोक लोड करते समय न्यूनतम लॉगिंग की अपेक्षा न करने का कोई अन्य कारण नहीं है। (या समकक्ष) — इंसर्ट अभी भी शायद नहीं कम से कम लॉग इन हो...
नियम का अपवाद
निम्नलिखित डेमो स्क्रिप्ट को नए परीक्षण डेटाबेस में विकास उदाहरण पर चलाया जाना चाहिए SIMPLE
का उपयोग करने के लिए सेट करें रिकवरी मॉडल। यह INSERT...SELECT
. का उपयोग करके ढेर सारी पंक्तियों को एक हीप टेबल में लोड करता है TABLOCK
के साथ , और उत्पन्न लेनदेन लॉग रिकॉर्ड पर रिपोर्ट:
CREATE TABLE dbo.TestHeap ( id integer NOT NULL IDENTITY, c1 integer NOT NULL, padding char(45) NOT NULL DEFAULT '' ); GO -- Clear the log CHECKPOINT; GO -- Insert rows INSERT dbo.TestHeap WITH (TABLOCK) (c1) SELECT TOP (897) CHECKSUM(NEWID()) FROM master.dbo.spt_values AS SV; GO -- Show log entries SELECT FD.Operation, FD.Context, FD.[Log Record Length], FD.[Log Reserve], FD.AllocUnitName, FD.[Transaction Name], FD.[Lock Information], FD.[Description] FROM sys.fn_dblog(NULL, NULL) AS FD; GO -- Count the number of fully-logged rows SELECT [Fully Logged Rows] = COUNT_BIG(*) FROM sys.fn_dblog(NULL, NULL) AS FD WHERE FD.Operation = N'LOP_INSERT_ROWS' AND FD.Context = N'LCX_HEAP' AND FD.AllocUnitName = N'dbo.TestHeap';
आउटपुट से पता चलता है कि सभी 897 पंक्तियाँ पूरी तरह से लॉग थीं न्यूनतम लॉगिंग के लिए सभी शर्तों को स्पष्ट रूप से पूरा करने के बावजूद (अंतरिक्ष कारणों से केवल लॉग रिकॉर्ड का एक नमूना दिखाया गया है):
वही परिणाम देखा जाता है यदि सम्मिलन दोहराया जाता है (यानी यह कोई फर्क नहीं पड़ता कि ढेर तालिका खाली है या नहीं)। यह परिणाम दस्तावेज़ीकरण के विपरीत है।
ढेरों के लिए न्यूनतम लॉगिंग सीमा
किसी एक INSERT...SELECT
. में जितनी पंक्तियाँ जोड़ने की आवश्यकता है, उसकी संख्या न्यूनतम लॉगिंग . प्राप्त करने के लिए कथन तालिका लॉकिंग सक्षम के साथ एक अनइंडेक्स्ड हीप में उस गणना पर निर्भर करता है जो SQL सर्वर कुल आकार का अनुमान लगाते समय करता है डालने के लिए डेटा का। इस गणना के इनपुट हैं:
- एसक्यूएल सर्वर का संस्करण।
- पंक्तियों की अनुमानित संख्या सम्मिलित करें में ले जाती है ऑपरेटर।
- लक्ष्य तालिका पंक्ति आकार।
SQL सर्वर 2012 और इससे पहले . के लिए , इस विशेष तालिका . के लिए संक्रमण बिंदु 898 पंक्तियां है . डेमो स्क्रिप्ट में नंबर बदलना TOP
897 से 898 तक का क्लॉज निम्नलिखित आउटपुट देता है:
उत्पन्न लेनदेन लॉग प्रविष्टियाँ पृष्ठ आवंटन और सूचकांक आवंटन मानचित्र . के रखरखाव से संबंधित हैं (IAM) और पेज फ्री स्पेस (पीएफएस) संरचनाएं। याद रखें कि न्यूनतम लॉगिंग इसका अर्थ है कि SQL सर्वर प्रत्येक पंक्ति प्रविष्टि को व्यक्तिगत रूप से लॉग नहीं करता है। इसके बजाय, केवल मेटाडेटा और आवंटन संरचना में परिवर्तन लॉग होते हैं। 897 से 898 पंक्तियों में परिवर्तन न्यूनतम लॉगिंग सक्षम करता है इस विशिष्ट तालिका के लिए।
SQL सर्वर 2014 और बाद में . के लिए , संक्रमण बिंदु 950 पंक्तियाँ . है इस तालिका के लिए। चल रहा है INSERT...SELECT
TOP (949)
. के साथ पूर्ण लॉगिंग . का उपयोग करेगा - TOP (950)
में बदल रहा है न्यूनतम लॉगिंग उत्पन्न करेगा ।
दहलीज नहीं हैं कार्डिनैलिटी अनुमान . पर निर्भर उपयोग में मॉडल या डेटाबेस संगतता स्तर।
डेटा आकार की गणना
क्या SQL सर्वर रोसेट बल्क लोड का उपयोग करने का निर्णय लेता है? — और इसलिए क्या न्यूनतम लॉगिंग उपलब्ध है या नहीं — sqllang!CUpdUtil::FOptimizeInsert
नामक विधि में निष्पादित गणनाओं की एक श्रृंखला के परिणाम पर निर्भर करता है , जो या तो सत्य . लौटाता है न्यूनतम लॉगिंग के लिए, या गलत पूर्ण लॉगिंग के लिए। एक उदाहरण कॉल स्टैक नीचे दिखाया गया है:
परीक्षण का सार है:
- सम्मिलन 250 से अधिक पंक्तियों के लिए होना चाहिए ।
- कुल सम्मिलित डेटा आकार की गणना कम से कम 8 पृष्ठों . के रूप में की जानी चाहिए ।
250 से अधिक पंक्तियों के लिए जाँच पूरी तरह से टेबल इंसर्ट . पर आने वाली पंक्तियों की अनुमानित संख्या पर निर्भर करती है ऑपरेटर। इसे निष्पादन योजना में 'अनुमानित पंक्तियों की संख्या' . के रूप में दिखाया गया है . इससे सावधान रहें। पंक्तियों की कम अनुमानित संख्या वाली योजना बनाना आसान है, उदाहरण के लिए TOP
में एक चर का उपयोग करके बिना OPTION (RECOMPILE)
. के क्लॉज . उस स्थिति में, ऑप्टिमाइज़र 100 पंक्तियों का अनुमान लगाता है, जो थ्रेशोल्ड तक नहीं पहुंचेंगी, और इसलिए बल्क लोड और न्यूनतम लॉगिंग को रोकेंगी।
कुल डेटा आकार की गणना अधिक जटिल है, और मेल नहीं खाती ‘अनुमानित पंक्ति आकार’ टेबल इंसर्ट . में प्रवाहित हो रहा है ऑपरेटर। गणना करने का तरीका SQL Server 2012 और पहले SQL Server 2014 और बाद के संस्करण की तुलना में थोड़ा अलग है। फिर भी, दोनों एक पंक्ति आकार परिणाम उत्पन्न करते हैं जो निष्पादन योजना में दिखाई देने वाले से भिन्न होता है।
पंक्ति आकार की गणना
कुल सम्मिलित डेटा आकार की गणना पंक्तियों की अनुमानित संख्या . को गुणा करके की जाती है अपेक्षित अधिकतम पंक्ति आकार . द्वारा . पंक्ति आकार गणना वह बिंदु है जो SQL सर्वर संस्करणों के बीच भिन्न होता है।
SQL सर्वर 2012 और इससे पहले के संस्करण में, परिकलन sqllang!OptimizerUtil::ComputeRowLength
द्वारा किया जाता है . परीक्षण हीप तालिका के लिए (मूल FixedVar का उपयोग करके जानबूझकर साधारण निश्चित-लंबाई वाले गैर-शून्य स्तंभों के साथ डिज़ाइन किया गया पंक्ति भंडारण प्रारूप) गणना की एक रूपरेखा है:
- एक FixedVarइनिशियलाइज़ करें मेटाडेटा जनरेटर।
- टेबल इंसर्ट में प्रत्येक कॉलम के लिए प्रकार और विशेषता जानकारी प्राप्त करें इनपुट स्ट्रीम।
- टाइप किए गए कॉलम और एट्रिब्यूट को मेटाडेटा में जोड़ें।
- जनरेटर को अंतिम रूप दें और अधिकतम पंक्ति आकार के लिए पूछें।
- शून्य बिटमैप के लिए ओवरहेड जोड़ें और स्तंभों की संख्या।
- पंक्ति के लिए चार बाइट जोड़ें स्थिति बिट्स और पंक्ति ऑफ़सेट कॉलम डेटा की संख्या के लिए।
भौतिक पंक्ति आकार
इस गणना के परिणाम भौतिक पंक्ति आकार से मेल खाने की उम्मीद की जा सकती है, लेकिन ऐसा नहीं है। उदाहरण के लिए, डेटाबेस के लिए पंक्ति संस्करण बंद कर दिया गया है:
SELECT DDIPS.index_type_desc, DDIPS.alloc_unit_type_desc, DDIPS.page_count, DDIPS.record_count, DDIPS.min_record_size_in_bytes, DDIPS.max_record_size_in_bytes, DDIPS.avg_record_size_in_bytes FROM sys.dm_db_index_physical_stats ( DB_ID(), OBJECT_ID(N'dbo.TestHeap', N'U'), 0, -- heap NULL, -- all partitions 'DETAILED' ) AS DDIPS;
... 60 बाइट्स का रिकॉर्ड आकार देता है परीक्षण तालिका की प्रत्येक पंक्ति में:
यह एक ढेर के आकार का अनुमान लगाने में वर्णित है:
- सभी का कुल बाइट आकार निश्चित-लंबाई कॉलम =53 बाइट्स:
id integer NOT NULL
=4 बाइट्सc1 integer NOT NULL
=4 बाइट्सpadding char(45) NOT NULL
=45 बाइट्स।
- शून्य बिटमैप =3 बाइट्स :
- =2 + int((Num_Cols + 7) / 8)
- =2 + int((3 + 7) / 8)
- =3 बाइट्स।
- पंक्ति शीर्षलेख =4 बाइट्स ।
- कुल 53 + 3 + 4 =60 बाइट्स ।
यह निष्पादन योजना में दिखाए गए अनुमानित पंक्ति आकार से भी मेल खाता है:
आंतरिक गणना विवरण
यह निर्धारित करने के लिए उपयोग की जाने वाली आंतरिक गणना कि क्या बल्क लोड का उपयोग किया जाता है, निम्न स्ट्रीम सम्मिलित करें के आधार पर एक अलग परिणाम के साथ आता है। डीबगर का उपयोग करके प्राप्त कॉलम जानकारी। इस्तेमाल की गई संख्याएं sys.types
. से मेल खाती हैं :
- कुल निश्चित लंबाई स्तंभ का आकार =66 बाइट्स :
- टाइप आईडी 173
binary(8)
=8 बाइट्स (आंतरिक)। - आईडी 56 टाइप करें
integer
=4 बाइट्स (आंतरिक)। - टाइप आईडी 104
bit
=1 बाइट (आंतरिक)। - आईडी 56 टाइप करें
integer
=4 बाइट्स (id
कॉलम)। - आईडी 56 टाइप करें
integer
=4 बाइट्स (c1
कॉलम)। - टाइप आईडी 175
char(45)
=45 बाइट्स (padding
कॉलम)।
- टाइप आईडी 173
- शून्य बिटमैप =3 बाइट्स (पहले की तरह)।
- पंक्ति शीर्षलेख ओवरहेड =4 बाइट्स (पहले की तरह)।
- पंक्ति का परिकलित आकार =66 + 3 + 4 =73 बाइट्स ।
अंतर यह है कि टेबल इंसर्ट को फीड करने वाली इनपुट स्ट्रीम ऑपरेटर में तीन अतिरिक्त आंतरिक कॉलम शामिल हैं . शोप्लान तैयार होने पर इन्हें हटा दिया जाता है। अतिरिक्त कॉलम टेबल इंसर्ट लोकेटर बनाते हैं , जिसमें इसके पहले घटक के रूप में बुकमार्क (RID या पंक्ति लोकेटर) शामिल है। यह मेटाडेटा . है डालने के लिए और अंत में तालिका में जोड़ा नहीं जा रहा है।
अतिरिक्त कॉलम OptimizerUtil::ComputeRowLength
द्वारा की गई गणना के बीच विसंगति की व्याख्या करते हैं और पंक्तियों का भौतिक आकार। इसे बग . के रूप में देखा जा सकता है :SQL सर्वर को पंक्ति के अंतिम भौतिक आकार की ओर सम्मिलित स्ट्रीम में मेटाडेटा कॉलम की गणना नहीं करनी चाहिए। दूसरी ओर, सामान्य अपडेट . का उपयोग करके गणना केवल एक सर्वोत्तम प्रयास अनुमान हो सकता है ऑपरेटर।
गणना में अन्य कारकों जैसे पंक्ति संस्करण के 14-बाइट ओवरहेड का भी कोई हिसाब नहीं है। इसका परीक्षण किसी भी स्नैपशॉट आइसोलेशन . के साथ डेमो स्क्रिप्ट को फिर से चलाकर किया जा सकता है या प्रतिबद्ध स्नैपशॉट अलगाव पढ़ें डेटाबेस विकल्प सक्षम। पंक्ति का भौतिक आकार 14 बाइट्स (60 बाइट्स से 74 तक) बढ़ जाएगा, लेकिन न्यूनतम लॉगिंग के लिए सीमा 898 पंक्तियों पर अपरिवर्तित रहता है।
सीमा गणना
अब हमारे पास यह देखने के लिए आवश्यक सभी विवरण हैं कि SQL Server 2012 और इससे पहले की इस तालिका के लिए थ्रेशोल्ड 898 पंक्तियाँ क्यों हैं:
- 898 पंक्तियाँ 250 से अधिक पंक्तियों के लिए पहली आवश्यकता को पूरा करती हैं ।
- पंक्ति का परिकलित आकार =73 बाइट्स।
- पंक्तियों की अनुमानित संख्या =897.
- कुल डेटा आकार =73 बाइट्स * 897 पंक्तियाँ =65481 बाइट्स।
- कुल पृष्ठ =65481/8192 =7.9932861328125।
- यह>=8 पृष्ठों के लिए दूसरी आवश्यकता के ठीक नीचे है।
- 898 पंक्तियों के लिए, पृष्ठों की संख्या 8.002197265625 है।
- यह >=8 पृष्ठ है इसलिए न्यूनतम लॉगिंग सक्रिय है।
SQL सर्वर 2014 और बाद में . में , परिवर्तन हैं:
- पंक्ति आकार की गणना मेटाडेटा जनरेटर द्वारा की जाती है।
- टेबल लोकेटर में आंतरिक पूर्णांक स्तंभ अब सम्मिलित स्ट्रीम में मौजूद नहीं है। यह अद्वितीय का प्रतिनिधित्व करता है , जो केवल अनुक्रमणिका पर लागू होता है। ऐसा लगता है कि इसे बग फिक्स के रूप में हटा दिया गया था।
- अपेक्षित पंक्ति आकार 73 से 69 बाइट्स में बदल जाता है छोड़े गए पूर्णांक कॉलम (4 बाइट्स) के कारण।
- भौतिक आकार अभी भी 60 बाइट्स है। 9 बाइट्स के शेष अंतर को अतिरिक्त 8-बाइट RID और 1-बाइट बिट आंतरिक कॉलम इन्सर्ट स्ट्रीम में शामिल किया जाता है।
69 बाइट्स प्रति पंक्ति के साथ 8 पृष्ठों की सीमा तक पहुँचने के लिए:
- 8 पेज * 8192 बाइट्स प्रति पेज =65536 बाइट्स।
- 65535 बाइट्स / 69 बाइट्स प्रति पंक्ति =949.7971014492754 पंक्तियाँ।
- इसलिए हम कम से कम 950 पंक्तियों की अपेक्षा करते हैं रोसेट बल्क लोड . को सक्षम करने के लिए SQL सर्वर 2014 पर इस तालिका के लिए आगे।
सारांश और अंतिम विचार
थोक लोडिंग विधियों के विपरीत जो बैच आकार . का समर्थन करती हैं , जैसा कि परीक्षित सवजानी द्वारा पोस्ट में कवर किया गया है, INSERT...SELECT
एक unindexed ढेर में (खाली या नहीं) हमेशा नहीं . करता है टेबल-लॉकिंग निर्दिष्ट होने पर न्यूनतम लॉगिंग में परिणाम।
INSERT...SELECT
. के साथ न्यूनतम लॉगिंग सक्षम करने के लिए , SQL सर्वर को 250 से अधिक पंक्तियों की अपेक्षा करनी चाहिए कम से कम एक हद . के कुल आकार के साथ (8 पृष्ठ)।
अनुमानित कुल सम्मिलित आकार (8 पृष्ठ थ्रेशोल्ड के साथ तुलना करने के लिए) की गणना करते समय, SQL सर्वर पंक्तियों की अनुमानित संख्या को परिकलित अधिकतम पंक्ति आकार से गुणा करता है। SQL सर्वर आंतरिक स्तंभों की गणना करता है पंक्ति आकार की गणना करते समय सम्मिलित स्ट्रीम में मौजूद होता है। SQL सर्वर 2012 और इससे पहले के लिए, यह प्रति पंक्ति 13 बाइट्स जोड़ता है। SQL सर्वर 2014 और बाद के संस्करण के लिए, यह प्रति पंक्ति 9 बाइट्स जोड़ता है। यह केवल गणना को प्रभावित करता है; यह पंक्तियों के अंतिम भौतिक आकार को प्रभावित नहीं करता है।
जब न्यूनतम लॉग हीप बल्क लोड सक्रिय होता है, तो SQL सर्वर नहीं करता है पंक्तियों को एक-एक करके डालें। विस्तार अग्रिम रूप से आवंटित किए जाते हैं, और सम्मिलित की जाने वाली पंक्तियों को sqlmin!RowsetBulk
द्वारा संपूर्ण नए पृष्ठों में एकत्रित किया जाता है मौजूदा संरचना में जोड़े जाने से पहले। एक उदाहरण कॉल स्टैक नीचे दिखाया गया है:
तार्किक पठन रिपोर्ट नहीं किया गया . है लक्ष्य तालिका के लिए जब न्यूनतम लॉग किए गए हीप बल्क लोड का उपयोग किया जाता है - टेबल इंसर्ट प्रत्येक नई पंक्ति के लिए सम्मिलन बिंदु का पता लगाने के लिए ऑपरेटर को मौजूदा पृष्ठ को पढ़ने की आवश्यकता नहीं है।
वर्तमान में निष्पादन योजनाएं दिखाई नहीं जाती रोसेट बल्क लोड . का उपयोग करके कितनी पंक्तियाँ या पृष्ठ सम्मिलित किए गए थे और न्यूनतम लॉगिंग . शायद यह उपयोगी जानकारी भविष्य के रिलीज में उत्पाद में जोड़ दी जाएगी।