SQL सर्वर के 8 KByte डेटा पृष्ठ से 512 बाइट्स का उपयोग नहीं किया जा रहा है


13

मैंने निम्नलिखित तालिका बनाई है:

CREATE TABLE dbo.TestStructure
(
    id INT NOT NULL,
    filler1 CHAR(36) NOT NULL,
    filler2 CHAR(216) NOT NULL
);

और फिर एक गुच्छेदार सूचकांक बनाया:

CREATE CLUSTERED INDEX idx_cl_id 
ON dbo.TestStructure(id);

इसके बाद मैंने इसे 30 पंक्तियों के साथ आबाद किया जिसका प्रत्येक आकार 256 बाइट (तालिका घोषणा के आधार पर) है:

DECLARE @i AS int = 0;

WHILE @i < 30
BEGIN
    SET @i = @i + 1;

    INSERT INTO dbo.TestStructure (id, filler1, filler2)
    VALUES (@i, 'a', 'b');
END;

अब मैं "प्रशिक्षण किट (परीक्षा 70-461)" में पढ़ी गई जानकारी के आधार पर: Microsoft SQL Server 2012 (इट्ज़िक बेन-गान) को छोड़ कर पुस्तक:

SQL सर्वर आंतरिक रूप से पृष्ठों में डेटा फ़ाइल में डेटा को व्यवस्थित करता है। एक पृष्ठ 8 केबी इकाई है और एक एकल वस्तु के अंतर्गत आता है; उदाहरण के लिए, एक तालिका या एक सूचकांक के लिए। एक पृष्ठ पढ़ने और लिखने की सबसे छोटी इकाई है। पेज आगे विलुप्त होने में व्यवस्थित हैं। एक सीमा में लगातार आठ पृष्ठ होते हैं। एक सीमा से पृष्ठ किसी एक वस्तु या कई वस्तुओं से संबंधित हो सकते हैं। यदि पृष्ठ कई वस्तुओं से संबंधित हैं, तो सीमा को मिश्रित सीमा कहा जाता है; यदि पृष्ठ एक ही वस्तु के हैं, तो सीमा को एक समान सीमा कहा जाता है। SQL सर्वर किसी ऑब्जेक्ट के पहले आठ पृष्ठों को मिश्रित एक्स्टेंट में संग्रहीत करता है। जब कोई ऑब्जेक्ट आठ पृष्ठों से अधिक हो जाता है, तो SQL सर्वर इस ऑब्जेक्ट के लिए अतिरिक्त एकसमान अंश आवंटित करता है। इस संगठन के साथ, छोटी वस्तुएं कम जगह बर्बाद करती हैं और बड़ी वस्तुएं कम खंडित होती हैं।

इसलिए यहाँ मेरे पास पहला मिश्रित सीमा 8KB पृष्ठ है, जिसकी आबादी 7680 बाइट्स से है (मैंने 30 बार 256 बाइट आकार पंक्ति में डाली है, इसलिए 30 * 256 = 7680), आकार की जांच करने के लिए मैंने साइज़ चेक प्रोक खरीद की है - यह निम्न परिणाम देता है।

index_type_desc: CLUSTERED INDEX
index_depth: 1
index_level: 0 
page_count: 1 
record_count: 30 
avg_page_space_used_in_percent: 98.1961947121324
name : TestStructure        
rows : 30   
reserved :  16 KB
data : 8 KB 
index_size : 8 KB       
unused :    0 KB

तो 16 KB तालिका के लिए आरक्षित हैं, पहला 8 KB पृष्ठ रूट IAM पृष्ठ के लिए है, दूसरा पत्ता डेटा भंडारण पृष्ठ के लिए है जो ~ 7.5 KB के कब्जे के साथ 8KB है, अब जब मैं 256 बाइट के साथ एक नई पंक्ति सम्मिलित करता हूं:

INSERT INTO dbo.TestStructure (id, filler1, filler2)
VALUES (1, 'a', 'b');

यह एक ही पृष्ठ में संग्रहीत नहीं है, हालांकि इसमें 256 बाइट का स्थान है (7680 b + 256 = 7936 जो अभी भी 8KB से छोटा है), एक नया डेटा पेज बनाया गया है, लेकिन यह नया पंक्ति उसी पुराने पृष्ठ पर फिट हो सकता है SQL सर्वर एक नया पेज क्यों बनाता है, जब वह अंतरिक्ष को बचा सकता है और मौजूदा पेज में उसे डालते समय खोज सकता है?

