Sys.allocation_units থেকে টেবিলের আকারের সাথে মেলে না এমন ডেটাএলএনজিটিএসের সুম UM


11

আমি এই ছাপে ছিলাম যে যদি আমি DATALENGTH()একটি টেবিলের সমস্ত রেকর্ডের জন্য সমস্ত ক্ষেত্রের যোগফল যোগ করি তবে আমি টেবিলের মোট আকার পাই। আমি কি ভুল করছি?

SELECT 
SUM(DATALENGTH(Field1)) + 
SUM(DATALENGTH(Field2)) + 
SUM(DATALENGTH(Field3)) TotalSizeInBytes
FROM SomeTable
WHERE X, Y, and Z are true

আমার ডাটাবেসে একটি নির্দিষ্ট টেবিলের আকার পেতে আমি নীচে এই ক্যোয়ারীটি ব্যবহার করেছি (টেবিলের আকারগুলি, ক্লাস্টারড ইনডেক্সগুলি কেবল অনলাইনে পেয়েছি যাতে এতে এনসি সূচি অন্তর্ভুক্ত হয় না) particular বিলিংয়ের উদ্দেশ্যে (আমরা আমাদের বিভাগগুলি তাদের যে পরিমাণ জায়গাগুলি ব্যবহার করি সেগুলি দিয়ে চার্জ করি) প্রতিটি টেবিলটিতে প্রতিটি বিভাগ কতটা জায়গা ব্যবহার করেছে তা আমাকে খুঁজে বের করতে হবে। আমার একটি প্রশ্ন আছে যা টেবিলের মধ্যে প্রতিটি গ্রুপকে সনাক্ত করে। আমার কেবল প্রতিটি গ্রুপ কতটা জায়গা নিচ্ছে তা নির্ধারণ করতে হবে।

VARCHAR(MAX)সারণীতে ক্ষেত্রগুলির কারণে সারি প্রতি স্পেস বন্যভাবে দুলতে পারে , সুতরাং আমি কেবলমাত্র একটি বিভাগের জন্য সারির অনুপাতের গড় আকার নিতে পারি না। আমি যখন DATALENGTH()উপরে বর্ণিত পদ্ধতিটি ব্যবহার করি তখন আমি নীচের ক্যোয়ারীতে ব্যবহৃত মোট স্থানের 85% পাই। থটস?

SELECT 
s.Name AS SchemaName,
t.NAME AS TableName,
p.rows AS RowCounts,
(SUM(a.total_pages) * 8)/1024 AS TotalSpaceMB, 
(SUM(a.used_pages) * 8)/1024 AS UsedSpaceMB, 
((SUM(a.total_pages) - SUM(a.used_pages)) * 8)/1024 AS UnusedSpaceMB
FROM 
    sys.tables t with (nolock)
INNER JOIN 
    sys.schemas s with (nolock) ON s.schema_id = t.schema_id
INNER JOIN      
    sys.indexes i with (nolock) ON t.OBJECT_ID = i.object_id
INNER JOIN 
    sys.partitions p with (nolock) ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN 
    sys.allocation_units a with (nolock) ON p.partition_id = a.container_id
WHERE 
    t.is_ms_shipped = 0
    AND i.OBJECT_ID > 255 
    AND i.type_desc = 'Clustered'
GROUP BY 
    t.Name, s.Name, p.Rows
ORDER BY 
    TotalSpaceMB desc

এটি প্রস্তাবিত হয়েছে যে আমি প্রতিটি বিভাগের জন্য একটি ফিল্টার সূচক তৈরি করি বা সারণি বিভাজন করি, তাই আমি সরাসরি সূচক অনুসারে ব্যবহৃত স্থানটি অনুসন্ধান করতে পারি। ফিল্টারড সূচকগুলি প্রোগ্রামিকভাবে তৈরি করা যেতে পারে (এবং কোনও রক্ষণাবেক্ষণ উইন্ডো চলাকালীন বা যখন আমাকে পর্যায়ক্রমিক বিলিংয়ের প্রয়োজন হয় তখন আবার বাদ দেওয়া হয়) পরিবর্তে স্থানটি সারাক্ষণ ব্যবহারের পরিবর্তে (পার্টিশনগুলি এই ক্ষেত্রে আরও ভাল হবে)।

আমি সেই পরামর্শটি পছন্দ করি এবং এটি সাধারণত করি। তবে সত্য কথা বলতে আমি কেন প্রতিটি প্রয়োজন এটি ব্যাখ্যা করার জন্য উদাহরণ হিসাবে "প্রতিটি বিভাগ" ব্যবহার করি, তবে সত্য বলতে সত্যই তাই নয়। গোপনীয়তার কারণে আমি কেন এই ডেটা প্রয়োজন তার সঠিক কারণটি আমি ব্যাখ্যা করতে পারি না, তবে এটি বিভিন্ন বিভাগের সাথে সাদৃশ্যপূর্ণ।

