Please note that the following info is not intended to be a comprehensive
description of how data pages are laid out, such that one can calculate
the number of bytes used per any set of rows, as that is very complicated.
डेटा केवल 8k डेटा पृष्ठ पर स्थान लेने वाली चीज़ नहीं है:
आरक्षित स्थान है। आपको केवल 8192 बाइट्स में से 8060 का उपयोग करने की अनुमति है (यह 132 बाइट्स हैं जो आपकी पहली जगह में कभी नहीं थे):
- पृष्ठ शीर्ष लेख: यह ठीक 96 बाइट्स है।
- स्लॉट सरणी: यह प्रति पंक्ति 2 बाइट्स है और प्रत्येक पंक्ति को पृष्ठ पर शुरू होने की भरपाई का संकेत देता है। इस सरणी का आकार शेष 36 बाइट्स (132 - 96 = 36) तक सीमित नहीं है, अन्यथा आप केवल एक डेटा पेज पर अधिकतम 18 पंक्तियों को लगाने के लिए प्रभावी रूप से सीमित होंगे। इसका मतलब है कि प्रत्येक पंक्ति 2 बाइट्स से बड़ी है जितना आपको लगता है कि यह है। यह मान "रिकॉर्ड आकार" में शामिल नहीं है
DBCC PAGE
, जैसा कि रिपोर्ट किया गया है , यही वजह है कि इसे नीचे प्रति-पंक्ति जानकारी में शामिल किए जाने के बजाय यहां अलग रखा गया है।
- प्रति-पंक्ति मेटा-डेटा (सहित, लेकिन सीमित नहीं):
- आकार तालिका की परिभाषा (स्तंभों की संख्या, चर-लंबाई या निश्चित लंबाई, आदि) के आधार पर भिन्न होता है। @ पॉल व्हाईट और @ आरोन की टिप्पणियों से ली गई जानकारी जो इस उत्तर और परीक्षण से संबंधित चर्चा में पाई जा सकती है ।
- पंक्ति-शीर्षलेख: 4 बाइट्स, उनमें से 2 रिकॉर्ड प्रकार को दर्शाते हैं, और अन्य दो NULL बिटमैप के लिए एक ऑफसेट हैं
- कॉलम की संख्या: 2 बाइट्स
- पूर्ण बिटमैप: वर्तमान में कौन से कॉलम हैं
NULL
। 8 कॉलम के प्रत्येक सेट पर 1 बाइट। और सभी स्तंभों के लिए, यहां तक कि NOT NULL
लोगों के लिए भी । इसलिए, न्यूनतम 1 बाइट।
- चर-लंबाई स्तंभ ऑफ़सेट सरणी: 4 बाइट न्यूनतम। 2 बाइट्स चर-लंबाई स्तंभों की संख्या को रखने के लिए, और फिर प्रत्येक बाइट-लेंथ कॉलम के प्रति 2 बाइट्स जहां से शुरू होती है, उस पर होल्ड करने के लिए।
- संस्करण जानकारी: 14 बाइट्स (यह तब मौजूद होगा जब आपका डेटाबेस
ALLOW_SNAPSHOT_ISOLATION ON
या तो सेट हो गया हो या READ_COMMITTED_SNAPSHOT ON
)।
- कृपया इस पर अधिक विवरण के लिए निम्न प्रश्न और उत्तर देखें: स्लॉट अर्रे और कुल पृष्ठ का आकार
- कृपया पॉल रान्डेल से निम्नलिखित ब्लॉग पोस्ट देखें जिसमें डेटा पेज कैसे रखे गए हैं, इस बारे में कई दिलचस्प विवरण हैं: DBCC पेज के साथ पोकिंग (भाग 1?)
डेटा के लिए LOB संकेत जो पंक्ति में संग्रहीत नहीं है। ताकि DATALENGTH
+ के लिए खाता होगा । लेकिन ये एक मानक आकार के नहीं हैं। कृपया इस जटिल विषय पर जानकारी के लिए निम्नलिखित ब्लॉग पोस्ट देखें: (MAX) प्रकार जैसे वरचर, वरीनेन्सी, आदि के लिए LOB सूचक का आकार क्या है? । उस लिंक किए गए पोस्ट और कुछ अतिरिक्त परीक्षण के बीच , मैंने (डिफ़ॉल्ट) नियम निम्नानुसार होने चाहिए:
- विरासत / पदावनत LOB प्रकार है कि कोई भी (SQL सर्वर 2005 के रूप में अब और का उपयोग करना चाहिए
TEXT
, NTEXT
और IMAGE
):
- डिफ़ॉल्ट रूप से, हमेशा अपने डेटा को LOB पृष्ठों पर संग्रहीत करते हैं और हमेशा LOB संग्रहण के लिए 16-बाइट पॉइंटर का उपयोग करते हैं।
- यदि विकल्प सेट करने के लिए if sp_tableoption का उपयोग किया गया था
text in row
, तो:
- यदि मान को संग्रहीत करने के लिए पृष्ठ पर जगह है, और मान अधिकतम-पंक्ति आकार (256 के डिफ़ॉल्ट के साथ 24 - 7000 बाइट्स की विन्यास योग्य सीमा) से अधिक नहीं है, तो इसे इन-पंक्ति में संग्रहीत किया जाएगा;
- वरना यह 16-बाइट पॉइंटर होगा।
- नए LOB प्रकार एसक्यूएल सर्वर 2005 में शुरू के लिए (
VARCHAR(MAX)
, NVARCHAR(MAX)
, और VARBINARY(MAX)
):
- डिफ़ॉल्ट रूप से:
- यदि मूल्य 8000 बाइट्स से अधिक नहीं है, और पृष्ठ पर कमरा है, तो इसे इन-रो में संग्रहीत किया जाएगा।
- इनलाइन रूट - 8001 से 40,000 (वास्तव में 42,000) बाइट्स, अंतरिक्ष अनुमति के बीच डेटा के लिए, 1 से 5 पॉइंटर्स (24 - 72 बाइट्स) होंगे जो कि सीधे LOB पेज (ओं) को इंगित करते हैं। प्रारंभिक 8k LOB पेज के लिए 24 बाइट्स, और प्रत्येक अतिरिक्त 8k पेज पर 12 बाइट्स चार से अधिक 8k पेजों के लिए।
- TEXT_TREE - 42,000 बाइट्स के डेटा के लिए, या यदि 1 से 5 पॉइंटर्स-इन-रो फिट नहीं हो सकते हैं, तो LOB पेज (यानी "text_tree" पॉइंटर्स की सूची के शुरुआती पृष्ठ पर सिर्फ 24 बाइट पॉइंटर होगा। " पृष्ठ)।
- यदि विकल्प सेट करने के लिए sp_tableoption का उपयोग किया गया था
large value types out of row
, तो हमेशा LOB स्टोरेज के लिए 16-बाइट पॉइंटर का उपयोग करें।
- मैंने "डिफ़ॉल्ट" नियमों को कहा क्योंकि मैंने कुछ विशेषताओं जैसे डेटा संपीड़न, स्तंभ-स्तरीय एन्क्रिप्शन, पारदर्शी डेटा एन्क्रिप्शन, हमेशा एन्क्रिप्ट किए गए, आदि के प्रभाव में इन-पंक्ति मानों का परीक्षण नहीं किया था ।
LOB अतिप्रवाह पृष्ठ: यदि कोई मान 10k है, तो इसके लिए 1 पूर्ण 8k पृष्ठ अतिप्रवाह की आवश्यकता होगी, और फिर 2 पृष्ठ का भाग। यदि कोई अन्य डेटा शेष स्थान नहीं ले सकता है (या मुझे अनुमति नहीं है, तो मैं उस नियम के बारे में अनिश्चित हूं), तो आपके पास उस 2 LOB ओवरफ्लो डेटापेज पर "बर्बाद" अंतरिक्ष के 6kb लगभग है।
अप्रयुक्त स्थान: एक 8k डेटा पेज सिर्फ इतना है: 8192 बाइट्स। यह आकार में भिन्न नहीं होता है। इस पर रखा गया डेटा और मेटा-डेटा, हालांकि, सभी 8192 बाइट्स में हमेशा फिट नहीं होता है। और पंक्तियों को कई डेटा पृष्ठों पर विभाजित नहीं किया जा सकता है। इसलिए यदि आपके पास 100 बाइट्स शेष हैं, लेकिन कोई पंक्ति (या कोई पंक्ति जो उस स्थान में फिट नहीं होगी, कई कारकों पर निर्भर करता है) वहां फिट हो सकती है, डेटा पेज अभी भी 8192 बाइट्स ले रहा है, और आपकी दूसरी क्वेरी केवल संख्या की गिनती कर रही है डेटा पृष्ठ। आप इस मूल्य को दो स्थानों पर पा सकते हैं (बस ध्यान रखें कि इस मूल्य का कुछ हिस्सा उस आरक्षित स्थान की कुछ राशि है):
DBCC PAGE( db_name, file_id, page_id ) WITH TABLERESULTS;
के लिए देखो ParentObject
= "पृष्ठ हैडर:" और Field
= "m_freeCnt"। Value
क्षेत्र अप्रयुक्त बाइट्स की संख्या है।
SELECT buff.free_space_in_bytes FROM sys.dm_os_buffer_descriptors buff WHERE buff.[database_id] = DB_ID(N'db_name') AND buff.[page_id] = page_id;
यह "m_freeCnt" द्वारा रिपोर्ट की गई समान मान है। यह DBCC की तुलना में अधिक आसान है क्योंकि इसमें कई पृष्ठ मिल सकते हैं, लेकिन इसके लिए यह भी आवश्यक है कि पृष्ठों को पहले स्थान पर बफर पूल में पढ़ा गया हो।
FILLFACTOR
<100 द्वारा आरक्षित स्थान। नए बनाए गए पृष्ठ FILLFACTOR
सेटिंग का सम्मान नहीं करते हैं, लेकिन REBUILD करने से प्रत्येक डेटा पृष्ठ पर वह स्थान आरक्षित हो जाएगा। आरक्षित स्थान के पीछे विचार यह है कि इसका उपयोग गैर-अनुक्रमिक आवेषण और / या अपडेट द्वारा किया जाएगा जो पहले से ही पृष्ठ पर पंक्तियों के आकार का विस्तार करते हैं, चर लंबाई के स्तंभों को थोड़ा और डेटा के साथ अद्यतन किए जाने के कारण (लेकिन पर्याप्त नहीं है पेज-विभाजन)। लेकिन आप आसानी से डेटा पृष्ठों पर स्थान आरक्षित कर सकते हैं जो स्वाभाविक रूप से नई पंक्तियों को कभी नहीं प्राप्त करेंगे और मौजूदा पंक्तियों को कभी भी अपडेट नहीं किया जाएगा, या कम से कम इस तरह से अपडेट नहीं किया जाएगा जो पंक्ति के आकार को बढ़ाएगा।
पृष्ठ-विभाजन (विखंडन): पंक्ति को किसी स्थान पर जोड़ने की आवश्यकता है जिसमें पंक्ति के लिए कोई स्थान नहीं है, जिससे पृष्ठ विभाजन हो जाएगा। इस स्थिति में, मौजूदा डेटा का लगभग 50% एक नए पृष्ठ पर ले जाया जाता है और नई पंक्ति को 2 पृष्ठों में से एक में जोड़ा जाता है। लेकिन आपके पास अब थोड़ी अधिक खाली जगह है जिसका हिसाब नहीं है DATALENGTH
।
हटाने के लिए चिह्नित पंक्तियाँ। जब आप पंक्तियों को हटाते हैं, तो उन्हें हमेशा डेटा पेज से तुरंत हटा नहीं दिया जाता है। यदि उन्हें तुरंत हटाया नहीं जा सकता है, तो उन्हें "मौत के लिए चिह्नित" (स्टीवन सेगल संदर्भ) और भूत सफाई की प्रक्रिया के बाद शारीरिक रूप से हटा दिया जाएगा (मेरा मानना है कि यह नाम है)। हालाँकि, ये इस विशेष प्रश्न के लिए प्रासंगिक नहीं हो सकते हैं।
भूत पेज? निश्चित नहीं है कि क्या यह उचित शब्द है, लेकिन कभी-कभी डेटा पेज तब तक हटाए नहीं जाते हैं जब तक कि क्लस्टर सूचकांक का REBUILD नहीं किया जाता है। यह भी अधिक पृष्ठों के लिए खाते की तुलना में DATALENGTH
जोड़ देगा। यह आमतौर पर नहीं होना चाहिए, लेकिन मैं कई साल पहले एक बार इसमें चला गया था।
स्पार्स स्तंभ: स्पार्स स्तंभ उन तालिकाओं में स्थान (अधिकतर निश्चित लंबाई के डेटाटाइप्स) के लिए बचाते हैं जहां NULL
एक या अधिक कॉलम के लिए बड़ी% पंक्तियाँ होती हैं । SPARSE
विकल्प बनाता है NULL
अप 0 बाइट्स (सामान्य फिक्स्ड लंबाई राशि के बजाय, एक के लिए इस तरह के रूप 4 बाइट मान प्रकार INT
), लेकिन गैर-शून्य तय-लंबाई प्रकार के लिए एक अतिरिक्त 4 बाइट और के लिए एक चर राशि प्रत्येक ले महत्व देता है चर-लंबाई प्रकार। यहाँ समस्या यह है कि DATALENGTH
स्पार्स कॉलम में गैर-पूर्ण मानों के लिए अतिरिक्त 4 बाइट्स शामिल नहीं हैं, इसलिए उन 4 बाइट्स को वापस जोड़ने की आवश्यकता है। आप यह देखने के लिए देख सकते हैं कि क्या कोई SPARSE
कॉलम हैं:
SELECT OBJECT_SCHEMA_NAME(sc.[object_id]) AS [SchemaName],
OBJECT_NAME(sc.[object_id]) AS [TableName],
sc.name AS [ColumnName]
FROM sys.columns sc
WHERE sc.is_sparse = 1;
और फिर प्रत्येक SPARSE
कॉलम के लिए, मूल क्वेरी का उपयोग करने के लिए अपडेट करें:
SUM(DATALENGTH(FieldN) + 4)
कृपया ध्यान दें कि मानक 4 बाइट्स में जोड़ने के लिए ऊपर की गणना थोड़ी सरल है क्योंकि यह केवल निश्चित लंबाई के प्रकारों के लिए काम करता है। और, प्रति पंक्ति अतिरिक्त मेटा-डेटा है (जो मैं अभी तक बता सकता हूं) जो डेटा के लिए उपलब्ध स्थान को कम कर देता है, बस कम से कम एक स्पार्स कॉलम होने से। अधिक जानकारी के लिए, कृपया उपयोग विरल कॉलम के लिए MSDN पृष्ठ देखें ।
सूचकांक और अन्य (जैसे IAM, PFS, GAM, SGAM, आदि) पृष्ठ: ये उपयोगकर्ता डेटा के संदर्भ में "डेटा" पृष्ठ नहीं हैं। ये तालिका के कुल आकार को बढ़ाएँगे। यदि SQL Server 2012 या नए का उपयोग कर रहे हैं, तो आप sys.dm_db_database_page_allocations
पृष्ठ प्रकार (SQL सर्वर के पुराने संस्करण उपयोग कर सकते हैं DBCC IND(0, N'dbo.table_name', 0);
) को देखने के लिए डायनेमिक मैनेजमेंट फ़ंक्शन (DMF) का उपयोग कर सकते हैं :
SELECT *
FROM sys.dm_db_database_page_allocations(
DB_ID(),
OBJECT_ID(N'dbo.table_name'),
1,
NULL,
N'DETAILED'
)
WHERE page_type = 1; -- DATA_PAGE
न तो और DBCC IND
न ही sys.dm_db_database_page_allocations
(उस WHERE क्लॉज के साथ) कोई भी इंडेक्स पेज रिपोर्ट करेगा, और केवल DBCC IND
कम से कम एक IAM पेज रिपोर्ट करेगा।
DATA_COMPRESSION: यदि आपने क्लस्टर इंडेक्स या हीप पर सक्षम ROW
या PAGE
कंप्रेशन को सक्षम किया है, तो आप अभी तक उल्लेखित अधिकांश बातों के बारे में भूल सकते हैं। 96 बाइट पेज हैडर, 2 बाइट्स-प्रति-पंक्ति स्लॉट ऐरे, और 14 बाइट्स-प्रति-पंक्ति संस्करण जानकारी अभी भी हैं, लेकिन डेटा का भौतिक प्रतिनिधित्व अत्यधिक जटिल हो जाता है (पहले से उल्लिखित पहले की तुलना में बहुत अधिक) उपयोग नहीं किया जा रहा है)। उदाहरण के लिए, रो संपीड़न के साथ, SQL सर्वर प्रत्येक पंक्ति में, प्रत्येक कॉलम को फिट करने के लिए सबसे छोटे संभव कंटेनर का उपयोग करने का प्रयास करता है। इसलिए यदि आपके पास एक BIGINT
कॉलम है जो अन्यथा होगा (यह मानते हुए SPARSE
भी सक्षम नहीं है) हमेशा 8 बाइट्स लें, यदि मूल्य -128 और 127 (यानी 8-बिट पूर्णांक पर हस्ताक्षर किए गए) के बीच है, तो यह सिर्फ 1 बाइट का उपयोग करेगा, और यदि 8 मान एक में फिट हो सकता हैSMALLINT
, यह केवल 2 बाइट्स लेगा। पूर्णांक प्रकार जो NULL
या तो 0
कोई स्थान नहीं लेते हैं और स्तंभों को मैप करने वाले एक सरणी में बस NULL
"रिक्त" (यानी 0
) होने के रूप में इंगित किए जाते हैं। और कई, कई अन्य नियम हैं। यूनिकोड डेटा ( NCHAR
और NVARCHAR(1 - 4000)
, लेकिन नहीं NVARCHAR(MAX)
, भले ही इन-रो संग्रहीत)? यूनिकोड संपीड़न को SQL सर्वर 2008 R2 में जोड़ा गया था, लेकिन नियमों की जटिलता को देखते हुए वास्तविक संपीड़न किए बिना सभी स्थितियों में "संपीड़ित" मूल्य के परिणाम की भविष्यवाणी करने का कोई तरीका नहीं है ।
तो वास्तव में, आपकी दूसरी क्वेरी, जबकि डिस्क पर लिए गए कुल भौतिक स्थान के संदर्भ में अधिक सटीक है, केवल REBUILD
क्लस्टर्ड इंडेक्स के करने पर वास्तव में सटीक है । और उसके बाद, आपको अभी भी FILLFACTOR
100 से नीचे किसी भी सेटिंग के लिए खाते की आवश्यकता है। और फिर भी हमेशा पेज हेडर होते हैं, और अक्सर पर्याप्त मात्रा में "बर्बाद" जगह होती है जो किसी भी पंक्ति को फिट करने के लिए बहुत छोटा होने के कारण बस भरने योग्य नहीं होती है। तालिका, या कम से कम पंक्ति जो तार्किक रूप से उस स्लॉट में जानी चाहिए।
"डेटा उपयोग" का निर्धारण करने में दूसरी क्वेरी की सटीकता के बारे में, पृष्ठ हैडर बाइट्स का बैक-आउट करना सबसे उचित लगता है क्योंकि वे डेटा उपयोग नहीं हैं: वे लागत-से-व्यवसाय ओवरहेड हैं। यदि किसी डेटा पृष्ठ पर 1 पंक्ति है और वह पंक्ति सिर्फ एक है TINYINT
, तो उस 1 बाइट को अभी भी आवश्यक है कि डेटा पेज मौजूद था और इसलिए हेडर के 96 बाइट्स। क्या पूरे डेटा पृष्ठ के लिए 1 विभाग को शुल्क देना चाहिए? यदि उस डेटा पृष्ठ को विभाग # 2 द्वारा भरा जाता है, तो क्या वे समान रूप से उस "ओवरहेड" लागत को विभाजित करेंगे या आनुपातिक रूप से भुगतान करेंगे? लगता है सबसे आसान बस इसे वापस करने के लिए। किस मामले में, के 8
विरुद्ध गुणा करने के मूल्य का उपयोग number of pages
बहुत अधिक है। कैसा रहेगा:
-- 8192 byte data page - 96 byte header = 8096 (approx) usable bytes.
SELECT 8060.0 / 1024 -- 7.906250
इसलिए, कुछ का उपयोग करें:
(SUM(a.total_pages) * 7.91) / 1024 AS [TotalSpaceMB]
"नंबर_ऑफ_पेज" कॉलम के खिलाफ सभी गणनाओं के लिए।
और , यह विचार करते हुए कि DATALENGTH
प्रत्येक क्षेत्र का उपयोग करके प्रति पंक्ति मेटा-डेटा वापस नहीं किया जा सकता है, जिसे आपकी प्रति-तालिका क्वेरी में जोड़ा जाना चाहिए, जहां आपको DATALENGTH
प्रत्येक "विभाग" पर फ़िल्टर करते हुए प्रत्येक फ़ील्ड मिलता है :
- रिकॉर्ड प्रकार और नल बिटमैप को ऑफसेट: 4 बाइट्स
- कॉलम गणना: 2 बाइट्स
- स्लॉट ऐरे: 2 बाइट्स ("रिकॉर्ड आकार" में शामिल नहीं है, लेकिन फिर भी इसके लिए खाता होना चाहिए)
- पूर्ण बिटमैप: प्रत्येक 8 कॉलम के लिए 1 बाइट ( सभी कॉलम के लिए)
- पंक्ति संशोधन: 14 बाइट (डेटाबेस या तो है, तो
ALLOW_SNAPSHOT_ISOLATION
या READ_COMMITTED_SNAPSHOT
करने के लिए सेट ON
)
- वैरिएबल-लेंथ कॉलम ऑफसेट एरे: 0 बाइट्स यदि सभी कॉलम फिक्स्ड-लेंथ हैं। यदि कोई कॉलम परिवर्तनशील-लंबाई वाला है, तो 2 बाइट्स, प्लस 2 बाइट्स केवल प्रत्येक चर-लंबाई वाले कॉलम हैं।
- LOB पॉइंटर्स: यह हिस्सा बहुत इंप्रेसिव है क्योंकि वैल्यू होने पर कोई पॉइंटर नहीं होगा
NULL
, और अगर वैल्यू रो पर फिट होती है तो यह पॉइंटर की तुलना में बहुत छोटा या बहुत बड़ा हो सकता है, और अगर वैल्यू को स्टोर किया जाता है- पंक्ति, तो पॉइंटर का आकार इस बात पर निर्भर हो सकता है कि कितना डेटा है। हालाँकि, जब से हम सिर्फ एक अनुमान (यानी "स्वैग") चाहते हैं, ऐसा लगता है कि 24 बाइट्स का उपयोग करने के लिए एक अच्छा मूल्य है (अच्छी तरह से, किसी भी अन्य के रूप में अच्छा ;-)। यह प्रत्येक MAX
क्षेत्र है।
इसलिए, कुछ का उपयोग करें:
सामान्य तौर पर (पंक्ति शीर्षलेख + स्तंभों की संख्या + स्लॉट सरणी + NULL बिटमैप):
([RowCount] * (( 4 + 2 + 2 + (1 + (({NumColumns} - 1) / 8) ))
सामान्य तौर पर (यदि "संस्करण की जानकारी" मौजूद है तो ऑटो-डिटेक्ट करें):
+ (SELECT CASE WHEN snapshot_isolation_state = 1 OR is_read_committed_snapshot_on = 1
THEN 14 ELSE 0 END FROM sys.databases WHERE [database_id] = DB_ID())
यदि कोई चर-लंबाई वाले स्तंभ हैं, तो जोड़ें:
+ 2 + (2 * {NumVariableLengthColumns})
यदि कोई MAX
/ LOB कॉलम हैं, तो जोड़ें:
+ (24 * {NumLobColumns})
सामान्य रूप में:
)) AS [MetaDataBytes]
यह सटीक नहीं है, और फिर से काम नहीं करेगा यदि आपके पास हीप या क्लस्टर इंडेक्स पर सक्षम पंक्ति या पृष्ठ संपीड़न है, लेकिन निश्चित रूप से आपको पास होना चाहिए।
अद्यतन 15% अंतर रहस्य के बारे में
हम (स्वयं शामिल हैं) यह सोचने पर केंद्रित थे कि डेटा पृष्ठ कैसे रखे जाते हैं और DATALENGTH
उन चीज़ों के लिए कैसे हिसाब- किताब किया जा सकता है जिन्हें हमने 2 जी क्वेरी की समीक्षा किए बहुत समय व्यतीत नहीं किया। मैंने उस क्वेरी को एक ही टेबल के खिलाफ चलाया और फिर उन मूल्यों की तुलना की, जिनके द्वारा रिपोर्ट की जा रही थी sys.dm_db_database_page_allocations
और वे पृष्ठों की संख्या के लिए समान मान नहीं थे। कूबड़ पर, मैंने कुल कार्यों को हटा दिया और GROUP BY
, और SELECT
सूची को बदल दिया a.*, '---' AS [---], p.*
। और फिर यह स्पष्ट हो गया: लोगों को सावधान रहना चाहिए, जहां इन घिनौने अंतराल पर उन्हें अपनी जानकारी और स्क्रिप्ट ;-); प्रश्न में पोस्ट की गई 2 क्वेरी बिल्कुल सही नहीं है, विशेष रूप से इस विशेष प्रश्न के लिए।
छोटी समस्या: इसके बाहर GROUP BY rows
(और एक समग्र कार्य में उस स्तंभ का नहीं होना) से कोई मतलब नहीं है, जो बीच में है sys.allocation_units
और sys.partitions
तकनीकी रूप से सही नहीं है। आवंटन इकाइयों के 3 प्रकार हैं, और उनमें से एक को एक अलग क्षेत्र में शामिल होना चाहिए। अक्सर partition_id
और hobt_id
समान होते हैं, इसलिए कभी कोई समस्या नहीं हो सकती है, लेकिन कभी-कभी उन दो क्षेत्रों में अलग-अलग मूल्य होते हैं।
प्रमुख समस्या: क्वेरी used_pages
फ़ील्ड का उपयोग करती है । वह क्षेत्र सभी प्रकार के पृष्ठों को कवर करता है : डेटा, इंडेक्स, आईएएम, आदि, टीसी। केवल वास्तविक डेटा से संबंधित होने पर उपयोग करने के लिए एक और, अधिक उपयुक्त क्षेत्र है data_pages
:।
मैंने उपरोक्त मदों के साथ प्रश्न में 2 की क्वेरी को ध्यान में रखते हुए, और पृष्ठ शीर्ष लेख का समर्थन करने वाले डेटा पृष्ठ आकार का उपयोग किया। मैंने दो JOIN को भी हटा दिया जो अनावश्यक थे: sys.schemas
(कॉल के साथ बदल दिया गया SCHEMA_NAME()
), और sys.indexes
(Clustered Index is always index_id = 1
and we have index_id
in sys.partitions
)।
SELECT SCHEMA_NAME(st.[schema_id]) AS [SchemaName],
st.[name] AS [TableName],
SUM(sp.[rows]) AS [RowCount],
(SUM(sau.[total_pages]) * 8.0) / 1024 AS [TotalSpaceMB],
(SUM(CASE sau.[type]
WHEN 1 THEN sau.[data_pages]
ELSE (sau.[used_pages] - 1) -- back out the IAM page
END) * 7.91) / 1024 AS [TotalActualDataMB]
FROM sys.tables st
INNER JOIN sys.partitions sp
ON sp.[object_id] = st.[object_id]
INNER JOIN sys.allocation_units sau
ON ( sau.[type] = 1
AND sau.[container_id] = sp.[partition_id]) -- IN_ROW_DATA
OR ( sau.[type] = 2
AND sau.[container_id] = sp.[hobt_id]) -- LOB_DATA
OR ( sau.[type] = 3
AND sau.[container_id] = sp.[partition_id]) -- ROW_OVERFLOW_DATA
WHERE st.is_ms_shipped = 0
--AND sp.[object_id] = OBJECT_ID(N'dbo.table_name')
AND sp.[index_id] < 2 -- 1 = Clustered Index; 0 = Heap
GROUP BY SCHEMA_NAME(st.[schema_id]), st.[name]
ORDER BY [TotalSpaceMB] DESC;