नोट: एक ही बात ढेर सूचकांक में हो रहा है।

जवाबों:


9

आपकी डेटा पंक्तियाँ 256 बाइट्स नहीं हैं। हर एक 263 बाइट्स की तरह है। SQL सर्वर में डेटा पंक्ति की संरचना के कारण विशुद्ध रूप से निश्चित लंबाई के डेटा प्रकारों की डेटा पंक्ति में अतिरिक्त ओवरहेड होता है। इस साइट पर एक नज़र डालें और पढ़ें कि कैसे एक डेटा पंक्ति बनाई जाती है। http://aboutsqlserver.com/2013/10/15/sql-server-storage-engine-data-pages-and-data-rows/

तो आपके उदाहरण में, आपके पास एक डेटा पंक्ति है जिसमें 256bytes हैं, स्टेटस बिट्स के लिए 2 बाइट्स, स्तंभों की संख्या के लिए 2 बाइट्स, डेटा लंबाई के लिए 2 बाइट्स, और एक और 1 या शून्य बिटमैप के लिए जोड़ें। यह 263 * 30 = 7,890bytes है। एक और 263 जोड़ें और आप 8kb पेज की सीमा से अधिक हैं, जो दूसरे पेज को बनाने के लिए बाध्य करेगा।


आपके द्वारा प्रदान की गई लिंक ने मुझे पृष्ठ संरचना को बेहतर ढंग से देखने में मदद की, मैं इसके समान कुछ खोज रहा था, लेकिन इसे खोजने में असमर्थ था, थैक्स
अल्पेश सुप्रीमो

11

हालांकि यह सही है कि SQL सर्वर 1 या अधिक पंक्तियों को संग्रहीत करने के लिए 8k (8192 बाइट्स) डेटा पृष्ठों का उपयोग करता है, प्रत्येक डेटा पेज में कुछ ओवरहेड (96 बाइट्स) होते हैं, और प्रत्येक पंक्ति में कुछ ओवरहेड (कम से कम 9 बाइट्स) होते हैं। 8192 बाइट्स विशुद्ध रूप से डेटा नहीं है।

यह कैसे काम करता है, इसकी अधिक विस्तृत परीक्षा के लिए, कृपया निम्नलिखित DBA.SE प्रश्न के लिए मेरा उत्तर देखें:

DATALENGTHs का सारांश sys.allocation_units से तालिका आकार का मिलान नहीं कर रहा है

उस लिंक किए गए उत्तर में जानकारी का उपयोग करके, हम वास्तविक पंक्ति आकार की स्पष्ट तस्वीर प्राप्त कर सकते हैं:

  1. रो हेडर = 4 बाइट्स
  2. कॉलम की संख्या = 2 बाइट्स
  3. पूर्ण बिटमैप = 1 बाइट
  4. संस्करण जानकारी ** = 14 बाइट्स (वैकल्पिक, फुटनोट देखें)
  5. कुल प्रति पंक्ति ओवरहेड (स्लॉट ऐरे को छोड़कर) = 7 बाइट्स न्यूनतम, या 21 बाइट्स यदि संस्करण की जानकारी मौजूद है
  6. कुल वास्तविक पंक्ति आकार = 263 न्यूनतम (256 डेटा + 7 ओवरहेड), या 277 बाइट्स (256 डेटा + 21 ओवरहेड) यदि संस्करण की जानकारी मौजूद है
  7. स्लॉट ऐरे में जोड़कर, प्रति पंक्ति में लिया गया कुल स्थान वास्तव में 265 बाइट्स (संस्करण जानकारी के बिना) या 279 बाइट्स (संस्करण जानकारी के साथ) है।

का उपयोग करके DBCC PAGEमेरी गणना की पुष्टि करके दिखाता है: Record Size 263(के लिए tempdb), और Record Size 277(उस डेटाबेस के लिए जो सेट है ALLOW_SNAPSHOT_ISOLATION ON)।

