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.
8 কে ডেটা পৃষ্ঠায় ডেটা কেবল স্থান গ্রহণ করে না:
সংরক্ষিত জায়গা আছে। আপনি কেবল 8192 বাইটের 8060 ব্যবহারের অনুমতি পেয়েছেন (এটি ১৩২ বাইট যা আগে কখনও আপনার ছিল না):
- পৃষ্ঠার শিরোনাম: এটি ঠিক 96 বাইট।
- স্লট অ্যারে: এটি প্রতি সারি 2 বাইট এবং এটি পৃষ্ঠার প্রতিটি সারি শুরু হওয়ার অফসেট নির্দেশ করে। এই অ্যারের আকারটি বাকি 36 বাইট (132 - 96 = 36) এর মধ্যে সীমাবদ্ধ নয়, অন্যথায় আপনি কার্যকরভাবে কেবলমাত্র একটি ডেটা পৃষ্ঠায় 18 সারি সর্বাধিক স্থাপনের মধ্যে সীমাবদ্ধ থাকবেন। এর অর্থ হ'ল প্রতিটি সারিটি আপনি যা ভাবেন তার চেয়ে 2 বাইট বড়। এই মানটি উল্লিখিত হিসাবে "রেকর্ড আকারে" অন্তর্ভুক্ত করা হয়নি
DBCC PAGE
, এজন্য নীচে প্রতি-সারি তথ্যের মধ্যে অন্তর্ভুক্ত না করে এটিকে এখানে আলাদা রাখা হয়েছে।
- প্রতি-সারি মেটা-ডেটা (সহ, তবে সীমাবদ্ধ নয়):
- আকারটি টেবিলের সংজ্ঞা অনুসারে পরিবর্তিত হয় (যেমন কলামগুলির সংখ্যা, ভেরিয়েবল-দৈর্ঘ্য বা স্থির দৈর্ঘ্য ইত্যাদি) depending @ পলওয়াট এবং @ হারুনের মন্তব্যগুলি থেকে নেওয়া তথ্য যা এই উত্তর এবং পরীক্ষার সাথে সম্পর্কিত আলোচনায় পাওয়া যাবে ।
- সারি-শিরোলেখ: 4 বাইট, তাদের মধ্যে 2 রেকর্ড টাইপটি বোঝায় এবং অন্য দুটি নাল বিটম্যাপের অফসেট
- কলামের সংখ্যা: 2 বাইট
- নুল বিটম্যাপ: বর্তমানে কলামগুলি রয়েছে
NULL
। 8 টি কলামের প্রতিটি সেট 1 বাইট। এবং সমস্ত কলামের জন্য, এমনকিNOT NULL
। সুতরাং, সর্বনিম্ন 1 বাইট।
- পরিবর্তনশীল-দৈর্ঘ্যের কলাম অফসেট অ্যারে: সর্বনিম্ন 4 বাইট। ভেরিয়েবল-দৈর্ঘ্যের কলামগুলির সংখ্যা ধরে রাখতে 2 বাইট এবং তারপরে যেখানে অফসেটটি শুরু হয় সেখানে ধরে রাখতে প্রতিটি ভেরিয়েবল-দৈর্ঘ্যের কলামে 2 বাইট
- সংস্করণ তথ্য: 14 বাইট (আপনার ডেটাবেস দুটি
ALLOW_SNAPSHOT_ISOLATION ON
বা সেট করা থাকলে এটি উপস্থিত থাকবে READ_COMMITTED_SNAPSHOT ON
)।
- এই বিষয়ে আরও তথ্যের জন্য দয়া করে নীচের প্রশ্নোত্তর দেখুন: স্লট অ্যারে এবং মোট পৃষ্ঠার আকার
- দয়া করে পল রান্ডাল এর নীচের ব্লগ পোস্টটি দেখুন যাতে ডেটা পৃষ্ঠাগুলি কীভাবে সাজানো হয় সে সম্পর্কে বেশ কয়েকটি আকর্ষণীয় বিশদ রয়েছে: ডিবিসিসি পৃষ্ঠায় পোকার করা (এর অংশ 1?)
সারিবদ্ধভাবে সংরক্ষণ করা হয় না এমন ডেটার জন্য এলওবি পয়েন্টার। সুতরাং যে অ্যাকাউন্টের জন্য DATALENGTH
+ পয়েন্টার_ আকার। তবে এগুলি মানক আকারের নয়। এই জটিল বিষয় সম্পর্কে বিস্তারিত জানার জন্য নীচের ব্লগ পোস্টটি দেখুন: বর্ণাচার, ভারবাইনারি, ইত্যাদি এর মতো (ম্যাক্স) ধরণের এলওবি পয়েন্টারের আকার কী? । সেই লিঙ্কযুক্ত পোস্ট এবং কিছু অতিরিক্ত টেস্টিংয়ের মধ্যে (ডিফল্ট) বিধিগুলি নীচে হওয়া উচিত:
- উত্তরাধিকার / অবচিত lob ধরনের যে কেউ কিছু (SQL সার্ভার 2005 হিসাবে আর ব্যবহার করা উচিত
TEXT
, NTEXT
এবং IMAGE
):
- ডিফল্টরূপে, সর্বদা LOB পৃষ্ঠাগুলিতে তাদের ডেটা সঞ্চয় করুন এবং সর্বদা LOB স্টোরেজে 16 বাইট পয়েন্টার ব্যবহার করুন।
- যদি sp_tableoption টি সেট করতে ব্যবহৃত হত
text in row
বিকল্পটি , তবে:
- যদি পৃষ্ঠায় মানটি সঞ্চয় করার জন্য জায়গা থাকে এবং মানটি সর্বাধিক ইন-সারি আকারের (256 এর ডিফল্ট সহ কনফিগারযোগ্য 24 - 7000 বাইট) এর চেয়ে বড় না হয়, তবে এটি সারি-এ সংরক্ষণ করা হবে,
- অন্যথায় এটি 16 বাইট পয়েন্টার হবে।
- নতুন lob ধরনের SQL সার্ভার 2005 সালে চালু জন্য (
VARCHAR(MAX)
, NVARCHAR(MAX)
, এবং VARBINARY(MAX)
):
- গতানুগতিক:
- যদি মান চেয়ে বড় 8000 বাইট নয়, এবং পৃষ্ঠাতে স্থান নেই, তাহলে এটি ইন-সারি সংরক্ষণ করা হবে।
- ইনলাইন রুট - 8001 থেকে 40,000 (সত্যই 42,000) বাইট, স্পেস অনুমতি সহ ডেটাগুলির জন্য, সেখানে ROW এ 1 থেকে 5 পয়েন্টার (24 - 72 বাইট) থাকবে যা সরাসরি এলওবি পৃষ্ঠায় (গুলি) যাবে। প্রাথমিক 8 কে এলওবি পৃষ্ঠার জন্য 24 বাইট, এবং আরও 4 কে 8 পৃষ্ঠার প্রতিটি অতিরিক্ত 8 কে পৃষ্ঠায় 12 বাইট
- TEXT_TREE - ৪২,০০০ বাইটের বেশি ডেটার জন্য, বা যদি 1 থেকে 5 পয়েন্টার সারি-সারি ফিট না করতে পারে তবে LOB পৃষ্ঠাগুলিতে পয়েন্টারগুলির তালিকার প্রারম্ভিক পৃষ্ঠায় কেবল 24 বাইট পয়েন্টার থাকবে (যেমন "পাঠ্য_ট্রি "পৃষ্ঠা)।
- IF sp_tableoption
large value types out of row
বিকল্পটি সেট করতে ব্যবহৃত হয় , তারপরে সর্বদা LOB স্টোরেজে 16 বাইট পয়েন্টার ব্যবহার করুন।
- আমি "ডিফল্ট" বিধি বলেছিলাম কারণ আমি ডেটা সংক্ষেপণ, কলাম-স্তরের এনক্রিপশন, স্বচ্ছ ডেটা এনক্রিপশন, সর্বদা এনক্রিপ্ট ইত্যাদির মতো নির্দিষ্ট বৈশিষ্ট্যের প্রভাবের বিরুদ্ধে সারি মানগুলি পরীক্ষা করি নি not
এলওবি ওভারফ্লো পৃষ্ঠাগুলি: যদি কোনও মান 10 কে হয় তবে তার জন্য প্রয়োজন 1 টি 8k পৃষ্ঠার ওভারফ্লো এবং তারপরে ২ য় পৃষ্ঠার অংশ। যদি অন্য কোনও ডেটা অবশিষ্ট স্থান নিতে না পারে (বা এমনকি অনুমতি দেওয়া হয় তবে আমি সেই নিয়ম সম্পর্কে অনিশ্চিত), তবে আপনার কাছে ২ য় এলওবি ওভারফ্লো ডেটাপেজে প্রায় 6kb "নষ্ট" স্থান রয়েছে।
অব্যবহৃত স্থান: একটি 8 কে ডেটা পৃষ্ঠাটি ঠিক এটি: 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" দ্বারা প্রতিবেদন করা একই মান। এটি ডিবিসিসির চেয়ে সহজ কারণ এটি অনেক পৃষ্ঠা পেতে পারে তবে এটিরও প্রয়োজন যে পৃষ্ঠাগুলি প্রথমে বাফার পুলে পড়ে।
স্থানটি FILLFACTOR
<100 দ্বারা সংরক্ষিত FILLFACTOR
New সংরক্ষিত জায়গার পিছনে ধারণাটি হ'ল এটি অ-অনুক্রমিক সন্নিবেশ এবং / অথবা আপডেটগুলির দ্বারা ব্যবহৃত হবে যা ইতিমধ্যে পৃষ্ঠায় সারিগুলির আকার প্রসারিত করে, ভেরিয়েবল দৈর্ঘ্যের কলামগুলি আরও কিছু ডেটা দিয়ে আপডেট করা হয়েছে (তবে এটির কারণ হওয়ার পক্ষে যথেষ্ট নয়) পৃষ্ঠা-বিভক্ত)। তবে আপনি সহজেই ডেটা পৃষ্ঠাগুলিতে স্থান সংরক্ষণ করতে পারবেন যা প্রাকৃতিকভাবে কখনই নতুন সারি পায় না এবং বিদ্যমান সারিগুলি কখনই আপডেট হয় না বা কমপক্ষে এমনভাবে আপডেট করা হয় না যা সারিটির আকার বাড়িয়ে তুলবে।
পৃষ্ঠা-বিভাজক (বিভাজন): সারিটির কোনও স্থান নেই এমন একটি স্থানে একটি সারি যুক্ত করার প্রয়োজন হলে পৃষ্ঠার বিভাজন ঘটবে। এই ক্ষেত্রে, বিদ্যমান উপাত্তের প্রায় 50% একটি নতুন পৃষ্ঠায় সরানো হয়েছে এবং নতুন সারিটি 2 পৃষ্ঠার একটিতে যুক্ত করা হয়েছে। তবে এখন আপনার কাছে আরও খানিকটা মুক্ত স্থান রয়েছে যা DATALENGTH
গণনা অনুসারে গণ্য হয় না ।
সারি মুছে ফেলার জন্য চিহ্নিত করা হয়েছে। আপনি যখন সারিগুলি মুছবেন তখন সেগুলি ডেটা পৃষ্ঠা থেকে তাত্ক্ষণিকভাবে সরানো হয় না। যদি তাদের তাত্ক্ষণিকভাবে অপসারণ করা না যায় তবে এগুলি "মৃত্যুর জন্য চিহ্নিত" (স্টিভেন সেগাল রেফারেন্স) এবং পরে ভূত পরিষ্কারের প্রক্রিয়া দ্বারা শারীরিকভাবে অপসারণ করা হবে (আমি বিশ্বাস করি যে এটিই নাম)। তবে এগুলি এই বিশেষ প্রশ্নের সাথে প্রাসঙ্গিক নাও হতে পারে।
ভুতের পৃষ্ঠা? এটি সঠিক শব্দটি কিনা তা নিশ্চিত নন তবে কখনও কখনও ক্লাস্টারড ইনডেক্সের পুনরায় বিল্ডিং না করা পর্যন্ত ডেটা পৃষ্ঠাগুলি মুছে ফেলা হয় না। এটি এতে DATALENGTH
যোগ করার চেয়ে আরও বেশি পৃষ্ঠাগুলির জন্য অ্যাকাউন্ট করবে। এটি সাধারণত হওয়া উচিত নয়, তবে আমি বেশ কয়েক বছর আগে একবার এটিতে প্রবেশ করেছি।
স্পারস কলাম: সারণীর বৃহত%% NULL
এক বা একাধিক কলামের জন্য সারণির ফাঁকে ফাঁকে ফাঁকে ফাঁকে ফাঁকে ফাঁকে ফাঁকে ফাঁকে কলামগুলি (বেশিরভাগ স্থির দৈর্ঘ্যের ডেটাটাইপগুলির জন্য) সংরক্ষণ করে । SPARSE
বিকল্প তোলে NULL
আপ 0 বাইটের (স্বাভাবিক সংশোধন দৈর্ঘ্যের পরিমাণ পরিবর্তে, একটি জন্য যেমন 4 বাইট মান টাইপ INT
), কিন্তু , অ-শূন্য আপ সংশোধন করা দৈর্ঘ্যের ধরনের জন্য একটি অতিরিক্ত 4 বাইট এবং জন্য একটি পরিবর্তনশীল পরিমাণ প্রতিটি নিতে মান পরিবর্তনশীল দৈর্ঘ্যের প্রকার। এখানে সমস্যাটি হ'ল DATALENGTH
একটি স্পারস কলামে নন-নুল মানগুলির জন্য অতিরিক্ত 4 বাইট অন্তর্ভুক্ত নয়, সুতরাং সেই 4 বাইটগুলি আবার যুক্ত করতে হবে SPARSE
via এখানে কোনও কলাম রয়েছে কিনা তা পরীক্ষা করে দেখতে পারেন :
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 বাইট যোগ করার জন্য উপরের গণনাটি কিছুটা সরলতর কারণ এটি কেবল স্থির দৈর্ঘ্যের ধরণের ক্ষেত্রেই কাজ করে। এবং, সারি প্রতি অতিরিক্ত মেটা-ডেটা রয়েছে (যা আমি এতদূর বলতে পারি) যা কমপক্ষে একটি স্পারস কলাম রেখে কেবল ডেটার জন্য উপলব্ধ স্থান হ্রাস করে। আরও বিশদের জন্য দয়া করে স্পার্স কলামগুলি ব্যবহারের জন্য এমএসডিএন পৃষ্ঠা দেখুন ।
সূচক এবং অন্যান্য (যেমন আইএএম, পিএফএস, গ্যাম, এসজিএএম, ইত্যাদি) পৃষ্ঠা: এটি ব্যবহারকারীর তথ্যের ক্ষেত্রে "ডেটা" পৃষ্ঠা নয়। এগুলি টেবিলের মোট আকার বাড়িয়ে দেবে। যদি এসকিউএল সার্ভার 2012 বা নতুন ব্যবহার করে থাকে sys.dm_db_database_page_allocations
তবে আপনি পৃষ্ঠার প্রকারগুলি দেখতে এসএমএল সার্ভারের পূর্ববর্তী সংস্করণগুলি ব্যবহার করতে ডায়নামিক ম্যানেজমেন্ট ফাংশন (ডিএমএফ) ব্যবহার করতে পারেন DBCC IND(0, N'dbo.table_name', 0);
:
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
(যেটির সাথে এই ধারাটি রয়েছে) কোনও সূচী পৃষ্ঠার DBCC IND
প্রতিবেদন করবে না এবং কেবলমাত্র কমপক্ষে একটি আইএএম পৃষ্ঠার প্রতিবেদন করবে।
DATA_COMPRESSION: আপনি যদি ROW
বা PAGE
কম্প্রেশন ক্লাস্টার ইনডেক্স বা গাদা সক্রিয়, তাহলে আপনি এতদূর কারণ বলা হয়েছে তা অধিকাংশ ভুলে যেতে পারেন। 96 বাইট পেজ শিরোলেখ, 2-বাইট-প্রতি-সারি স্লট অ্যারে এবং 14 বাইট-প্রতি-সারি সংস্করণ তথ্য এখনও রয়েছে, তবে ডেটার শারীরিক উপস্থাপনা অত্যন্ত জটিল হয়ে ওঠে (যখন কম্প্রেশন হওয়ার সময় ইতিমধ্যে উল্লিখিত হয়েছে তার চেয়ে অনেক বেশি ব্যবহার করা হচ্ছে না)। উদাহরণস্বরূপ, সারি সংক্ষেপণের সাথে, এসকিউএল সার্ভার প্রতিটি কলামে প্রতিটি কলামের সাথে ফিট করার জন্য ক্ষুদ্রতম সম্ভাব্য ধারকটি ব্যবহার করার চেষ্টা করে। তাই আপনি যদি একটি আছে BIGINT
কলাম হবে যা অন্যথায় (অভিমানীSPARSE
নেওয়াও সক্ষম নয়) সর্বদা 8 বাইট নেয়, যদি মানটি -128 এবং 127 (অর্থাত্ স্বাক্ষরিত 8-বিট পূর্ণসংখ্যা) এর মধ্যে হয় তবে এটি কেবল 1 বাইট ব্যবহার করবে, এবং যদি মান একটি মধ্যে মাপসই করতে পারেSMALLINT
, এটি কেবল 2 বাইট লাগবে। পূর্ণসংখ্যা ধরনের যে হয় হয় NULL
বা 0
কোন জায়গা নিয়ে কেবল হচ্ছে নির্দেশিত হয় NULL
অথবা "খালি" (অর্থাত0
) কলামগুলি ম্যাপিংয়ের একটি অ্যারেতে। এবং অন্যান্য অনেকগুলি বিধি রয়েছে। ইউনিকোড ডেটা আছে ( NCHAR
, NVARCHAR(1 - 4000)
তবে না NVARCHAR(MAX)
, এমনকি যদি সারি-তে সঞ্চিত থাকে)? ইউনিকোড সংক্ষেপণ এসকিউএল সার্ভার ২০০৮ আর 2 এ যুক্ত করা হয়েছিল, তবে নিয়মের জটিলতার কারণে প্রকৃত সংকোচন না করে সব পরিস্থিতিতে "সংকুচিত" মানের ফলাফলের পূর্বাভাস দেওয়ার কোনও উপায় নেই ।
সুতরাং প্রকৃতপক্ষে, আপনার দ্বিতীয় প্রশ্নটি যখন ডিস্কে নেওয়া মোট শারীরিক জায়গার ক্ষেত্রে আরও সঠিক REBUILD
, তবে ক্লাস্টারড ইনডেক্সের কোনও কিছু করার ক্ষেত্রে সত্যই সঠিক । এবং এর পরে, আপনার এখনও FILLFACTOR
100 এর নীচে যে কোনও সেটিংয়ের জন্য অ্যাকাউন্টিং করতে হবে And এবং তারপরেও সর্বদা পৃষ্ঠার শিরোনাম থাকে এবং প্রায়শই যথেষ্ট পরিমাণ "নষ্ট" স্থান থাকে যা কোনওরকম সারি ফিট করার পক্ষে খুব ছোট হওয়ার কারণে কেবল পরিস্ফুট নয় simply টেবিল, বা কমপক্ষে সারিটি যা যুক্তিযুক্তভাবে সেই স্লটে যেতে হবে।
"ডেটা ব্যবহার" নির্ধারণের ক্ষেত্রে ২ য় ক্যোয়ারের যথার্থতা সম্পর্কে, পৃষ্ঠা শিরোনাম বাইটগুলি ডেটা ব্যবহার না করার কারণে এটি ব্যাক-আউট করা সবচেয়ে সুষ্ঠু বলে মনে হচ্ছে: এগুলি ব্যবসায়ের ওভারহেড। যদি কোনও ডেটা পৃষ্ঠায় 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]
"number_of_pages" কলামগুলির বিরুদ্ধে সমস্ত গণনার জন্য।
এবং বিবেচনা করে যে DATALENGTH
প্রতি ক্ষেত্র প্রতি ব্যবহার করে প্রতি সারি মেটা ডেটা ফেরত দিতে পারে না, এটি আপনার প্রতি-টেবিল ক্যোয়ারিতে যুক্ত করা উচিত যেখানে আপনি DATALENGTH
প্রতিটি ক্ষেত্রের জন্য প্রতি পাবেন , প্রতিটি "বিভাগে" ফিল্টার করে:
- রেকর্ড টাইপ করুন এবং নুল বিটম্যাপ: 4 বাইটে অফসেট করুন
- কলাম গণনা: 2 বাইট
- স্লট অ্যারে: 2 বাইট ("রেকর্ড আকারে অন্তর্ভুক্ত করা হয়নি তবে এখনও অ্যাকাউন্টের প্রয়োজন)
- নুল বিটম্যাপ: প্রতি 8 কলামে 1 টি বাইট ( সমস্ত কলামের জন্য)
- সারি সংস্করণ: 14 বাইট (যদি ডেটাবেসটি হয়
ALLOW_SNAPSHOT_ISOLATION
বা READ_COMMITTED_SNAPSHOT
সেট করে থাকে ON
)
- পরিবর্তনশীল-দৈর্ঘ্যের কলাম অফসেট অ্যারে: সমস্ত কলাম স্থির-দৈর্ঘ্য হলে 0 বাইট। যদি কোনও কলামগুলি ভেরিয়েবল-দৈর্ঘ্যের হয় তবে 2 বাইট এবং প্লাস কেবলমাত্র ভেরিয়েবল-দৈর্ঘ্যের কলামগুলির জন্য 2 বাইট।
- এলওবি পয়েন্টার: এই অংশটি খুব সঠিক নয় কারণ মানটি থাকলে কোনও পয়েন্টার থাকবে না
NULL
, এবং মানটি যদি সারিটির সাথে ফিট করে তবে এটি পয়েন্টারের চেয়ে অনেক ছোট বা অনেক বড় হতে পারে, এবং যদি মানটি অফ-স্টোর করা থাকে- সারি, তারপরে পয়েন্টারের আকারটি নির্ভর করবে যে সেখানে কতটা ডেটা রয়েছে on তবে, যেহেতু আমরা কেবল একটি প্রাক্কলন চাই (অর্থাত্ "সোয়াগ"), তাই মনে হয় 24 বাইট ব্যবহার করার জন্য ভাল মান (ভাল, অন্য যে কোনও হিসাবে ভাল ;-))। এটি প্রতি MAX
ক্ষেত্রের।
সুতরাং, এর মতো কিছু ব্যবহার করুন:
সাধারণভাবে (সারি শিরোনাম + কলামগুলির সংখ্যা + স্লট অ্যারে + নুল বিটম্যাপ):
([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
/ এলওবি কলাম থাকে, তবে যুক্ত করুন:
+ (24 * {NumLobColumns})
সাধারণভাবে:
)) AS [MetaDataBytes]
এটি যথাযথ নয়, আবার যদি আপনার সারি বা পৃষ্ঠা সংক্ষেপণটি হিপ বা ক্লাস্টারড ইনডেক্সে সক্ষম করা থাকে তবে এগুলি আবার কাজ করবে না, তবে অবশ্যই আপনাকে আরও কাছাকাছি আসা উচিত।
15% পার্থক্য রহস্য সম্পর্কিত আপডেট
আমরা (আমার অন্তর্ভুক্ত) কীভাবে ডেটা পৃষ্ঠাগুলি নির্ধারণ করা হয়েছে এবং কীভাবে DATALENGTH
আমরা কীভাবে ২ য় ক্যোয়ারী পর্যালোচনা করতে খুব বেশি সময় ব্যয় করি নি সেগুলির জন্য কীভাবে অ্যাকাউন্ট করা যেতে পারে সে সম্পর্কে চিন্তাভাবনা করেছিলাম। আমি সেই জিজ্ঞাসাটি একটি একক টেবিলের বিপরীতে চালিয়েছি এবং তারপরে সেই মানগুলির সাথে তুলনা করে যা রিপোর্ট করা হয়েছিল sys.dm_db_database_page_allocations
এবং পৃষ্ঠাগুলির সংখ্যার জন্য সেগুলি একই মান ছিল না। একটি কুঁচকিতে, আমি সামগ্রিক ফাংশনগুলি সরিয়ে দিয়েছি এবং তালিকাটি এর সাথে GROUP BY
প্রতিস্থাপন SELECT
করেছি a.*, '---' AS [---], p.*
। এবং তারপরে এটি স্পষ্ট হয়ে উঠল: লোকেরা অবশ্যই সতর্কতা অবলম্বন করবে যেখানে এই ন্যক্কারজনক ইন্টারভেজে তারা তাদের তথ্য এবং স্ক্রিপ্টগুলি ;-) থেকে পাবেন। প্রশ্নে পোস্ট করা দ্বিতীয় কোয়েরিটি সঠিকভাবে নয়, বিশেষ করে এই বিশেষ প্রশ্নের জন্য।
গৌণ সমস্যা: এর বাইরে খুব বেশি অর্থবোধ না করে GROUP BY rows
(এবং এই কলামটি একটি সামগ্রিক ফাংশনে নেই), এর মধ্যে যোগ দিন sys.allocation_units
এবং sys.partitions
প্রযুক্তিগতভাবে সঠিক নয়। এখানে 3 ধরণের বরাদ্দ ইউনিট রয়েছে এবং এর মধ্যে একটির পৃথক ক্ষেত্রে যোগ দেওয়া উচিত। বেশিরভাগ ক্ষেত্রে partition_id
এবং hobt_id
একই রকম হয়, তাই কখনও কখনও সমস্যা নাও হতে পারে তবে কখনও কখনও এই দুটি ক্ষেত্রে আলাদা আলাদা মান থাকে।
প্রধান সমস্যা: ক্যোয়ারীটি used_pages
ক্ষেত্রটি ব্যবহার করে । এই ক্ষেত্রটি সমস্ত ধরণের পৃষ্ঠাগুলি জুড়ে : ডেটা, সূচক, আইএএম, ইত্যাদি, টিসি। যখন শুধুমাত্র প্রকৃত তথ্য সঙ্গে সংশ্লিষ্ট আছে ব্যবহার করতে অন্য, আরো উপযুক্ত ক্ষেত্র: data_pages
।
আমি উপরের আইটেমগুলি মাথায় রেখে প্রশ্নটিতে ২ য় ক্যোয়ারীটি মানিয়েছি এবং পৃষ্ঠার শিরোনামটি ব্যাকআপ করে এমন ডেটা পৃষ্ঠার আকার ব্যবহার করি। আমি অপ্রয়োজনীয় দুটি জিনও সরালাম: sys.schemas
(কল করার সাথে প্রতিস্থাপন করা হয়েছিল SCHEMA_NAME()
), এবং sys.indexes
(ক্লাস্টারড ইনডেক্স সর্বদা index_id = 1
এবং আমাদের index_id
সাথে রয়েছে 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;