شاخص یا indexهایی را بر روی فیلدهای موجود در ذخیرهگاه دادهها (data stores) ایجاد کنید که اغلب توسط کوئریها(queries) به آنها ارجاع داده میشود. این الگو میتواند عملکرد کوئریها را با اجازهدادن به برنامهها برای مکانیابی سریعتر دادهها جهت بازیابی آنها از data stores را بهبود بخشد.
بسیاری data store ها، برای مجموعهای از موجودیتها با استفاده از کلید اولیه (primary key) سازماندهی میکنند. یک برنامه میتواند از این کلید برای مکانیابی و بازیابی دادهها استفاده کند. شکل زیر نمونهای از یک data store را نشان میدهد که اطلاعات مشتری را در خود نگهداری میکند. در واقع primary key برابر با شناسه یا ID مشتری است. این شکل، اطلاعات مشتری سازماندهی شده توسط primary key (Customer ID) را نشان میدهد.
در برخی موارد ممکن است نتوانیم از primary key استفاده کنیم. بهعنوانمثال در زمانی که primary key با queryهایی که دادهها را مبتنی بر مقدار آن کلید واکشی میکند، اگر برنامهای نیاز به بازیابی دادهها بر اساس فیلد دیگری داشته باشد در این صورت استفاده از primary key غیرممکن میشود. در این مثال مشتریان، یک application نمیتواند از primary key شناسه مشتری(Customer ID primary key) برای بازیابی مشتریان استفاده کند، اگر دادهها را صرفاً با ارجاع به مقدار مشخصههای دیگر، مانند شهری که مشتری در آن قرار دارد، جستجو کند. برای انجام یک کوئری مانند این، برنامه ممکن است مجبور باشد هر رکورد مشتری را واکشی و بررسی کند که این رویکرد میتواند روند کندی داشته باشد. بسیاری از سیستمهای مدیریت پایگاهداده رابطهای از indexهای ثانویه پشتیبانی میکنند. index ثانویه یک ساختار داده جداگانه است که توسط یک یا چند فیلد کلیدی nonPrimary (ثانویه) سازماندهی شده است و نشان میدهد که دادههای هر مقدار index شده در کجا ذخیره میشود. موارد موجود در یک index ثانویه معمولاً بر اساس مقدار کلیدهای ثانویه مرتب میشوند تا امکان جستجوی سریع دادهها فراهم شود. این فهرستها معمولاً به طور خودکار توسط سیستم مدیریت پایگاهداده نگهداری میشوند. شما میتوانید به تعداد موردنیاز ایندکس ثانویه ایجاد کنید تا از کوئریهای مختلفی که برنامه شما انجام میدهد پشتیبانی کند. بهعنوانمثال، در یک Customers table در یک پایگاهداده رابطهای که ID مشتری primary key است، اگر برنامه مرتباً مشتریان را بر اساس شهر محل سکونت آنها جستجو میکند، افزودن یک فهرست ثانویه در قسمت شهر مفید است. بااینحال، اگرچه indexهای ثانویه در سیستمهای رابطهای رایج هستند، برخی از ذخیرهگاههای داده از نوع NoSQL که توسط برنامههای ابری استفاده میشوند، ویژگی مشابهی را ارائه نمیدهند.
اگر data store از indexهای ثانویه پشتیبانی نمیکند، میتوانید با ایجاد جداول فهرست(index tables) خود، آنها را بهصورت دستی شبیهسازی کنید. یک index table دادهها را با یک کلید مشخص سازماندهی میکند. بسته به تعداد indexهای ثانویه موردنیاز و ماهیت کوئریهایی که یک application انجام میدهد، معمولاً از سه راهبُرد برای ساختاربندی index table استفاده میشود. اولین راهبُرد این است که دادهها را در هر index table کپی کنید؛ اما آنها را با کلیدهای مختلف سازماندهی کنید یا به اصلاح غیرنرمال سازی کامل(complete denormalization) کنید. شکل بعدی index tableهای را نشان میدهد که اطلاعات مشتری یکسان را بر اساس شهر و نام خانوادگی سازماندهی میکند.
این راهبُرد در صورتی مناسب است که دادهها در مقایسه با تعداد دفعاتی که با استفاده از هر کلید که پرسوجو میشوند با احتمال بالایی ثابت باشند. اگر دادهها dynamic تر باشند، سربار پردازش نگهداری هر index table برای این رویکرد بسیار بزرگ میشود که در نتیجه این مسئله حالت مناسبی نیست. همچنین اگر حجم دادهها بسیار زیاد باشد، میزان فضای موردنیاز برای ذخیرهسازی دادههای تکراری قابلتوجه است. راهبُرد دوم ایجاد index tableهای نرمال(normalized) و سازماندهی شده توسط کلیدهای مختلف و ارجاع دادههای اصلی با استفاده از primary key بهجای تکرار آن است، همانطور که در شکل زیر نشاندادهشده است. دادههای اصلی جدول واقعیت (fact table) نامیده میشود.
این تکنیک باعث صرفهجویی در فضا و کاهش هزینههای سربار نگهداری دادههای تکراری میشود. نقطهضعف این است که یک application باید دو عملیات جستجو را برای یافتن دادهها با استفاده از یک کلید ثانویه (secondary key) انجام دهد. باید primary key دادهها را در index table پیدا کند و سپس از primary key برای جستجوی دادهها در fact table استفاده کند.
راهبرد سوم ایجاد index table که بهصورت جزئی نرمال (normalized) و سازماندهی شده توسط کلیدهای مختلف است که فیلدهای اغلب بازیابی شده را کپی میکنند. برای دسترسی به فیلدهایی که کمتر به آنها دسترسی دارید، به جدول واقعیت (fact table) مراجعه کنید. شکل بعدی نشان میدهد که چگونه دادههایی که معمولاً در دسترس هستند در هر index table تکرار میشوند.
با این راهبُرد میتوانید بین دو رویکرد اول تعادل برقرار کنید. دادههای کوئریهای(queries) رایج را میتوان با استفاده از یک جستجوی واحد بهسرعت بالا بازیابی کرد، درحالیکه فضا و سربار نگهداری بهاندازه کپی کردن کل مجموعهداده مهم نیست. اگر برنامهای اغلب با تعیین ترکیبی از مقادیر، دادهها را جستجو میکند (بهعنوانمثال، «همه مشتریانی را که در شهر Redmond زندگی میکنند و نام خانوادگی Smith دارند را بیابید»)، میتوانید کلیدهای موارد موجود در index table را بهصورت الحاقی پیادهسازی کنید. از ویژگی Town و ویژگی LastName. شکل بعدی یک index table بر اساس کلیدهای ترکیبی را نشان میدهد. کلیدها بر اساس Town و سپس برای رکوردهایی که مقدار مشابهی برای شهر (Town) دارند بر اساس نام خانوادگی (LastName) مرتب میشوند.
استفاده از index tableها میتوانند عملیات کوئری (query) را بر روی دادههای شارد شده (sharded data) سرعت بخشند و بهویژه در مواردی که shard key هش شده است مناسب هستند. شکل بعدی مثالی را نشان میدهد که در آن shard key بهصورت هش Customer ID است. index table میتواند دادهها را بر اساس مقدار غیر هَش شده (Town و LastName) سازماندهی کند و کلید هَش شده را بهعنوان داده جستجو ارائه دهد. این مورد میتواند برنامه را از محاسبه مکرر کلیدهای هَش (عملیات پر هزینه) نجات دهد. بهخصوص در حالتی که نیاز به بازیابی دادههایی داشته باشد که در یک محدوده قرار میگیرند یا نیاز به واکشی دادهها به ترتیب کلید غیرهششده داشته باشد. بهعنوانمثال، پرسوجوی مانند 'یافتن همه مشتریانی که در «ردموند» زندگی میکنند' را میتوان با قراردادن موارد منطبق در index table بهسرعت حل کرد، جایی که همه آنها در یک بلوک بههمپیوسته ذخیره میشوند. سپس، ارجاعات به دادههای customer را با استفاده از shard keyهای ذخیره شده در index table دنبال کنید.
هنگام تصمیمگیری در مورد نحوه اجرای این الگو به نکات زیر توجه کنید: * سربار حفظ ایندکسهای ثانویه میتواند قابلتوجه باشد. شما باید کوئریهایی را که برنامه شما استفاده میکند، تجزیهوتحلیل و درک کنید. index table را فقط زمانی ایجاد کنید که احتمالاً به طور منظم از آنها استفاده میشود. برای پشتیبانی از کوئریهایی که یک application انجام نمیدهد یا فقط گاهی اوقات انجام میدهد، index table مبهم ایجاد نکنید. * کپی کردن دادهها در یک index table میتواند هزینههای ذخیرهسازی و تلاش لازم برای نگهداری چندین نسخه از دادهها را افزایش دهد. * پیادهسازی index table بهعنوان یک ساختار نرمالشده که به دادههای اصلی ارجاع میدهد، نیازمند اجرای دو عملیات جستجو برای یافتن دادهها است. عملیات اول index table را برای بازیابی primary key جستجو میکند و عملیات دوم از primary key برای واکشی دادهها استفاده میکند. * اگر یک سیستم تعدادی index table را در مجموعهدادههای بسیار بزرگ ترکیب کند، حفظ یکپارچگی بین index tableها و دادههای اصلی میتواند دشوار باشد. ممکن است بتوان برنامه را بر اساس مدل یکپارچگی تدریجی(eventual consistency model) طراحی کرد. بهعنوانمثال، برای درج، بهروزرسانی یا حذف دادهها، یک برنامه میتواند پیامی را به یک صف ارسال کند و به یک کار جداگانه اجازه دهد این عملیات را انجام دهد و index table ای را که بهصورت ناهمزمان به این دادهها ارجاع میدهند را حفظ کند. برای اطلاعات بیشتر در مورد اجرای یکپارچگی تدریجی(eventual consistency model)، به Data Consistency Primer یا فصل مقدمه مراجعه کنید.
جداول ذخیرهسازی Microsoft Azure از بهروزرسانیهای تراکنشی برای تغییرات ایجاد شده در دادههای موجود در همان پارتیشن (که به آن تراکنشهای entity group گفته میشود) پشتیبانی میکنند. اگر میتوانید دادهها را برای یک fact table و یک یا چند index table در یک پارتیشن ذخیره کنید، میتوانید از این ویژگی برای اطمینان از یکپارچگی استفاده کنید.
- index tableها ممکن است بهصورت پارتیشنبندی یا خرد شده (sharded) باشند.
از این الگو برای بهبود عملکرد کوئریها زمانی که یک برنامه اغلب نیاز به بازیابی دادهها با استفاده از کلیدی غیر از primary key (یا کلید shard) دارد، استفاده کنید. این الگو ممکن است زمانی مفید نباشد که: دادهها فَرار (volatile) هستند.* یک index table میتواند خیلی سریع منسوخ شود یا ناکارآمد شود یا هزینه سربار نگهداری index table را بیشتر از صرفهجویی در استفاده از آن کند.
* فیلدی که بهعنوان کلید ثانویه برای index table انتخاب میشود، بدون انحصار (non discriminating) است و فقط میتواند مجموعهای از مقادیر کوچک (مثلاً جنسیت هر فرد) داشته باشد.
* متعادلسازی مقادیر داده برای یک فیلد انتخاب شده بهعنوان کلید ثانویه برای index table بسیار ناهماهنگ است. بهعنوانمثال، اگر ۹۰ درصد رکوردها دارای مقدار یکسان در یک فیلد باشند، ایجاد و نگهداری یک index table برای جستجوی دادهها بر اساس این فیلد ممکن است هزینه بیشتری نسبت به پویش و بررسی متوالی دادهها ایجاد کند. بااینحال، اگر کوئریها اغلب مقادیری را هدف قرار میدهند که در ۱۰٪ باقیمانده قرار دارند، این شاخص یا index میتواند مناسب باشد. شما باید کوئریهایی را که برنامه شما انجام میدهد و تعداد دفعات انجام آنها را بهخوبی بشناسید و درک کنید.
Azure storage table یک ذخیرهسازی key/value بسیار مقیاسپذیر (scalable) برای برنامههای در حال اجرا در محیط ابری فراهم میکنند. برنامهها با تعیین یک کلید، مقادیر داده را ذخیره و بازیابی میکنند. مقادیر دادهها میتوانند شامل چندین فیلد باشند، اما ساختار یک آیتم داده نسبت به ذخیرهسازی جدول (table storage) تقریباً ناواضح است که در نهایت بهسادگی یک آیتم داده را بهعنوان آرایهای از بایتها مدیریت میکند. Azure storage table نیز از sharding پشتیبانی میکنند. کلید اشتراکگذاری شامل دو عنصر اساسی است که یک کلید پارتیشن و یک کلید ردیف است. آیتمهایی که دارای کلید پارتیشن یکسان هستند در همان پارتیشن shard ذخیره شده و آیتمها به ترتیب کلیدهای ردیفی در یک shard ذخیره میشوند. Table storage برای انجام پرسوجوهایی بهینه شده است که دادهها را در محدوده پیوستهای از مقادیر کلید ردیف شده (row key values) در یک پارتیشن واکشی میکند. اگر در حال ساخت برنامههای ابری هستید که اطلاعات را در Azure table ذخیره میکنند، باید دادههای خود را با درنظرگرفتن این ویژگی ساختاردهی کنید. بهعنوانمثال، برنامهای را در نظر بگیرید که اطلاعات فیلمها را ذخیره میکند. این برنامه اغلب فیلمها را بر اساس ژانر (اکشن، مستند، تاریخی، کمدی، درام و غیره) جستجو میکند. میتوانید با استفاده از ژانر بهعنوان کلید پارتیشن، و تعیین نام فیلم بهعنوان کلید ردیف، همانطور که در شکل بعدی نشاندادهشده است، یک جدول Azure با پارتیشنهایی برای هر ژانر ایجاد کنید. ! [index-table-figure-7] (../assets/dataManagement/index-table-figure-7.png) اگر برنامه همچنین نیاز به پرسوجو روی فیلمها باتوجهبه بازیگرهای آنها داشته باشد، این رویکرد گفته شده در بالا کمی نامناسب است. در این حالت میتوانید یک جدول Azure جداگانه ایجاد کنید که بهعنوان index table عمل میکند. کلید پارتیشن برابر نام بازیگر و کلید ردیف برابر با نام فیلم است. دادههای هر بازیگر در پارتیشنهای جداگانه ذخیره میشود. اگر در یک فیلم بیش از یک بازیگر نقشآفرینی کند، همان فیلم در چندین پارتیشن نمایش داده میشود. میتوانید دادههای فیلم را در مقادیر نگهداشتن شده توسط هر پارتیشن با اتخاذ اولین رویکردی که در بخش راهحل بالا توضیح داده شد، کپی کنید. بااینحال، این احتمال وجود دارد که هر فیلم چندین بار تکرار شود (یکبار برای هر بازیگر)، بنابراین ممکن است کارآمدتر باشد که دادهها را تا حدی غیر نرمالسازی (partially denormalize) کنیم تا از رایجترین کوئریها مانند «نام دیگر بازیگرها» نیز پشتیبانی شود و یک برنامهای که برای بازیابی جزئیات باقیمانده با گنجاندن کلیدهای پارتیشنی موردنیاز برای یافتن اطلاعات کامل در پارتیشنهای مربوط به ژانر فیلم است، فعال شود. این رویکرد توسط گزینه سوم در بخش «راهحل» توضیح داده شده است. شکل بعدی این رویکرد را نشان میدهد. ! [index-table-figure-8] (../assets/dataManagement/index-table-figure-8.png)
- [Data Consistency Primer] (https://learn.microsoft.com/en-us/previous-versions/msp-n-p/dn589800(v=pandp.10)). یک index table باید با تغییر دادههایی که ایندکسهایش میکند قابل نگهداری و در نتیجه قابلاستفاده است. در محیط ابری، ممکن است انجام عملیاتی برای بهروزرسانی یک ایندکس بهعنوان بخشی از همان تراکنش که دادهها را تغییر میدهد، ممکن یا مناسب نباشد. در آن صورت، گزینه یکپارچگی تدریجی (eventually consistent) مناسبتر است که در نتیجه اطلاعاتی در مورد مسائل مربوط به یکپارچگی تدریجی را ارائه میدهد.
الگوهای زیر نیز ممکن است هنگام اجرای این الگو مرتبط باشند:
* Sharding pattern. الگوی index table اغلب در ارتباط با دادههای تقسیمبندیشده با استفاده از خردهها (shards) استفاده میشود. الگوی Sharding اطلاعات بیشتری در مورد نحوه تقسیم یک data store به مجموعهای از shardها ارائه میدهد.
* Materialized View pattern: بهجای ایندکس کردن دادهها برای پشتیبانی از کوئریها که دادهها را خلاصهبندی میکنند، شاید بهتر باشد که یک materialized view از دادهها ایجاد کنیم.