अब, 30 पंक्तियों के साथ, जो है:

  • संस्करण की जानकारी के बिना

    30 * 263 हमें 7890 बाइट देगा। फिर उपयोग किए गए 7986 बाइट्स के लिए पेज हेडर के 96 बाइट्स में जोड़ें। अंत में, पृष्ठ पर उपयोग किए गए कुल 8046 बाइट्स के लिए स्लॉट सरणी के 60 बाइट्स (2 प्रति पंक्ति) में जोड़ें, और शेष 146। उपयोग करके DBCC PAGEमेरी गणना की पुष्टि करके दिखाता है:

    • m_slotCnt 30 (पंक्तियों की संख्या)
    • m_freeCnt 146 (पृष्ठ पर बाइट्स की संख्या शेष है)
    • m_freeData 7986 (अर्थात डेटा + पेज हेडर - 7890 + 96 - स्लॉट एरे को "यूज्ड" बाइट्स गणना में फैक्टर नहीं किया गया है)
  • संस्करण जानकारी के साथ

    कुल 8310 बाइट्स के लिए 30 * 277 बाइट्स। लेकिन 8310 8192 से अधिक है, और इसने 96 बाइट पेज हेडर और न ही 2 बाइट प्रति पंक्ति स्लॉट सरणी (30 * 2 = 60 बाइट्स) का भी हिसाब नहीं दिया, जो हमें पंक्तियों के लिए केवल 8036 प्रयोग करने योग्य बाइट्स देना चाहिए।

    लेकिन, 29 पंक्तियों के बारे में क्या? यह हमें 8033 बाइट्स डेटा (29 * 277) + 96 बाइट्स पेज हेडर के लिए + 58 बाइट्स स्लॉट ऐरे (29 * 2) के बराबर 8187 बाइट्स देगा। और जो पेज को 5 बाइट्स के साथ छोड़ देगा (8192 - 8187; अनुपयोगी, निश्चित रूप से)। उपयोग करके DBCC PAGEमेरी गणना की पुष्टि करके दिखाता है:

    • m_slotCnt 29 (पंक्तियों की संख्या)
    • m_freeCnt 5 (पृष्ठ पर बाइट्स की संख्या शेष है)
    • m_freeData 8129 (अर्थात डेटा + पेज हेडर - 8033 + 96 - स्लॉट एरे को "उपयोग" बाइट्स गणना में फैक्टर नहीं किया गया है)

हीप्स के बारे में

ढेर डेटा पृष्ठों को थोड़ा अलग तरीके से भरते हैं। वे पृष्ठ पर छोड़े गए अंतरिक्ष की मात्रा का बहुत मोटा अनुमान बनाए रखते हैं। जब बी सी सी उत्पादन को देखते हुए, के लिए पंक्ति को देखो: PAGE HEADER: Allocation Status PFS (1:1)। आपको (जब मैंने क्लस्टर्ड टेबल पर देखा था) या हीप टेबल को देखते हुए VALUEलाइनों को दिखाया जाएगा । यह प्रति लेनदेन का मूल्यांकन किया जाता है, इसलिए व्यक्तिगत आवेषण जैसे कि यहां किया जा रहा परीक्षण क्लस्टर्ड और हीप टेबल के बीच अलग-अलग परिणाम दिखा सकता है। हालाँकि, सभी 30 पंक्तियों के लिए एक ही DML ऑपरेशन करना, अपेक्षा के अनुसार ढेर भर देगा।0x60 MIXED_EXT ALLOCATED 0_PCT_FULL0x64 MIXED_EXT ALLOCATED 100_PCT_FULL

हालांकि, हीप्स के बारे में इन विवरणों में से कोई भी इस विशेष परीक्षण को सीधे प्रभावित नहीं करता है क्योंकि तालिका के दोनों संस्करण केवल 146 बाइट्स के साथ 30 पंक्तियों को फिट करते हैं। क्लस्टर्ड या हीप की परवाह किए बिना दूसरी पंक्ति के लिए पर्याप्त जगह नहीं है।

कृपया ध्यान रखें कि यह परीक्षा सरल है। एक पंक्ति के वास्तविक आकार की गणना विभिन्न कारकों के आधार पर बहुत जटिल हो सकती है, जैसे:, SPARSEडेटा संपीड़न, एलओबी डेटा, आदि।


डेटा पृष्ठ का विवरण देखने के लिए, निम्नलिखित प्रश्न का उपयोग करें:

DECLARE @PageID INT,
        @FileID INT,
        @DatabaseID SMALLINT = DB_ID();

SELECT  @FileID = alloc.[allocated_page_file_id],
        @PageID = alloc.[allocated_page_page_id]
FROM    sys.dm_db_database_page_allocations(@DatabaseID,
                            OBJECT_ID(N'dbo.TestStructure'), 1, NULL, 'DETAILED') alloc
