آشنایی با ساختار سطر در جداول Memory Optimized

آشنایی با ساختار سطر در جداول Memory Optimized

نوشته شده توسط: احسان حسین پور
تاریخ انتشار: ۲۳ شهریور ۱۳۹۷
آخرین بروزرسانی: ۲۷ شهریور ۱۴۰۲
زمان مطالعه: 12 دقیقه
۲.۷
(۷)

مقدمه

سطرها در جداول Memory-Optimized بر خلاف جداول Disk-Based در مجاورت یکدیگر قرار نمی‌گیرند. به عبارت دیگر دیتای این جداول در حافظه بدون هیچ ترتیب منطقی پخش می‌شوند. ساختار کلی جداول Memory-Optimized به شکل زیر است.همانطور که می‌بینید این ساختار به دو بخش کلی Header و Payload تقسیم می‌شود. همانطور که اشاره شد ساختار سطرها در جداول Memory-Optimized با جداول Disk-Based به منظور دستیابی به بهترین عملکرد متفاوت است.
قسمت Payload شامل ستون‌های جدول است. در این قسمت به بررسی دقیق‌تر header می پردازیمBegin and End Timestamp: هر کدام به تنهایی ۸ بایت فضا نیاز دارند. که به ترتیب نشان دهنده برچسب زمانی تراکنشی که سطر را ایجاد کرده و تراکنشی که سطر را حذف کرده می‌باشند. اما مساله به همین سادگی نیست. به همین دلیل باید به جزییات مهمتری دقت کنید:

  • Timestamp مشخص کننده زمانی است که تراکنش به پایان می‌رسد. به همین دلیل هر دو برچسب شروع و پایان به صورت دائم شناسه سراسری تراکنش یا Global Transaction ID در خود نگه می‌دارند. Global Transaction IDیک مقدار افزایشی یکتاست که مشخص کننده یک تراکنش است. این مقدار در زمان ریست شدن سرویس بازیابی می‌شود.
  • زمانیکه یک سطر ایجاد می‌شود End Timestamp به بینهایت مقداردهی می شود.
  • در جداول Memory-Optimized فقط دستور delete سطر را حذف نمی‌کند. بلکه دستور update هم همین کار را انجام می‌دهد. هنگامی که یک سطر تغییر می‌کند. حذف سطر به دنبال درج سطر جدید اتفاق می‌افتد.
  • Statement ID یک فیلد ۴ بایتی است که شناسه یکتای دستوری که سطر را تولید کرده، ذخیره می‌کند.
  • IndexLink Count: یک فیلد دو بایتی است که همانطور از اسم آن مشخص است تعداد ایندکس‌هایی که به این سطر اشاره دارند را درخود ذخیره می‌کند.
  • Pointers: بخش باقیمانده Header به اشاره‌گرهای ایندکس تعلق است. در SQL Server 2014 امکان تغییر جدول (حذف و اضافه کردن ستون ) وجود ندارد و همچنین ایندکس‌های مرتبط با آن قابل تغییر نیست. امکان حذف و یا اضافه کردن ایندکس روی جداول Memory-Optimized وجود ندارد. این محدودیت به دلیل وجود ساختار ایندکس‌ها در Header مربوط به سطر است. این محدودیت در SQL Server 2016 به بعد برداشته شده است.

دوره In-Memory OLTP و Columnstore در SQL Server

ایندکس‌ها در جداول Memory-Optimized

  • ایندکس‌ها به عنوان مدخل ورودی جداول Memory-Optimized هستند. بر همین اساس، ایندکس‌ها یک جز جداناپذیر از جداول Memory-Optimized هستند که علاوه بر بهینه‌سازی عملکرد وظیفه مرتبط کردن سطرها را با یکدیگر به عهده دارند. در حال حاضر محدودیت تعریف ۸ ایندکس به ازای هر جدول Memory-OPtimized وجود دارد.

  • تمام عملیات هایی مانند تعریف و حذف ایندکس که بر روی ایندکس صورت می‌گیرد هیچ گاه در دیسک ذخیره نمی‌شوند و log برای آن‌ها تولید نمی‌شود. بر همین اساس، هر زمانی که سرویس SQL Sever ریست شود ایندکس دوباره در حافظه rebuild می‌شود.

  • همانطور که در مقاله قبلی اشاره شد ایندکس‌ها به دو صورت پایدار و موقت بر روی جداول Memory-Optimized تعریف می‌شوند و به دو نوع تقسیم می‌شوند.

  • Hash Index
  • Nonclustered (Range) Index

Hash Index