এই টেবিলের অবিবাহিত সূচীগুলি সম্পর্কে: আমি যদি এনসি সূচকের আকারগুলি পেতে পারি তবে তা দুর্দান্ত। যাইহোক, এনসি সূচকগুলি ক্লাস্টারড ইনডেক্সের আকারের 1% হারে থাকে, সুতরাং আমরা সেগুলি অন্তর্ভুক্ত করি না। তবে, কীভাবে আমরা এনসি সূচকগুলি অন্তর্ভুক্ত করব? আমি ক্লাস্টারড ইনডেক্সের জন্যও একটি সঠিক আকার পেতে পারি না :)


সুতরাং সংক্ষেপে, আপনার দুটি প্রশ্ন রয়েছে: (1) সারির দৈর্ঘ্যের সমষ্টিটি পুরো টেবিলের আকারের মেটাডাটার অ্যাকাউন্টিংয়ের সাথে কেন মেলে না? নীচের উত্তরে সম্বোধন করা হয়েছে যে কমপক্ষে অংশে (এবং এটি প্রতি রিলিজ এবং প্রতি বৈশিষ্ট্যতে ওঠানামা করতে পারে, উদাহরণস্বরূপ সংক্ষেপণ, কলামস্টোর ইত্যাদি)। এবং আরও গুরুত্বপূর্ণভাবে: (২) আপনি প্রতি বিভাগে ব্যবহৃত প্রকৃত স্থানটি কীভাবে সঠিকভাবে নির্ধারণ করতে পারেন? আমি জানি না যে আপনি এটি সঠিকভাবে করতে পারেন - কারণ উত্তরের কয়েকটি ডেটার উত্তর হিসাবে জবাবদিহি করার কারণে এটি কোন বিভাগের অন্তর্গত তা বলার উপায় নেই।
অ্যারন বারট্র্যান্ড

আমি মনে করি না যে সমস্যাটি আপনার কাছে ক্লাস্টারড ইনডেক্সের সঠিক আকার নেই - মেটাডেটা অবশ্যই আপনার সূচকটি কতটা জায়গা নেয় তা নির্ভুলতার সাথে আপনাকে বলে। কমপক্ষে আপনার বর্তমান নকশা / কাঠামো দেওয়া - প্রতিটি বিভাগের সাথে কতটা ডেটা যুক্ত। তা মেটাডেটা আপনাকে জানাতে কী ডিজাইন করা হয়নি।
অ্যারন বারট্রান্ড

উত্তর:


19

                          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_tableoptionlarge 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 দ্বারা সংরক্ষিত FILLFACTORNew সংরক্ষিত জায়গার পিছনে ধারণাটি হ'ল এটি অ-অনুক্রমিক সন্নিবেশ এবং / অথবা আপডেটগুলির দ্বারা ব্যবহৃত হবে যা ইতিমধ্যে পৃষ্ঠায় সারিগুলির আকার প্রসারিত করে, ভেরিয়েবল দৈর্ঘ্যের কলামগুলি আরও কিছু ডেটা দিয়ে আপডেট করা হয়েছে (তবে এটির কারণ হওয়ার পক্ষে যথেষ্ট নয়) পৃষ্ঠা-বিভক্ত)। তবে আপনি সহজেই ডেটা পৃষ্ঠাগুলিতে স্থান সংরক্ষণ করতে পারবেন যা প্রাকৃতিকভাবে কখনই নতুন সারি পায় না এবং বিদ্যমান সারিগুলি কখনই আপডেট হয় না বা কমপক্ষে এমনভাবে আপডেট করা হয় না যা সারিটির আকার বাড়িয়ে তুলবে।

  • পৃষ্ঠা-বিভাজক (বিভাজন): সারিটির কোনও স্থান নেই এমন একটি স্থানে একটি সারি যুক্ত করার প্রয়োজন হলে পৃষ্ঠার বিভাজন ঘটবে। এই ক্ষেত্রে, বিদ্যমান উপাত্তের প্রায় 50% একটি নতুন পৃষ্ঠায় সরানো হয়েছে এবং নতুন সারিটি 2 পৃষ্ঠার একটিতে যুক্ত করা হয়েছে। তবে এখন আপনার কাছে আরও খানিকটা মুক্ত স্থান রয়েছে যা DATALENGTHগণনা অনুসারে গণ্য হয় না ।

  • সারি মুছে ফেলার জন্য চিহ্নিত করা হয়েছে। আপনি যখন সারিগুলি মুছবেন তখন সেগুলি ডেটা পৃষ্ঠা থেকে তাত্ক্ষণিকভাবে সরানো হয় না। যদি তাদের তাত্ক্ষণিকভাবে অপসারণ করা না যায় তবে এগুলি "মৃত্যুর জন্য চিহ্নিত" (স্টিভেন সেগাল রেফারেন্স) এবং পরে ভূত পরিষ্কারের প্রক্রিয়া দ্বারা শারীরিকভাবে অপসারণ করা হবে (আমি বিশ্বাস করি যে এটিই নাম)। তবে এগুলি এই বিশেষ প্রশ্নের সাথে প্রাসঙ্গিক নাও হতে পারে।

  • ভুতের পৃষ্ঠা? এটি সঠিক শব্দটি কিনা তা নিশ্চিত নন তবে কখনও কখনও ক্লাস্টারড ইনডেক্সের পুনরায় বিল্ডিং না করা পর্যন্ত ডেটা পৃষ্ঠাগুলি মুছে ফেলা হয় না। এটি এতে DATALENGTHযোগ করার চেয়ে আরও বেশি পৃষ্ঠাগুলির জন্য অ্যাকাউন্ট করবে। এটি সাধারণত হওয়া উচিত নয়, তবে আমি বেশ কয়েক বছর আগে একবার এটিতে প্রবেশ করেছি।

  • স্পারস কলাম: সারণীর বৃহত%% NULLএক বা একাধিক কলামের জন্য সারণির ফাঁকে ফাঁকে ফাঁকে ফাঁকে ফাঁকে ফাঁকে ফাঁকে ফাঁকে কলামগুলি (বেশিরভাগ স্থির দৈর্ঘ্যের ডেটাটাইপগুলির জন্য) সংরক্ষণ করে । SPARSEবিকল্প তোলে NULLআপ 0 বাইটের (স্বাভাবিক সংশোধন দৈর্ঘ্যের পরিমাণ পরিবর্তে, একটি জন্য যেমন 4 বাইট মান টাইপ INT), কিন্তু , অ-শূন্য আপ সংশোধন করা দৈর্ঘ্যের ধরনের জন্য একটি অতিরিক্ত 4 বাইট এবং জন্য একটি পরিবর্তনশীল পরিমাণ প্রতিটি নিতে মান পরিবর্তনশীল দৈর্ঘ্যের প্রকার। এখানে সমস্যাটি হ'ল DATALENGTHএকটি স্পারস কলামে নন-নুল মানগুলির জন্য অতিরিক্ত 4 বাইট অন্তর্ভুক্ত নয়, সুতরাং সেই 4 বাইটগুলি আবার যুক্ত করতে হবে SPARSEvia এখানে কোনও কলাম রয়েছে কিনা তা পরীক্ষা করে দেখতে পারেন :

    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, তবে ক্লাস্টারড ইনডেক্সের কোনও কিছু করার ক্ষেত্রে সত্যই সঠিক । এবং এর পরে, আপনার এখনও FILLFACTOR100 এর নীচে যে কোনও সেটিংয়ের জন্য অ্যাকাউন্টিং করতে হবে 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;

মন্তব্যগুলি বর্ধিত আলোচনার জন্য নয়; এই কথোপকথন চ্যাটে সরানো হয়েছে ।
পল হোয়াইট 9

যদিও ২ য় ক্যোয়ারীর জন্য আপনি সরবরাহিত আপডেট হওয়া ক্যোয়ারীটি আরও এগিয়ে রয়েছে (এখন অন্য দিকে :)), আমি এই উত্তরের সাথে ঠিক আছি। আপাতদৃষ্টিতে ক্র্যাক করা এবং এটির মূল্য কী, এটি আমি খুব শক্ত বাদাম, বিশেষজ্ঞরা আমাকে সাহায্য করার পরেও আমি আনন্দিত যে আমি এখনও দুটি পদ্ধতির সাথে মেলে না তার সঠিক কারণটি বের করতে অক্ষম। আমি এক্সট্রোপোলেটের অন্যান্য উত্তরে পদ্ধতিটি ব্যবহার করতে যাচ্ছি। আমি আশা করি আমি এই দুটি উত্তরের জন্য হ্যাঁ ভোট দিতে পারতাম, তবে @ শ্রুতজকি দু'বার বন্ধ থাকার কারণেই সমস্ত কারণেই সহায়তা করেছিলেন।
ক্রিস উডস

6

হতে পারে এটি একটি গ্রঞ্জ উত্তর তবে এটি আমি করতাম।

সুতরাং ডেটাএলএনজিটিএই মোট মোট 86% ভাগ রয়েছে। এটি এখনও খুব প্রতিনিধি বিভক্ত। শ্রুতজকির দুর্দান্ত উত্তরে ওভারহেডের একটি সুন্দর এমনকি বিভাজন হওয়া উচিত।

মোটের জন্য আমি আপনার দ্বিতীয় ক্যোয়ারী (পৃষ্ঠা) ব্যবহার করব। এবং বিভাজন বরাদ্দের জন্য প্রথম (ডেটালেথ) ব্যবহার করুন। একটি নরমালাইজেশন ব্যবহার করে অনেক খরচ বরাদ্দ করা হয়।

এবং আপনাকে একটি নিবিড় উত্তর বিবেচনা করতে হবে যাতে দাম বাড়াতে চলেছে এমনকি বিভাজনে হারিয়ে যাওয়া ডিপেন্ড্ট এখনও আরও বেশি অর্থ দিতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.