WHERE   alloc.[previous_page_page_id] IS NULL -- first data page
AND     alloc.[page_type] = 1; -- DATA_PAGE

DBCC PAGE(@DatabaseID, @FileID, @PageID, 3) WITH TABLERESULTS;

** 14-बाइट "संस्करण जानकारी" मान मौजूद होगा यदि आपका डेटाबेस ALLOW_SNAPSHOT_ISOLATION ONया तो सेट है या READ_COMMITTED_SNAPSHOT ON


प्रति उपयोगकर्ता 8060 बाइट्स सटीक होने के लिए, उपयोगकर्ता डेटा के लिए उपलब्ध हैं। ओपी का डेटा अभी भी नीचे है।
रोजर वोल्फ

संस्करण की जानकारी नहीं है, अन्यथा 30 पंक्तियाँ 8310 बाइट्स लेती हैं। बाकी सब सही लग रहा है।
रोजर वुल्फ

@RogerWolf हाँ, "संस्करण जानकारी" है। और हां, 30 पंक्तियों के लिए 8310 बाइट्स की आवश्यकता होती है। यही कारण है कि उन 30 पंक्तियों में, वास्तव में, सभी 1 पेज में फिट नहीं होते हैं क्योंकि ओपी जो भी परीक्षण खरीद रहा है, उस पर विश्वास करने के लिए नेतृत्व किया जा रहा है। लेकिन वह परीक्षण खरीद गलत है। पृष्ठ पर केवल 29 पंक्तियाँ फिट हैं। मैंने इसकी पुष्टि की है (SQL Server 2012 का उपयोग करके भी)।
सोलोमन रटज़की

क्या आपने एक डेटाबेस पर अपना परीक्षण चलाने की कोशिश की है जो आरसीएसआई-सक्षम / नहीं है tempdb? मैं ओपी द्वारा प्रदान की गई सटीक संख्याओं को पुन: पेश करने में सक्षम था।
रोजर वुल्फ

@RogerWolf DB मैं उपयोग कर रहा हूँ RCSI- सक्षम नहीं है, लेकिन यह करने के लिए सेट है ALLOW_SNAPSHOT_ISOLATION। मैंने भी बस कोशिश की tempdbऔर देखा कि "संस्करण की जानकारी" नहीं है, इसलिए 30 पंक्तियाँ फिट हैं। मैं नई जानकारी जोड़ने के लिए अपडेट करूंगा।
सोलोमन रटज़की

3

डेटा पेज की वास्तविक संरचना काफी जटिल है। हालांकि यह आम तौर पर कहा जाता है कि उपयोगकर्ता डेटा के लिए प्रति पृष्ठ 8060 बाइट्स उपलब्ध हैं, कुछ अतिरिक्त ओवरहेड को कहीं भी नहीं गिना जाता है जिसके परिणामस्वरूप यह व्यवहार होता है।

हालाँकि, आपने देखा होगा कि SQL सर्वर वास्तव में आपको संकेत देता है कि 31 वीं पंक्ति पृष्ठ में फिट नहीं होगी। अगली पंक्ति के लिए एक ही पृष्ठ पर फिट होने के लिए, avg_page_space_used_in_percentमान 100% से नीचे होना चाहिए - (100/31) = 96.774194, और आपके मामले में यह ऊपर का रास्ता है।

पीएस मुझे विश्वास है कि मैंने कालेन डेलाने की "एसक्यूएल सर्वर इंटरनल्स" पुस्तकों में से एक में डेटा पेज संरचना के बाइट विवरण के नीचे देखा था, लेकिन यह लगभग 10 साल पहले था, इसलिए कृपया मुझे कोई और विवरण याद न करने के लिए बहाना दें। इसके अलावा, पृष्ठ संरचना संस्करण से संस्करण में बदल जाती है।


1
नहीं। यूनीकफायर केवल डुप्लिकेट कुंजी पंक्तियों में जोड़ा जाता है। प्रत्येक अद्वितीय कुंजी मान की पहली पंक्ति में अतिरिक्त 4 बाइट अद्वितीय नहीं है।
सोलोमन रटज़की

@ श्रुतस्की, स्पष्ट रूप से आप सही हैं। कभी नहीं सोचा था कि SQL सर्वर चर चौड़ाई कुंजी की अनुमति देगा। यह बदसूरत है। कुशल, हाँ, लेकिन बदसूरत।
रोजर वुल्फ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.