یک Hash Index شامل مجموعه‌ای از سطل هاست( bucket) که در آرایه‌ای از اشاره گرها مدیریت می‌شوند. نام این ایندکس به این دلیل است که از یک تابع Hash برای مقداردهی مقادیر ایندکس استفاده می‌کند. این نوع ایندکس‌ها بر روی عملگرهای pointer-lookup بسیار کارا هستند. به عبارت دیگر زماینکه دقیقا به دنبال یک مقدار خاص هستیم.bucket یک اشاره گر به سطری است که در حافظه قرار گرفته است و وابسته به مقداری است که تابع Hash تولید کرده است. کلیدهایی که یکHash تولید می کنند به همان اشاره گر دسترسی خواهند داشت و در یک زنجیره به هم متصل هستند. مثال زیر یک Hash Index را برای ستون City نمایش می‌دهد. تابع Hash مقدار “New York” را دریافت می‌کند و یک Hash برای آن تولید می‌کند که مشخص کننده Bucket مختص به خود است.با اضافه شدن سطرهای جدید با همان مقدار یک زنجیره از سطرهای متصل بهم ایجاد می‌شود. در شکل زیر دو سطر جدید با شهر New York اضافه شده است. بنابراین زنجیره از سطرها به وجود آمده است.هنگامی که ایندکسی از نوع hash ایجاد می‌کنید. تعیین تعداد Bucket پراهمیت است. این تعیین مقدار، زمانی که از SQL Server 2014 استفاده می‌کنید به دلیل عدم امکان تغییر ایندکس ایجاد شده بسیار پراهمیت تر می‌شود.
دو سناریو ممکن وجود دارد. تعیین مقدار بسیار بالا یا بسیار پایین برای Bucket. هر دو حالت گزینه‌های بدی هستند اما اثرات متفاوتی دارند.
همانطور که اشاره شد، زمانیکه یک سطر با یک Hash Index در جدول درج می‌شود، یک تابع Hash مقدار کلید ایندکس را می‌گیرد و یک مقدار hash تولید می‌کند که به سطر خاصی اشاره می‌کند. با این توضیح میتوان حدس زد چه اتفاقی خواهد افتاد وقتی مقادیر یکتای تولید شده از تعداد Bucket موجود بیشتر باشد. در این شرایط تابع Hash شروع به تولید مقادیر یکسان با مقادیر ورودی متفاوت می‌کند. این اتفاق که تصادم یا Hash Collsion نام دارد منجر به ترکیب مقادیر مختلف در یک لیست به هم پیوسته می‌شود که ایده ال نیست. Microsoft توصیه می‌کند حداکثر تا ۳۰% تصادم قابل قبول است و بیشتر از این مقدار باعث تاثیر بسیار منفی در عملکرد جدول خواهد داشت.

از طرفی انتخاب مقدار بسیار زیاد برای Bucket توصیه نمی‌شود.چون به منظور نگهداری هر Bucket در حافظه ۸ بایت استفاده می‌شود. و هدف از استفاده از جداول Memory-Optimized افزایش عملکرد و استفاده از حداقل فضای حافظه تا حد امکان است. همچنین تعداد Bucket تولید شده یک عدد به توان ۲ است یعنی نزدیکترین عدد به توان که بزرگتر یا مساوی عدد تعیین شده در هنگام تعریف جدول است. به طور مثال اگر BUCKET_COUNT=25 ست کنیم. تعداد bucket تولید شده برابر با ۳۲ خواهد بود. برای BUCKET_COUNT معمولا ۱.۵ تا ۲ برابر مقدار یکتای دیتای ستون ایندکس توصیه می شود. در مثال زیر BUCKET_COUNT برابر ۱۲۴ تعیین شده است.

CREATE TABLE Customers (
  ID		INT NOT NULL,
  NAME		VARCHAR(10) NOT NULL,
  PRIMARY KEY NONCLUSTERED HASH (NAME) WITH ( BUCKET_COUNT = 124 )
)  WITH ( MEMORY_OPTIMIZED=ON, DURABILITY=SCHEMA_AND_DATA )

همانطور که اشاره شد در SQL Server 2016 به بالا می‌توان پس از تعریف جدول ایندکس را تعریف کرد.

ALTER TABLE [Customers]
ADD INDEX idx_hash_customers
HASH (ID) WITH (BUCKET_COUNT = 124);

Nonclustered Index

ایندکس‌های Nonclustered در جداول Memory-Optimized متفاوت با ایندکس‌های Nonclustered در جداول Disk-Based هستند. این نوع ایندکس‌ها در جداول Memory-Optimized از ساختاری به نام Bw-tree استفاده می‌کنند. که بهبود یافته ساختار b-tree با تکنیک lock-and-latch-free است. این نوع ایندکس در زماینکه جستجو بر اساس بازه صورت می‌گیرد گزینه مناسبتری نسبت به hash index شمار می‌آید. تصویر ساختار Bw-tree را نمایش می‌دهد.همانطور که می‌بینید ساختار Bw-tree تقریبا مشابه ساختار B-tree است. هر Page مجموعه‌ای از مقادیر منظم با اشاره‌گری به مرحله بعد در خود دارد. در سطح میانی اشاره گرهای به سطح برگ مشاهده می‌کنید. که اشاره گرهای سطح برگ هم به سطرهای دیتا اشاره می‌کنند.
اگر مقدار کلید ایندکس برای چندین سطر یکی باشد زنجیره‌ای از داده‌ها مشابه Hash Index ایجاد می‌شود مانند آنچه که در تصویر می‌بینید هر دو سطر دارای مقدار کلید ایندکس ۳ هستند. بنابراین هر دو سطر بخشی از یک لیست متصل هستند.
Bw-tree از ساختاری به نام Page Mapping Table (PMT) به منظور اتصال Page های به یکدیگر استفاده می‌کند. PMT ازشناسه‌هایی به نام Page ID (PID) استفاده می‌کند که این شناسه‌ها برای ارجاع آدرس حافظه فیزیکی صفحه به کار می‌روند.هر اشاره‌گر Page شامل یک مقدار PID از جدول نگاشت PMT است. که این PID به آدرس فیزیکی حافظه Page مرتبط اشاره می کند. این قانون در مورد Page های در سطح برگ صدق نمی‌کند و سطرها مستقیما به آدرس فیزیکی حافظه اشاره می‌کنند.
اگر نیاز به تغییر page ایندکس باشد، SQL Server یک Page جدید ایجاد می‌کند. بنابراین PMT با تغییر آدرس فیزیکی حافظه مربوط به آن PID بروزرسانی می‌شود. همچنین در مورد Pageهای سطح برگ متفاوت رفتار می‌شود.

هنگامی که Insert یا Delete انجام می‌شود و مقدار کلید ایندکس Page در سطح برگ را تغییر می‌دهد یک رکورد به نام Delta Record ایجاد می‌شود که این تغییر را شامل می‌شود. پس از آن PMT اشاره‌گر خود را به آدرس فیزیکی Delta Page بروزرسانی می‌کند. در واقع تکنیک Delta Page ، SQL Server را وادار می‌کند Pageهای اصلی با Delta Pageها به منظور رسیدن به سطر اصلی ترکیب کند، به همین دلیل عملیات یافتن سطر کمی پرهزینه‌تر خواهد بود.
البته همچنان در مورد Delta Records محدودیتی با نام ۶ Delta Records وجود دارد. یعنی زمانی که این اتفاق می‌افتد، SQL Server فرآیند تلفیقی را به منظور بازسازی Page با استفاده از تمام تغییرات ثبت شده توسط Delta record انجام می‌دهد.

در واقع مکانیزم ۶ Delta Records تضمینی برای بهبود عملکرد است. یکی دیگر از محدودیت‌های مرتبط با ساختار ایندکس Page Split است. وقتی که فضای صفحه ایندکس به 8KB می‌رسد به منظور تطبیق با مقادیر جدید ایندکس Page Split اتفاق می‌افتد. از طرف دیگر زمانی که فضای یک Page به کمتر از ۱۰ درصد از 8KB می‌رسد.عملیات Merge اتفاق می‌افتد که منجر به ترکیب Page ایندکس مجاور می‌شود.
در اسکریپت زیر نمونه‌ای از تعریف یک جدول یا یک ایندکس Nonclustered مشاهده می‌کنید.

CREATE TABLE [dbo].[Customers]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](100) COLLATE Latin1_General_CI_AS NOT NULL,
PRIMARY KEY NONCLUSTERED
(
[ID] ASC
)
)WITH ( MEMORY_OPTIMIZED = ON , DURABILITY = SCHEMA_AND_DATA )

همچنین امکان تعریف ایندکس بر روی جدولی که وجود دارد در نسخه SQL Server 2016 به بالا امکانپذیر است.

ALTER TABLE [Customers]
ADD INDEX idx_nc_Customers
NONCLUSTERED (Price ASC)
go

 

چه رتبه ای می‌دهید؟

میانگین ۲.۷ / ۵. از مجموع ۷

اولین نفر باش

title sign
دانلود مقاله
آشنایی با ساختار سطر در جداول Memory Optimized
فرمت PDF
7 صفحه
حجم 1 مگابایت
دانلود مقاله
title sign
معرفی نویسنده
احسان حسین پور
مقالات
4 مقاله توسط این نویسنده
محصولات
4 دوره توسط این نویسنده
احسان حسین پور

احسان حسین پور مدیر بانک اطلاعاتی در شرکت پرداخت الکترونیک سداد و همچنین مدرس و مشاور SQL Server در نیک‌آموز است. از دیگر سوابق او به مدیر پایگاه داده در شرکت حصین ، مدیر فنی توسعه سامانه نیکنام، ، متخصص سیستم‌های انبارداده و هوش تجاری، طراحی In-Memory OLTP در SQL Server اشاره کرد.

title sign
دیدگاه کاربران