قدرت SQL فقط در ذخیرهسازی دادهها نیست بلکه در تضمین یکپارچگی دادهها (Data Integrity)، اجرای کارآمد کوئریهای پیچیده و پشتیبانی اصولی از دستکاری دادهها نهفته است. اما این موارد به تنهایی برای توسعهدهندگان SQL کافی نیست و حیاتیترین فاکتور برای دولوپرها، پرفورمنس (عملکرد) SQL است، چراکه مستقیماً بر موارد زیر تاثیر میگذارد:
وقتی SQL را بهینهسازی میکنیم، فقط سرعت را بالا نمیبریم بلکه تمام سیستم را متحول میکنیم. بهینهسازی پرفورمنس SQL به اجرای سریعتر کوئریها و بهبود پاسخگویی سیستم منجر میشود. با بهینهسازی SQL، برنامهها میتوانند مجموعه دادههای بزرگتری را مدیریت و حجم زیادی از دادهها را بدون کندی پردازش کنند. بهینهسازی SQL به استفاده هوشمندانه از منابع سختافزاری کمک میکند و میتوانیم از منابع خود حداکثر استفاده را داشته باشیم. وقتی پرفورمنس را در نظر میگیریم، مجبوریم راهحلهای فنی زیباتر، تمیزتر و بهینهتری بنویسیم که این خود حاصل کدنویسی تمیزتر و استانداردتر است.
اما مهمتر از همه اینکه پرفورمنس عالی منجر به بهبود تجربه کاربری (User Experience) و در نهایت باعث پیشرفت یک کسبوکار میشود. در دنیای امروز، کاربران عاشق سرعت هستند و سریعتر بودن برنامهها، رضایت بیشتر کاربران را بههمراه میآورد و این امر مستقیما در موفقیت یک کسبوکار تاثیر میگذارد.
پس در چشمانداز کسبوکارهای دادهمحور امروز، تسلط بر بهینهسازی SQL دیگر لوکس محسوب نمیشود، بلکه یک ضرورت اجتناب ناپذیر است.
در این مقاله با هم:
بیایید شروع کنیم.
هنگام کار با پایگاهدادههای SQL، مشکلات پرفورمنسی گوناگونی میتوانند رخ دهند. وقتی دیتابیس کند میشود، معمولا بخاطر وجود یکسری الگوهای تکراری است که در ادامه آنها را بررسی میکنیم تا بتوانید سریعتر تشخیصشان دهید.
منظور از کوئریهای کند، کوئریهایی هستند که زمان زیادی طول میکشد تا پاسخ دهند. طراحی ناکارآمد، نبودن ایندکس، حجم زیاد داده و نیز طرحریزی ضعیف اسکیما (مثلاً دادههای تکراری زیاد یا جوینهای بیشازحد پیچیده) باعث میشوند که دیتابیس کارهای اضافی انجام دهد، در پردازش گیر کند و در نتیجه سرعت پائین داشته باشد.
وقتی چندتا کاربر بهطور همزمان با دیتابیس کار میکنند (یعنی تراکنشهای همزمان بهطور همزمان به یک داده دسترسی پیدا میکنند) دو مشکل اصلی پیش میآید:
قفلگذاری (Locking): منظور از قفلگذاری، مکانیزمی است که از تغییر همزمان دادههای یکسان توسط چندین تراکنش جلوگیری میکند. به بیان سادهتر وقتی یک تراکنش یک منبع داده خاص را قفل میکند، دسترسی یا تغییر سایر تراکنشها به آن منبع را تا زمانی که قفل آزاد شود، محدود مینماید.
به عنوان مثال فرض کنید دو نفر همزمان میخواهند یک موجودی بانک را کم کنند. دیتابیس برای اینکه مطمئن شود در موجودی اشتباهی رخ ندهد، یکی را قفل میکند تا دیگری محدود شود و صبر کند. حال اگر قفلها طولانی یا تعدادشان زیاد باشد، بقیه کاربران منتظر میمانند و کندی زیادی را تجربه میکنند.
رقابت (Contention): رقابت زمانی رخ میدهد که چندین تراکنش برای دسترسی به یک منابع واحد (مثلاً یک سطر خاص یا یک جدول شلوغ) با هم رقابت میکنند و در نتیجه، ممکن است تأخیر و تعارضات احتمالی صورت گیرد. چنانچه رقابت، درست مدیریت نشود، میتواند منجر به کاهش همزمانی (Concurrency) و کندی شود.
منابع ناکافی: گاهی مشکل از کد نیست و به زیرساخت برمیگردد؛ منابع سختافزاری ناکافی، مانند CPU یا حافظه (Memory)، میتوانند بر عملکرد پایگاهداده تاثیر منفی داشته باشند و آن را به شدت محدود کنند.
ضعف در Query Execution Plans : منظور از Query Execution Plan نقشهی راه یا نموداریست که نشان میدهد موتور پایگاه داده دقیقاً چگونه یک کوئری را پردازش میکند. نقشهها و نمودارهای اجرایی غیربهینه منجر به کندی میشوند. به عبارت دیگر گاهی اوقات دیتابیس، یک روند اجرایی را انتخاب میکند که اصلاً بهینه نیست (مثلاً به جای استفاده از ایندکس، تمام جدول را جستجو میکند). این یعنی کوئریهای ما بهصورت خودکار کند اجرا میشوند.
برای نجات سیستم باید استراتژیهای منظم داشته باشید. اولین گام برای رفع مشکلات عملکردی SQL، مانیتورینگ و عیبیابی است یعنی باید ابزارهای پایش را روشن کنیم تا ببینیم کدام کوئریها کند و غیربهینه هستند.
پس از مانیتورینگ و عیبیابی است که میتوانید کوئریهای SQL را بهینه کنید، استراتژیهای ایندکسگذاری را بهبود ببخشید، اسکیمای پایگاهداده را بازبینی کنید، مکانیزمهای کش (Caching) را پیادهسازی کنید، تعادل بار (Load Balancing) و مقیاسپذیری (Scaling) را اعمال کنید و در صورت نیاز سرور را ارتقا و منابع سختافزاری اضافی اختصاص دهید.
در این مسیر، ابزارهای پایش (Monitoring Tools) بهترین دوست ما هستند تا همیشه از پرفورمنس SQL مطمئن باشیم!
بیایید فرآیند پایش پرفورمنس SQL را بهصورت یک چکلیست عملیاتی با هم جلو ببریم. هدف نهایی این است که از حالت «حدس و گمان» خارج شویم و بر اساس دادههای واقعی مشکلات SQL را پیدا کنیم.
برای اینکه بتوانیم سیستم دیتابیس خود را مثل یه ساعت دقیق نگه داریم، باید اول بفهمیم چه اتفاقی در حال افتادن است. پس قبل از هر چیزی، لازم است دیتابیس خود را مجبور کنیم که گزارش دهد چه اتفاقی در احل افتادن است! این کار را با لاگگیری کوئری انجام میدهیم.
برای فعالسازی لاگگیری کوئری در یک سیستم مدیریت پایگاه داده SQL، باید به تنظیمات Configuration سیستم خود (DBMS) مراجعه کنید. در آنجا پارامتری تحت عنوان “query_log” یا چیزی مشابه آن وجود دارد که مرتبط با لاگگیری کوئری است. آن را روی “ON” یا “TRUE” تنظیم کنید تا فعال شود. در صورت نیاز، سطح جزئیات لاگ (Log Verbosity Level) را مشخص کنید. سپس تغییرات خود را ذخیره کنید و سرویس DBMS را مجدداً راهاندازی نمائید. حالا میتوانید کوئریهای تستی خود را اجرا کنید تا مطمئن شوید که لاگها بهدرستی ثبت میشوند یا خیر.
برای دستورالعملهای تکمیلی متناسب با سیستم خود، مستندات یا منابع ارائهشده توسط DBMS خاص خود را مطالعه کنید.
پس از جمعآوری دادهها در مرحلهی قبل، نوبت به تحلیل دادهها میرسد.
هر دیتابیس، ابزارهای پروفایلینگ پایگاه داده یا بهینهسازهای کوئری (Query Optimizers) مخصوص به خود را دارد. این ابزارها زمان اجرای کوئریها را ثبت و تحلیل میکنند و به ما این امکان را میدهند که کوئریهایی را که همواره عملکرد کندی دارند، شناسایی کنیم.
یکی از ابزارهای پروفایلینگ محبوب و کلاسیک، Microsoft SQL Server Profiler است که به توسعهدهندگان این امکان را میدهد فعالیت کوئریهای SQL Server را ثبت و تحلیل کنند. این ابزار پایش لحظهای، انتخاب رویدادهای سفارشی و قابلیت ردیابی کوئریها را برای شناسایی گلوگاههای پرفورمنسی فراهم میکند.
ابزار محبوب دیگر EXPLAIN در PostgreSQL است که Execution Plan کوئری (نمودار اجرای کوئری) را برای دستورات SQL تولید میکند و به شما میگوید دیتابیس دقیقا در حال انجام چه کاری است. در نتیجه به شناسایی عملیات ناکارآمد، مراحل پرهزینه و نقاط قابلبهینهسازی در روند اجرای کوئریها کمک میکند.
PostgreSQL افزونهای به نام pg_stat_statements را ارائه کرده است که برای تحلیل دقیق آمار کوئری و معیارهای پرفورمنسی کاربرد دارد.
ابزار دیگر، MySQL Workbench است که شامل یک پروفایلر کوئری میشود. این ابزار جامع به توسعهدهندگان اجازه میدهد زمان اجرای کوئریها را ثبت و تحلیل کنند، پلن کوئری (Query Plan) را بررسی و کوئریهای کند را شناسایی نمایند. اطلاعات بیشتر را اینجا بخوانید.
پایگاه داده Oracle ابزار قدرتمندی به نام SQL Tuning Advisor را با هدف بهینهسازی کوئریها عرضه کرده است. این ابزار قابلیت این را دارد که پرفورمنس کوئری را تحلیل کند، ایندکسها یا تغییرات ساختاری را پیشنهاد دهد و گزارشی جامع با رویکردهای اجرایی برای بهینه کردن کوئریها در اختیار شما قرار دهد. میتوانید جزئیات بیشتر را در وبسایت Oracle مشاهده کنید.
SQL Server Query Store که در Microsoft SQL Server 2016 معرفی شد، یک ویژگی داخلی است که پلنهای اجرایی کوئری و شاخصهای عملکردی را ثبت میکند. این ابزار این ابزار به شناسایی و رفع افت پرفورمنس کوئریها کمک کرده و به دولوپرها این امکان را میدهد که پرفورمنس کوئری را در طول زمان پایش کرده و تصمیمات بهینهسازی مبتنی بر داده اتخاذ کنند. بهترین شیوهها برای استفاده از این ابزار در وبسایت Microsoft موجود است.
در این مرحله باید مدتزمان متوسط اجرای کوئریها را پایش کنید و طولانیترین آنها را شناسایی کنید. به مصرف بالای CPU یا I/O توجه کنید و بر این اساس به دنبال عملیاتهای پرهزینه بگردید.
هشدارها را بر اساس آستانههای دیفالت برای زمان اجرای کوئری تنظیم کنید تا در صورتی که کوئریها از آن آستانهها فراتر رفتند، سریعا اعلان دریافت کنید و درلحظه از مشکلات پرفورمنسی دیتابیس مطلع شوید.
Query Execution Planها در درک نحوه عملکرد کوئریهای کند SQL بسیار مفید هستند.
به نمودار یا درخت سلسلهمراتبی از روند اجرای یک کوئری در دیتابیسها، Query Execution Plan میگویند. این نمودار جزئیات مهمی مثل ترتیب انجام عملیات، روش خواندن دادهها، میزان استفاده از از ایندکسها، تعداد سطرهای پردازششده و مقدار مصرف منابع (مثل CPU و حافظه) را به تصویر میکشد. با بررسی این درخت یا نمودار، میتوانید نقاط کندی را شناسایی کرده و با اصلاح آنها، سرعت و کارایی کل پایگاه داده خود را بهطور چشمگیری افزایش دهید.
بیشتر سیستمهای مدیریت پایگاه داده (DBMS) راههایی برای دریافت Query Execution Plan فراهم میکنند. از ابزارهایی مانند EXPLAIN، EXPLAIN ANALYZE یا ابزارهای پروفایلینگ کوئری خاص سیستم خود (DBMS) برای دریافت آنها استفاده کنید.
Query Execution Planها را دریافت کنید و در آنها به دنبال عملیاتهای پرهزینه، مانند اسکن کامل جدول یا حلقههای تو در تو بگردید، زیرا این نقاط احتمالا به بهینهسازی نیازمندند.
همانطور که پیشتر گفتیم Query Execution Planها معمولاً به صورت یک درخت سلسلهمراتبی یا زنجیرهای از عملیاتها نمایش داده میشود. هر عملیات نشاندهنده یک مرحله در اجرای کوئری (مانند اسکن جدول، جوینها یا جستجو در ایندکس) است. سعی کنید ساختار و جریان Query Execution Plan را به خوبی درک کنید تا دریابید چه عواملی بر پردازش کوئری تأثیر دارند.
هزینههای تخمینی یا واقعی مرتبط با هر عملیات در نمودار را ارزیابی کنید و مقدار تقریبی منابع مورد نیاز (مانند CPU و I/O) برای آن عملیات را محاسبه کنید. به عملیاتهایی با هزینه بالاتر عمیقتر بپردازید، زیرا آنها معمولاً بیشترین تأثیر را بر عملکرد کوئری دارند.
در انتها، به کوئریهای کند نگاهی بیندازید و ببینید آیا الگوی مشترکی میان آنها وجود دارد؟ آیا آنها شامل جوینهای پیچیده هستند؟ آیا همه آنها با دادههای خیلی بزرگ سروکار دارند؟
شناسایی این الگوهای مشترک در میان کوئریهای کند میتواند درک شما از مسائل زیربنایی را بالا ببرد و کمکتان کند تا مسائل عملکردی را بهصورت سیستماتیک برطرف کنید.
فرض کنید دیتابیس یک کتابخانهی عظیم است وما در آن دنبال یک کتاب خاص میگردیم. بدون ایندکس، برای پیدا کردن یه کتاب باید کل کتابخانه را با تکتک کتابهایش چک کنیم! ایندکس مثل فهرستی است که کتابدار در کتابخانه در اختیار دارد و به ما میگوید آن کتاب دقیقا در کدام قفسه قرار دارد.
با مثال فوق میتوان دریافت که تا چه اندازه بهینهسازی ایندکسها برای بهبود سرعت اجرای کوئریها و کارایی کلی پایگاه داده حیاتی است. وقتی ایندکس بهینه داشته باشید، کوئریهای شما (درخواستهای دیتابیس) خیلی سریعتر اجرا میشوند و سیستم، روانتر کار میکند.
یکی از مهمترین اقدامات در بهینهسازی ایندکسها، انتخاب ستونهای مناسب برای گنجاندن در ایندکسهاست.
حتما برایتان این سوال پیش میآید که کدام ستونها را ایندکس بزنید؟
1-ستوانهایی که تمایزپذیری (Selectivity) بالا دارند: یعنی مقادیر تکراری کم دارند. مثلاً «کد ملی» یا «ایمیل» چون هر کدام مقادیر خاص و یکتا دارند، ایندکس کردنشان عالی محسوب میشود اما «جنسیت» (مرد/زن) چون فقط دو حالت دارد، ایندکس کردنش کمکی به شما نمیکند و فقط منجر به اشغال کردن فضا میشود.
2- ستونهایی که در شرطهای WHERE، JOIN یا ORDER BY زیاد از آنها استفاده میکنید.
بنابراین از ایندکسگذاری روی ستونهایی با تمایزپذیری پایین یا آنهایی که به ندرت در کوئریها استفاده میشوند، خودداری کنید تا از ایجاد سربار (Overhead) غیرضروری جلوگیری شود.
همه کوئریها به یک اندازه مهم نیستند. آنهایی که روزانه هزاران بار اجرا میشوند، بیشترین فشار را به سیستم وارد میکنند و تاثیر قابل توجهی بر پرفورمنس کلی سیستم ما دارند. پس باید اولویتمان را به سریعتر کردن آن کوئریها اختصاص دهیم. با تحلیل نمودار اجرای کوئریها (Execution Plan) میتوانیم بفهمیم ایندکسهای موجود، قابل ارتقا هستند یا نه.
ایندکسها با گذشت زمان و تغییر دادهها، تکهتکه (Fragmented) میشوند؛ درست مانند خانهای که با اضافه کردن و جابجایی وسایل در آن، دچار بینظمی شده و پیدا کردن وسایل در آن دشوار میشود.
باید به صورت دورهای ایندکسها را مرتب (بازسازی یا سازماندهی مجدد-Reorganize یا Rebuild) کنید تا دیتابیس بتواند سریعتر به دادهها دسترسی پیدا کند.
فرض کنید یک سایت فروشگاهی دارید و میخواهید بدانید قیمت یک محصول چقدر است. برای یافتن قیمت دو حالت وجود دارد:
با توجه به مثال فوق، در نظر گرفتن ایندکسهای پوششی (Covering Indexes) از آنجا که باعث میشود تمام ستونهای مورد نیاز در خود ایندکس گنجانده شود، میتواند نیاز به جستجوهای اضافی را حذف کرده و منجر به اجرای سریعتر کوئریها شود.
ابزارها و ویژگیهایی در پایگاه داده وجود دارند که برای ایندکسگذاری طراحی شدهاند و مانند یک مشاور هوشمند به شما میگویند مثلا «اگر فلان ایندکس را ایجاد کنی، سرعتت ۵۰ درصد بهتر میشه». Database Engine Tuning Advisor (DTA) یا ویژگی Query Store در Microsoft SQL Server نمونهای از این ابزارها و ویژگیها هستند. ولی یادتان باشد هر تغییری که در ایندکسها اعمال میشود باید به دقت آزمایش و اعتبارسنجی شود. پس قبل از اعمال تغییرات، حتماً تست کنید تا مطمئن شوید مشکل جدیدی ایجاد نمیکنند و پیامد نامطلوبی در پی ندارند.
فرض کنید دیتابیس شما انباری بزرگ است و برنامهی شما کارگری است که بیرون آوردن کالاها از آن انبار است. بزرگترین اشتباه اینست که از SELECT * استفاده کنید (به کارگر بگویید همه کالاها را بیاورد). در این صورت دیتابیس مجبور میشود تمام انبار را بگردد و اطلاعات اضافی را هم سمت برنامه ارسال کند.
در نتیجه برای افزایش پرفورمنس، باید تنها دادههای ضروری را بازیابی کنید تا مقدار دادههای منتقلشده بین پایگاه داده و برنامه به حداقل برسد. فقط ستونهایی که مورد نیاز است به صراحت مشخص و از استفاده ازSELECT * خودداری کنید. به این ترتیب عملیات I/O و ترافیک شبکه کاهش یافته و کوئری، سریعتر اجرا میشود.
نکته طلایی: در نظر بگیرید که برای کاهش فشار روی دیتابیس، به جای بازیابی و تجمیع مجموعهنتایج بزرگ در لایه برنامه، از توابع تجمعی (Aggregate Functions) مانند SUM یا AVG مستقیماً در کوئریها استفاده کنید. به عنوان مثال اگر قصد دارید میانگین قیمت یا جمع کل فروش را بدانید، اجازه ندهید برنامه همه قیمتها را استحراج کند و بعد با هم جمع بزند! بلکه بگذارید خود دیتابیس با دستورSUM این کار را انجام دهد.
کوئریهای خود را مرتبا ساختاردهی کنید تا عملیات غیرضروری را به حداقل برسانید.
پیشگیری از ضرب دکارتی: در هنگام پیوند دادن دو جدول، با مشخصسازی شرایط اتصال (Join conditions) مناسب، از ایجاد حاصلضرب دکارتی (Cartesian products) یا همان cross joins خودداری کنید. به زبان سادهتر، وقتی دو جدول را به هم وصل میکنید (Join)، حتماً شرط اتصال را مشخص کنید. در غیراینصورت، دیتابیس همه ردیفهای جدول اول را با همه ردیفهای جدول دوم ترکیب میکند (Cartesian Product) که این فاجعه محسوب میشود و سیستم را قفل میکند!
فیلتر زودهنگام با کمک Where: از WHERE استفاده کنید تا دیتابیس در مراحل اولیهی اجرای کوئری، دادهها را فیلتر کرده، دادههای اضافی را دور بریزد و فقط روی اطلاعات مورد نظر متمرکز شود.
انتخابهای هوشمندانه: گاهی اوقات استفاده از IN یا EXISTS یا نوشتن یه Sub-query (زیرکوئری) هوشمندانه، خیلی بهتر از نوشتن چند JOIN پیچیده است.
سادهسازی: کوئریهای طولانی و پیچیده را همیشه بازبینی کنید. شاید بتوانید با یک تغییر کوچک، آنها را سادهسازی و سریع کنید.
یک بانک جهانی بخاطر استفاده از کوئریهای پیچیده شامل چندین پیوند (Joins) و شرایط فیلتر، با در تولید گزارشها با کندی مواجه بود. تیم فنی با اجرای بهترین شیوههای بهینهسازی کوئری، از جمله ایجاد ایندکسهای دقیق و هدفمند روی ستونهای مهم و سادهسازی منطق کوئریها، پرفورمنس را بهطور چشمگیری ارتقا دادند. زمان پردازش کوئریها از چند دقیقه به چند ثانیه کاهش یافت و مشتریان خیلی سریعتر میتوانستند به اطلاعات لحظهای حساب بانکی خود دست پیدا کنند.
بگذارید مبحث مدلسازی دادهها را با یک مثال ساده برایتان باز کنیم: فرض کنید قصد داریم یک کتابخانه با هزاران جلد کتابایجاد کنیم. اگر برای این کتابخانه قفسهبندی در نظر نگیریم، حتی با سریع جستجوها هم پیدا کردن یک کتاب خاص واقعا دشوار خواهد شد.
این مثال روشن میکند که مدلسازی دادهها تا چه میزان برای بهینهسازی پرفورمنس SQL ضروری است. اگر از بهترین شیوههای مدلسازی استفاده کنید، میتوانید پایگاهدادههایی را طراحی کنید که برای اجرای کوئریها و بازیابی دادهها بهینه شدهاند. در ادامه، برخی از شیوههای دستکاری دادههای SQL، آورده شده است:
۴ تا قانون طلایی در زمینه مدلسازی دادهها برای اینکه دیتابیس شما سریع و سبک باشد در ادامه آورده شده است:
اولین قدم این است که دادهها را نرمالسازی کنید. یعنی هر داده فقط در یک جا ذخیره شود و از افزونگی داده خودداری کنید. از بهترین شیوههای نرمالسازی پیروی کنید تا از تکرار دادهها جلوگیری و یکپارچگی دادهها را حفظ نمائید. با این کار، مقدار دادههایی که باید دستکاری شوند، کاهش یافته و عملکرد کوئری بهبود مییابد.
بگذارید با یک مثال، به درک بهتر موضوع کمک کنیم: چنانچه آدرس مشتری را هم در جدول سفارشات و هم در جدول مشتریان ذخیره کنید و هم در جداولی دیگر ذخیره کنید، اگر آدرس مشتری تغییر کند، باید ۱۰۰ جا را آپدیت کنید! این کار هم زمانبر است و هم احتمال خطا را بالا میبرد.
گاهی اوقات لازم است برای سرعت بیشتر، عمدا کمی «تکرار» ایجاد کنیم! غیرنرمالسازی شامل افزودن دادههای تکراری یا ترکیب جداول برای ساده کردن کوئریهای پیچیده و کاهش عملیات پیوند (Join) است. در غیرنرمالسازی باید بخشهایی از مدل داده که میتوانند تاثیر قابلتوجهی بر سرعت کوئری داشته باشند را با دقت شناسایی و آنها را غیرنرمال کنید.
مثال: فرض کنید میخواهیم «نام مشتری» را علاوه بر جدول مشتریان، در هر فاکتور هم ذخیره کنیم. در اینصورت وقتی میخواهیم فاکتور را چاپ کنیم، نیازی نیست هربار جدول مشتریان چک کنیم و مستقیم از فاکتور نام مشتری را میخوانیم.این کار عملیات Join را کم کرده و سرعت را بالا میبرد.
نکته: غیرنرمالسازی را فقط برای مواردی که به سرعت بالا نیاز دارید، بکار ببرید و در مواردی که واقعا ضرورتی ندارد، ازغیرنرمالسازی خودداری کنید چرا که منجر به اشغال شدن فضای بیشتر از دیتابیس میشود.
برای بهبود ذخیرهسازی و پردازش داده، انواع دادههای مناسب را انتخاب کنید. از انواع دادهای که با ماهیت دادههای ذخیرهشده مطابقت دارند استفاده کنید تا نیازهای ذخیرهسازی به حداقل برسند و استفاده از حافظه بهینه شود.
از انواع دادهای که بهطور غیرضروری بزرگ هستند، خودداری کنید و بدانید که همیشه بهتر است از اعداد صحیح (Integers) یا انواع دادهی با اندازه کوچکتر که فضای کمتری میگیرند و پردازش سریعتری دارند استفاده کنید.
اگر جدولی دارید که میلیونها رکورد دارد (مثلاً تاریخچه تراکنشهای ۱۰ ساله)، اسکن کل آن جدول مثل پیدا کردن یک سوزن در انبار کاه است!
در چنین شرایطی بهتر است جدول را بر اساس معیارهای منطقی (مثلاً سال یا ماه) به بخشهای کوچکتر (Partition) تقسیم کنید در نتیجه وقتی مثلا میخواهیم تراکنشهای سال ۱۴۰۲ را ببینیم، دیتابیس فقط همان بخش را اسکن میکند و نیازی نیست کل جدول را جستجو کند.
پس بطور کلی باید جداول بزرگ را با تقسیم دادهها به پارتیشنهای کوچکتر و قابلمدیریت، پارتیشنبندی (Partition) کنید. این کار امکان بازیابی و دستکاری سریعتر دادهها فراهم میکند. برای پارتیشنبندی جداول از معیارهای منطقی، مانند بازههای زمانی یا مقادیر کلیدی، استفاده میشود.
یک شرکت فناوری پیشرو که به سرعت در حال رشد بود، حجم عظیمی از داده در بخشهای مختلف داشت. آنها هنگام اجرای کوئریهای پیچیده برای تحلیل داده، با مشکلات متعددی روبرو بودند. برای رفع این مشکلات تیم فنی اقدامات زیر را انجام داد:
نتیجه اینکه سرعت گزارشگیری از چند دقیقه به چند ثانیه رسید و مدیران میتوانستند سریعتر تصمیم بگیرند.
پس یادتان بماند:
مدلسازی خوب یعنی تعادل بین نظم (برای حفظ داده) و سرعت (برای بازیابی داده).
«کشینگ» (Caching) یا همان «حافظه پنهان»، مثل یک میز کار مرتب و منظم برای برنامهی شما عمل میکند تا لازم نباشد هر بار برای پیدا کردن یه وسیله، بروید کل اتاق را بگردید. استفاده از کشینگ (Caching) در پایگاه دادههای SQL، یک استراتژی کارآمد برای بهبود عملکرد و کاهش زمان پاسخگویی کوئریهاست.
وقتی یک کوئری سنگین و پرتکرار داریم، هر بار اجرا کردنش فشار زیادی به سرور وارد میآورد. کش کردنِ نتایج این کوئریها، زمان را ذخیره میکند. وقتی همان کوئری دوباره اجرا میشود، به جای اجرای مجدد آن، نتایج را از کش دریافت کنید. این کار، بار روی سرور پایگاه داده را کم کرده و زمان پاسخگویی کوئری را بهبود میدهد.
سیستمهای مدیریت پایگاه داده (DBMS)، مکانیزمهای کشینگ داخلی مانند کشهای حافظه (Memory Caches) یا کشهای کوئری (Query Caches) را در خود دارند. با فعال کردن ویژگیهای کشینگ در دیتابیس، دادههای پرتکرار و نتایج کوئری در حافظه (RAM) نگهداری میشود. از آنجا که رم بسیار سریعتر از هارد دیسک است، دفعه بعد که خواستیم همان کوئری را اجرا کنیم، بجای اجرای دوباره، پایگاه داده، نتیجه را از رم در اختیار ما میگذارد. بدین ترتیب سرعت بالاتری را تجربه میکنیم و سرور فشار کمتری را متحمل میشود.
گاهی اوقات کشینگ دیتابیس بهتنهایی کافی نیست یا میخواهیم کنترل بیشتری بر کشینگ داشته باشیم. در چنین شرایطی میتوانیم مکانیزم کشینگ را در لایهی برنامه پیادهسازی نمائیم.
ابزارهای خارجی مثل Redis یا Memcached انبارهای داده درونحافظهای در اختیار ما میگذارند. این ابزارها در واقع دیتابیسهای کوچک و فوقسریعی هستند که در حافظهی رم اجرا میشوند. بهعنوان مثال شما در کد برنامهی خود چک میکنید: «آیا این داده را قبلاً کش کردم؟» اگر بله، از Redis میگیرم؛ اگر خیر، از دیتابیس اصلی میگیرم و میگذارمش در Redis. بدین ترتیب بار از روی دیتابیس اصلی برداشته میشود.
از تکنیکهای کشینگ سمت کلاینت (Client-side Caching) برای ذخیره دادههای پربازدید درون برنامه (موبایل یا دسکتاپ) کلاینت یا مرورگر کاربر استفاده میشود. اینجا دیگر با سرور و دیتابیس سروکاری ندارید. با کشینگ سمت کلاینت تعداد دفعات رفتوبرگشت به سرور کاهش پیدا میکند که به معنای پاسخگویی سریعتر و بار شبکهی کمتر است.
برای درک بهتر فرض کنید کاربر لیست محصولات موجود در یک سایت را مشاهده میکند. ما این لیست را در مرورگر کاربر ذخیره میکنیم و دفعهی بعد که کاربر همان صفحه را باز کرد، به جای اینکه درخواستی به سرور ارسال شود، دادهها از مرورگر خوانده میشوند.
همانطور که میدانید کش همیشه بهروز و آپدیت نیست. بطور مثال اگر قیمت یک محصول در دیتابیس تغییر کند، کش باید آپدیت شود پس باید مکانیزمی تعبیه شود که تضمین کند دادههای کش بهروز باقی میمانند. برای همگامسازی کش با دادهها از انقضای مبتنی بر زمان، انقضای مبتنی بر رویداد، یا انقضای دستی بر اساس تغییرات داده استفاده میشود.
مثال برای انقضای مبتنی بر زمان: هر 10 دقیقه کش را پاک کن و از نو بگیر
مثال برای انقضای مبتنی بر رویداد: هرگاه ادمین محصولی را ویرایش کرد، بلافاصله کش مربوط به آن محصول را پاک کن.
فعال کردن کش، همه کاری نیست که باید انجام دهید. همین که کش را فعال کردید باید ببینید که چطور دارد کار میکند!
پس از فعال کردن کش باید بهطور منظم معیارهای عملکرد کش، مانند نرخ برخورد (Hit Ratio) و کارایی کش را مانیتور کنید.
نرخ برخورد (Hit Ratio): یعنی چند درصد دفعات، داده را از کش دریافت کردید (خوب است) و چند درصد دفعات مجبور شدید بروید سراغ دیتابیس اصلی (بد است). / نرخ برخورد پائین بد است و به این معناست که کشینگ به درستی انجام نشده است.
الگوهای استفاده کشینگ سیستم خود را تحلیل کرده و اندازه کش، سیاستهای حذف (Eviction Policies) یا استراتژیهای کشینگ را متناسب با آن تنظیم کنید. پیکربندیهای کشینگ را دائما بهتر کنید تا به بهترین پرفورمنس برسید.
بخش تحلیل داده (Analytics) از یک شرکت بزرگ هر روز تعداد بالایی گزارش پیچیده ارائه میکرد اما زمان تولید گزارشها و پاسخ کوئریها کند و آزاردهنده بود و تصمیمگیری مدیران را مختل میکرد. برای رفع این مشکل، تیم مهندسان استراتژیهای کشینگ را پیاده کردند و در نتیجه با کش کردن دادههای پرتکرار، عملکرد کوئریها به طرز قابل توجهی بهتر شد. همین اقدام میزان بهرهوری مجموعه را بالا برد و فرهنگ دادهمحور را در شرکت تقویت کرد.
کشینگ یعنی «جلوگیری از کار تکراری». هر جا دیدید دارید یک عملیات سنگین و کوئری پر مصرف را تکرار میکنید، آن را در یک جای امن (رم، مرورگر، یا کش خارجی) بگذارید تا دفعهی بعد نتیجه را از آنجا دریافت کنید. فقط یادتان بماند مکانیزم همگامسازی (Invalidation) را فراموش نکنید تا دادهها قدیمی نشوند و از دست نروند.
نرمافزار و کدهای شما هرچقدر هم که خوب باشند و درست عمل کنند، اگر سختافزار ضعیف داشته باشید یا پیکربندی نامناسبی داشته باشند، کند عمل خواهند کرد.
بیایید دوباره به مثال کتابخانه برگردیم. تصور کنید دیتابیس یک کتابخانهی عظیم است. هر چقدر این کتابخانه را بهتر بچینیم (راهروها، قفسهها و کتابها)، کتابها سریعتر پیدا میشوند.
در گذشته از هاردهای چرخشی (HDD) استفاده میشد که متحرک و کند بودند. امروزه از درایوهای حالت جامد (SSD) یا آرایههای RAID استفاده میشود و از آنجا که SSDها هیچ قطعه متحرکی ندارن، سرعتی چند ده برابر هاردهای قدیمی چرخشی دارند.
نکته: در این درایوها به عدد IOPS دقت کن. این یعنی سرور قادر است در ثانیه چند عملیات خواندن/نوشتن انجام دهد. IOPS به معنای سرعت بالاتر است.
رم را میتوان به میز کار تشبیه کرد. هرچقدر میز بزرگتر باشد میتوانید کتابهای بیشتری را باز بگذارید و نیازی نیست مدام سراغ قفسهها (دیسک) بروید. پس مقدار کافی RAM را به سرور پایگاه داده اختصاص دهید. با این کار دیتابیس میتوانید دادههای پرتکرار (کشینگ) و Query Execution Planهای بیشتری را در رم نگه دارد. بدیهی است که وقتی داده در رم باشد، دسترسی به آن در کسری از ثانیه امکانپذیر است. نتیجه اینکه ورودی/خروجی دیسک (Disk I/O) کاهش یافته و پرفورمنس کلی دیتابیس بهتر میشود.
پایگاه داده را طوری پیکربندی کنید که از حافظه بصورت کاملا بهینه استفاده کند، با تنظیماتی مانند اندازه بافرپول (Buffer Pool) یا کش کوئری (Query Cache) بر اساس سیستم پایگاه داده خود، پایگاه دادهتان را طوری پیکربندی کنید که بهینهترین استفاده از حافظه را داشته باشد.
مطمئن شوید سرور پایگاه داده، CPU کافی برای مدیریت بار کاری دارد. از پردازندههای چند هستهای برای اجرای موازی کوئریها استفاده کنید. دیتابیسهای مدرن که پردازنده چند هستهای دارند میتوانند به صورت موازی چند کوئری را همزمان اجرا کنند اما در پردازندههای تکهستهای، کوئریها باید در صف و نوبت قرار بگیرند.
اطمینان حاصل کنید تنظیمات پایگاه داده چندهستهای شما طوری است که بار کاری را بهطور مساوی بین هستههای موجود توزیع میکند.
سرور دیتابیس و سرور برنامه (یا مرورگر کاربر) باید با هم در ارتباط باشند. ما بهعنوان توسعهدهنده باید این ارتباط را تا جای ممکن بهینه کنیم.
پهنای شبکه باید کافی باشد که تاخیر (Latency) به حداقل برسد و دادهها سریعا منتقل شوند. همچنین روشهایی مانند فشرده کردن دادهها (Compression) قبل از ارسال و کشینگ در لایه شبکه کمک میکند که بار اضافی انتقال را کم کنید.
اگه بار کاری خیلی زیاد باشد، حتی ممکن است یک سرور قوی را هم له کند! بنابراین زیرساخت پایگاه داده را به صورت مقیاسپذیر (مقیاسپذیری افقی یا شاردینگ) طراحی کنید. به این ترتیب میتوانید بار کاری را بین چند سرور تقسیم کنید تا تقاضاهای افزایشیافته را مدیریت کنید. مکانیزمهای تعادلدهی بار (Load Balancing) نیز کمک میکنند تا کوئریها به طور مساوی بین سرورهای پایگاه داده توزیع شوند.
اجازه ندهید سختافزارتان خراب شود. اجزای سختافزار را به صورت منظم چک کنید. سلامت دیسک، دمای CPU و سلامت هارد دیسک را مدام زیرنظر داشته باشید و درایورها و فریمور (Firmware) را آپدیت کنید. این کارها از خرابیهای ناگهانی پیشگیری میکنند و عملکرد دیتابیس را پایدار نگه میدارند.
فرض کنید در دنیای موازی یک شرکت بورس دارید که ثانیهای هزاران معامله انجام میدهد؛ یعنی یک میز معاملاتی شلوغ که اتفاقا مشکلات زیادی دارد، سیستمش کند شده و قیمتها دیر آپدیت میشوند و شما به طرز دیوانهکنندهای در حال ضرر کردن هستید و زمان زیادی هم برای عیبیابی ندارید!
در چنین شرایطی باید سراغ راهحلهای سختافزاری بروید؛ هاردهای قدیمی را با SSD پرسرعت عوض کنید (برای نوشتن سریع معاملات)، رم را ارتقا دهید تا دادههای لحظهای بازار در رم بماند، از CPUهای چند هستهای استفاده کنید تا بتوانید هزاران معامله را همزمان پردازش کنید. سیستم تعادلدهی بار (Load Balancer) تعبیه کنید تا اگر یک سرور شلوغ شد، ترافیک سراغ سرورهای دیگر برود.
نتیجه اینکه معاملات شما با سرعت نور انجام خواهد شد و تحلیل بازار را به صورت لحظهای در اختیار خواهید داشت.
یادتان باشد:
سختافزار خوب مثل بنزین باکیفیت برای یک ماشین مسابقه است؛ بدون آن، بهترین کدها هم نمیتوانند سرعت واقعی خود را نشان دهند!
این بخش مربوط به «مدیریت فضا و سرعت» است. یعنی چطور با کمترین فضا، بیشترین سرعت را از دیتابیس بگیریم.
فرض کنید دیتابیس یک انبار بزرگ و شلوغ است. قرار است راهحلهایی بدهیم که چطور این انبار را مرتبتر، کوچکتر و سریعتر کنیم.
در روش سنتی (Row-based) دادهها مثل یک جدول اکسل ذخیره میشوند: سطر اول، سطر دوم و…
در این روش، اگر بخواهیم مثلا فقط «ستون حقوق» را برای هزار نفر حساب کنیم، سیستم باید تمام سطرهای هزار نفر را بخواند-حتی اگر به بقیه ستونها (مثل نام و آدرس) نیاز نداشته باشد. این کار زمانبر است و بهتر است به جای استفاده از فرمت ذخیرهسازی مبتنی بر سطر (Row-based storage)، فرمت ذخیرهسازی ستونی (Columnar storage) را در نظر بگیرید؛ یعنی همه حقوقها پشت سر هم، همه نامها پشت سر هم و ... به این ترتیب، فقط ستون مورد نیاز خوانده میشود که هم فضای کمتری اشغال میشود و هم سرعت کوئریهای تحلیلی بالا میرود.
این فرمت برای انبارهای داده (Data Warehouses) و بارهای کاری تحلیلی که عملکرد کوئری در آنها حیاتی است، بسیار مؤثر است. این فرمت امکان فشردهسازی بهتر و کاهش ردپای ذخیرهسازی (Storage Footprint) را فراهم میکند.
همونطور که میدانید، فایلهای فشرده (مثل ZIP) حجم کمتری دارند. دیتابیسها هم این قابلیت را دارا هستند و با فشردهسازی دادهها، فضای ذخیرهسازی موردنیازشان نیز کمتر میشود. فواید فشردهسازی دادهها عبارتند از:
فضای کمتر: دیتابیس کوچکتر و هزینه هارد دیسک کمتر میشود.
سرعت بیشتر: وقتی داده فشرده است، حجمش کمتر است، پس I/O کمتر است و انتقال داده کمتر = سرعت بیشتر.
اکثر سیستمهای مدیریت پایگاه داده (DBMS) گزینههای فشردهسازی داخلی مانند فشردهسازی در سطح صفحه (Page-level compression) یا فشردهسازی مبتنی بر دیکشنری (Dictionary-based compression) را ارائه میدهند.
همانطور که در قسمتهای ابتدایی این مقاله هم اشاره کردیم ایندکسها نقش حیاتی در عملکرد کوئری دارند، اما میتوانند مقدار قابل توجهی از فضای ذخیرهسازی را اشغال کنند. فعال کردن فشردهسازی ایندکس، ردپای ذخیرهسازی ایندکسها را بدون قربانی کردن عملکرد کوئری کاهش میدهد. این کار در کاهش هزینههای ذخیرهسازی نقش دارد.
فرض کنید جدولی دارید که ۱۰ میلیون رکورد دارد. بدیهی است که جستجو در این حجم از داده چقدر دشوار است. در چنین شرایطی راهکار این است که جدول را به تکههای کوچکتر و قابل مدیریتتر تقسیم کنیم. مثلاً بر اساس سال: پارتیشن ۱۴۰۰، پارتیشن ۱۴۰۱ و…
در این حالت هنگامی که کاربر دنبال دادههای سال ۱۴۰۱ میگردد، دیتابیس فقط همان پارتیشن سال ۱۴۰۱ را اسکن کرده و بقیه ۹ میلیون رکورد را نادیده میگیرد.
از تکنیکهای پارتیشنبندی برای توزیع دادهها در چندین دستگاه ذخیرهسازی یا گروه فایل استفاده میشود. پارتیشنبندی امکان مدیریت کارآمد جداول بزرگ را با تقسیم آنها به قطعات کوچکتر و قابلمدیریتتر برای ما فراهم میکند. از طریق پارتیشنبندی، با حداقل کردن مقدار دادهای که در حین اجرای کوئری دسترسی به آن صورت میگیرد، رقابت ورودی/خروجی (I/O Contention) کاهش یافته و عملکرد کوئری بهتر میشود.
همه دادهها نیاز نیست همیشه «زنده» و در دسترس باشند. بهتر است دادههای قدیمی یا دادههایی که بهندرت استفاده میشوند را از دیتابیس اصلی حذف کنیم و آنها را در فرمتهای فشرده در هاردهای ارزانتر آرشیو کنیم تا دیتابیس اصلی سبک و آزاد شود.
همه دادهها ارزش یکسانی ندارند. بعضی دادهها پرمصرف و برخی دیگر کممصرفند. بهتر است یک مکانیزم ذخیرهسازی برای دادههای مختلف با ارزشهای مختلف در نظر بگیریم:
با لایهبندی پویای دادهها بر اساس الگوهای دسترسی، میتوان تعادل بهینهای بین عملکرد و هزینه را به دست آورد.
بخش «ریسک و انطباق» در یک موسسه مالی باید بطور مداوم گزارشهای سنگینی از تراکنشهای چند سال اخیر خود تهیه میکرد. دیتابیس این بانک کند شده، فضاها اشغال شده و گزارشگیری ساعتها بهطول میانجامید.
تیم فنی تصمیم گرفت ذخیرهسازی دادهها را به فرمت ستونی تغییر دهید تا گزارشگیری سریعتر شود. همچنین عملیات فشردهسازی روی دادهها انجام شد و حجمی که دادهها اشغال میکردند کاهش یافت و سرعت خواندن دادهها چند برابر شد.
اقدام دیگر این بود که دادههای خیلی قدیمی را آرشیو کردند و دادههای جدید را روی SSD قرار دادند که دسترسی لحظهای به آنها داشته باشند. در نتیجه اینکه زمان دریافت گزارش از چند ساعت به چند ثانیه کاهش یافت.
برای بهینهسازی فضا و سرعت:
بگذارید بحث فشردهسازی در SQL را به زبان ساده و خودمانی باز کنیم: اینبار فرض کنید که دیتابیسُ یک انبار بزرگ پر از جعبه است. اگر این جعبهها را فشرده کنیم، فضای کمتری اشغال میشود و هزینه اجاره انبار برای ما کمتر میشود ولی یک نکته مهم وجود دارد: هرچقدر جعبهها را بیشتر فشرده کنیم، باز کردن این جعبهها و دسترسی به محتویات آنها سختتر میشود! پس هنر اصلی این است که نقطه تعادل را پیدا کنیم. تعادل میان نرخ فشردهسازی (Compression Ratio) و سرعت کوئری، کلید اصلی بهینهسازی عملکرد پایگاه دادههای SQL است.
برای دستیابی به «تعادلی» که به آن اشاره کردیم، باید موارد زیر را رعایت کنید:
یک استارتاپ تازهتاسیس که رشد خیلی سریعی داشت و تعداد کاربرانش بهشدت در حال افزایش بودند، حجم دادههایش داشت به نقطهی انفجار میرسید. تیم فنی میدانست باید برای مقیاسپذیری حتما دیتابیس را فشردهسازی کند و فضای بیشتری از دیتابیس آزاد کند اما مرتکب یک اشتباه جدی شد؛ آنها فکر میکردند هرچقدر بیشتر فشردهسازی کنند، بهتر است. اما نتیجه چه بود؟ وقتی بیشازحد فشردهسازی انجام دادند، سیستم برای بازکردن دادهها خیلی کند شد و کاربرها دیگر نمیتوانستند سریعا جستجو انجام دهند.
تیم فنی در مواجهه با این مشکل، سریعا دستبهکار شد و به سراغ تحلیل دادهها رفت و دادههای پرتکرار و مهم را از دادههای کممصرف تفکیک کرد. پس از آن، روشهای مختلف فشردهسازی را تست کردد تا ببیند کدام روش بهتر جواب میدهد. سپس میزان فشردهسازی را برای دادههای مهم، کمتر و برای دادههای غیرمهم بیشتر کرد. آنها با انجام این کارها به نقطه ظریف و طلایی تعادل میان نرخ فشردهسازی و سرعت کوئری رسیدند.
این اقدامات عملکرد پایگاه داده این استارتاپ را به اوج خود رساند و تیم آنها را توانمند ساخت تا تجربهای بینقص به کاربران ارائه و اندازه مجموعه خود را با اطمینان گسترش دهند.
فشردهسازی دقیقا مانند یک شمشیر دو لبه است. اگر بدون فکر و فقط برای کم کردن فضا انجام شود، سرعت را نابود میکند. اما اگر هوشمندانه و بر اساس نیاز واقعی تنظیم شود، هم هزینه را نجات میدهد و هم سرعت را بالا میبرد.
باز هم باید به مثال کتابخانه مراجعه کنیم : ) فرض کنید میخواهیم یک کتابخانه خیلی بزرگ تاسیس کنیم. اگر تمام کتابها را در یک انبار شلوغ روی هم بریزیم، پیدا کردن یک کتاب خاص تقریبا غیرممکن میشود. پارتیشنبندی به این مفهوم است که این انبار بزرگ را به اتاقهای کوچکتر و منظمتر (بر اساس یک قانون مشخص) تقسیم کنیم. پارتیشنبندی کتابخانه از یک طرف باعث میشود سریعتر کتاب مورد نظر خود را پیدا کنیم (مثلا اگر به دنبال کتاب «بوف کور» میگردیم کافیست به اتاق «رمان فارسی» مراجعه کنیم) و از طرف دیگر هر موقع یک اتاق پر شد، میتوانیم اتاق جدیدی اضافه کنیم، بدون اینکه کل کتابخانه را به هم بریزیم!
مثال فوق بهروشنی نشان میدهد که پارتیشنبندی مؤثر، راهی ارزشمند برای بالابردن پرفورمنس و مقیاسپذیری پایگاه دادههای SQL است اما سوالی که مطرح میشود این است که چطور پایگاه داده را پارتیشنبندی کنیم؟
معیارهای منطقی پارتیشنبندی را بر اساس دادهها و الگوهای کوئری تعیین کنید. شما میتوانید پارتیشنبندی را به صورتهای زیر زیر انجام دهید:
بر اساس بازه (Range): مثلاً کاربران را بر اساس سال عضویت دستهبندی کنیم (۲۰۰۰-۲۰۱۰، ۲۰۱۰-۲۰۲۰ و…).
بر اساس لیست (List): مثلاً کاربران را بر اساس شهر محل زندگیشان دستهبندی کنیم (تهران، اصفهان، شیراز).
بر اساس هش (Hash): یک فرمول ریاضی روی اطلاعات اعمال میکنیم تا کاربران به صورت تصادفی ولی یکنواخت در سرورهای مختلف پخش شده و هیچ سروری شلوغتر از بقیه نشود.
یک) سعی کنید توزیع یکنواخت و متعادلی از دادهها در سراسر پارتیشنها ایجاد کنید تا از ایجاد نقاط داغ (Hotspots) و استفاده ناهمگون از منابع جلوگیری شود.
دو) از تکنیکهای پارتیشن پرینگ (Partition Pruning) بهره ببرید. یعنی با مشخص کردن کلید پارتیشنبندی در کوئریها، به پایگاه داده میفهمانید پارتیشنهای غیرضروری را از فرآیند اجرای کوئری حذف کند که این امر سرعت را انفجاری میکند!
سه) ایندکسها را روی جداول پارتیشنبندیشده ایجاد کنید. ساختار ایندکسها باید با طرح پارتیشنبندی هماهنگ باشند. ایندکسهای همتراز با پارتیشن میتوانند بازیابی کارآمد دادهها را تسهیل کنند.
چهار) پایش و رسیدگی شما به پارتیشنها باید بهطور منظم و دائمی باشد. این رسیدگی شامل آرشیو یا پاکسازی پارتیشنهای قدیمی، بهینهسازی اندازه پارتیشنها یا ادغام پارتیشنها بر اساس الگوهای رشد داده است.
پنج) گزینههای پارتیشنبندی در سطوح مختلف را بررسی کنید، مانند پارتیشنبندی در سطح جدول (Table-level Partitioning) یا زیرپارتیشنبندی (Sub-partitioning) درون پارتیشنها. این کار دقت را بالابرده و سناریوهای دسترسی به داده را بهینه میکند.
در یک شرکت خردهفروشی چندملیتی دادههای مشتریان بهصورت نمایی رشد کرد و پایگاه دادههایی که دشبوردهای فروش را ساپورت میکرد در آن شرکت دچار اختلال جدی شدند. برای حل این مشکل، آنها استراتژیهای پارتیشنبندی پایگاه داده را پیادهسازی کردند. با پارتیشنبندی دادههای مشتریان بر اساس مناطق جغرافیایی، عملکرد بهتری در کوئریها بهدست آوردند.
پارتیشنبندی به آنها کمک کرد تا پاسخگویی سریعتر و تجربه مشتری بهبودیافتهتری داشته باشند. با گسترش شرکت به مناطق جغرافیایی جدید هم، آنها بهراحتی پایگاه داده خود را با افزودن پارتیشنهای جدید مخصوص آن مناطق، مقیاسپذیر کردند.
فرض کنید سایتی دارید که در ساعاتی از روز با ترافیک بسیار بالایی مواجه است. اگر از فضای ابری استفاده کنید، دیتابیس میتواند افزایش حجم کاری در زمانهای اوج را مدیریت کند. به بیان سادهتر، پایگاه داده قادر میشود در زمانهای شلوغی، منابع بیشتری (مانند رم و پردازنده) قرض بگیرد تا از پس ترافیک بالا بربیاید. همانطور که میدانید این مسئله، همان «مقیاسپذیری» است؛ یعنی دیتابیس اصطلاحا کِش میآید و جمع میشود.
با قابلیت مقیاسپذیری خودکار (Auto-scaling)، سیستم ابری بهصورت اتوماتیک میفهمد که بار کاری بالاست و خودبخود منابع را بر اساس تقاضا تنظیم میکند که این امر منجر به بهبود عملکرد SQL و بهرهوری هزینه میشود.
مزیت دیگر پلتفرمهای ابری این است که کارهای خستهکننده مثل آپدیت کردن، بکآپ گرفتن و نگهداری از دیتابیس را خودشان انجام میدهند و شما میتوانید وقت خود را فقط به بهینهسازی کوئریها و دیگر مسائل مرتبط با سرعت اختصاص دهید.
همچنین ارائهدهندگان سرویسهای ابری، ویژگیهای دسترسی بالا (High Availability) و بازیابی فاجعه (Disaster Recovery) را فراهم میکنند که زمان کار مداوم دیتابیس را تضمین کرده و زمان خرابی را به حداقل میرسانند. با این ویژگیها دیتابیس همیشه در دسترس است و اگر فاجعهای مثل قطعی برق پیش امد، سریع به کار برمیگردد.
در پلتفرمهای ابری، معماریهای محاسبات و یکپارچگی با پلتفرمهای تحلیلی بهگونهایست که پردازش موازی و تخلیه بارهای کاری پیچیده کاملا امکانپذیر است. ساده بگوییم آنها میتوانند کارها را خرد کرده و به چند ماشین واگذار کنند تا پردازشها بصورت موازی انجام شوند. همچنین میتوانند کارهای سنگین تحلیلی را در فضای جداگانهای انجام دهد تا فشار اضافی به دیتابیس اصلی تحمیل نشود.
بردن دیتابیس SQL روی فضای ابری مثل این است که یک تیم دستیار حرفهای استخدام کنید.
یک شرکت نرمافزاری با آگاهی از مقیاسپذیری و انعطافپذیری فوقالعادهای که زیرساخت ابری ارائه میدهد، تصمیم گرفت پایگاههای داده خود را به یک ارائهدهنده معتبر ابری منتقل کند.
آنها با بهرهگیری از سرویسها و فناوریهای بومی ابر، یک محیط پایگاه داده با معماری مناسب طراحی کردند که نیازهای خاص حجم کاری آنها را برآورده میساخت.
بهینهسازی دقیق کوئریها، ایندکسگذاریهای درست و مکانیزمهای کارآمد کشینگ در کنار استفاده از فضای ابری که پشتیبانگیری خودکار، همانندسازی (Replication)، دسترسی بالا و یکپارچگی دادهها را تضمین میکردند، باعث شد به تجربه کاربری بسیار روان و واکنشگرا و مقیاسپذیری عالی برسند.
Stored Procedureها (که "رویههای ذخیرهشده" هم نامیده میشوند) برنامههای کوچک و آمادهای هستند که میتوانند سرعت و عملکرد کوئریها و پایگاههای داده SQL را به چندین روش بهبود دهند.
1- رفت و آمد کمتر شبکه: منطق پیچیده و کوئریهایی که به طور مکرر اجرا میشوند درون Stored Procedureها محصور میشوند. این امر باعث میشود رفتوآمد شبکه کم شده و کوئریهای SQL سریعتر اجرا شوند. این یعنی چه؟ فرض کنید هربار یک کوئری سنگین و طولانی را از برنامه به دیتابیس میفرستید. حالا چنانچه آن کوئری را یکبار به صورت یک Stored Procedure در دیتابیس ذخیره کنید، دیگر لازم نیست هر بار آن کوئری مفصل را ارسال کنید. فقط کافیست بگویید: "آهای دیتابیس، اون Procedure رو اجرا کن!"
2-یکبار کامپایل کردن و همیشه اجرا کردن: ماهیت از پیش کامپایلشده (Precompiled) بودن Stored Procedureها، نیاز به تجزیه (Parsing) و بهینهسازی تکراری را از بین میبرد که نتیجه آن زمان اجرای سریعتر است. به زبان ساده: وقتی یک کوئری به دیتابیس ارسال میشود، دیتابیس باید با هربار ارسال کوئری، آن را تحلیل، ترجمه و اجرا کند اما Stored Procedureها ماهیتِ از پیش کامپایلشده دارند. یعنی دیتابیس یکبار تحلیل و ترجمه و اجرا را انجام میدهد و دفعات بعدی پردازش تکراری انجام نمیدهد.
3-ارتباط تنگاتنگ با منابع دیتابیس: Stored Procedureها مهمان دائمی دیتابیس هستند و از منابع سرور پایگاه داده به شکل بهینه استفاده میکنند، به ایندکسها (Indexes) بهدرستی دسترسی پیدا کرده و از مکانیزمهای حافظه و کش (Cache) بهره میجویند.
4-کد تمیز: Stored Procedureها قابلیت استفاده مجدد از کد و نگهداری آسانتر را فراهم میکنند. این یعنی کد تکراری (Duplicate Code) نوشته نمیشود و اگر زمانی خواستیم تغییری در کد ایجاد کنیم، کافیست فقط کد یک قسمت از برنامه را تغییر دهیم. این مسئله بهصورت غیرمستقیم روی کارایی تأثیر مثبت دارد.
نکته: برای استفاده از Stored Procedureها باید بر اساس کاری که میخواهید انجام دهید و نوع سیستم مدیریت پایگاه داده (DBMS) خود عمل کنید.
در اینجا 4 کتاب کاملا کاربری و تحسینشده در زمینه ارتقای عملکرد SQL را معرفی میکنیم:
نویسنده: Dmitri Korotkevitch
مناسب برای: متخصصان SQL Server
محتوای اصلی: عیبیابی پیشرفته و رفع گلوگاههای حافظه و قفلشدگی، آموزش استراتژیهای ایندکسگذاری و تنظیمات سرور برای حل مشکل کندی کوئریها.

نویسنده: Silvia Botros و Jeremy Tinley
مناسب برای: مدیران و توسعهدهندگان MySQL در مقیاس بزرگ
محتوای اصلی: طراحی پایگاه داده، بهینهسازی کش (Cache)، موضوعات پیشرفته مثل خرد کردن داده (Sharding) و پیادهسازی دسترسی بالا (High Availability).

نویسنده: Grant Fritchey
مناسب برای: کاربران نسخههای جدید SQL Server
محتوای اصلی: بررسی مفهوم «بوییدن پارامتر» و آمار (Statistics). استفاده از ابزارهای مدرن مثل Query Store برای تصحیح خودکار برنامه اجرایی (Execution Plan).

نویسنده: Daniel Nichter
مناسب برای: مهندسان سطح میانی
محتوای اصلی: تمرکز بر تحلیل زمان پاسخ کوئری و معیارها (Metrics). بررسی تأثیر تراکنشها، قفلگذاری ردیف (Row Locking) و فضای ابری بر سرعت MySQL.

تا بحال نام «کایزن» را شنیدهاید؟ فیلسوفی ژاپنی که معتقد بود: «بهجای اینکه یکشبه همهچیز را عوض کنید، سعی کنید هر روز فقط کمی بهتر شوید». کایزن ذهنیت ارزیابی و ارتقای مداوم را به جای یک تلاش یکباره برای بهتر شدن ترویج میکند.
بر اساس اصول کایزن، بهینهسازی یک کار یکباره نیست که امروز بنشینید و تمام کوئریهای خود را بهینه کنید و برای همیشه راحت شوید! کایزن، بر بهبودهای تدریجی تاکید میکند. به جای تلاش برای تغییرات بنیادین یا مخرب، تنظیمات کوچک و مداوم در کوئریهای SQL، ایندکسها، مدلهای داده و پیکربندیهای پایگاه داده را انجام دهید. چنین رویکردی ریسک پیامدهای ناخواسته را به حداقل میرساند و امکان آزمایش کنترلشده برای بررسی هر تغییر را فراهم میکند.
همچنین اصول کایزن بر اهمیت مشارکت دادن تمام ذینفعان در فرآیند بهینهسازی تأکید دارد. یعنی همکاری میان توسعهدهندگان، مدیران پایگاه داده و کاربران برای شناسایی و رفع مشکلات و بهبودهای تدریجی. چنین رویکردی فرهنگ بهبود مستمر را در یک سازمان یا تیم پرورش میدهد.
در بحث پایگاه داده، بهینهسازی مستمر به این دلیل ضروری است که پایگاههای داده بزرگتر میشوند، حجم دادههایشان زیاد میشود و نیازهای کاربران تغییر میکند. پس پایش، تحلیل و تنظیم دائمی، بهینهسازی کوئریها و سازگار کردن دیتابیسها با شرایط جدید برای توسعهدهندگان حیاتی است.
یادتان باشد بهینهسازی پایگاه داده SQL یک سفر است، نه یک مقصد. این نگاه به سازمانها این توانایی را میدهد که پیشرو بمانند، مقیاسپذیری باشند و همگام با دنیای پرتحول تکنولوژی و نیازهای کسبوکار، تجربه کاربری بینظیری را فراهم سازند.
در بهینهسازی پایگاه داده، مثل هر مسیر دیگر در زندگی خود، با پذیرش ذهنیت بهبود مستمر میتوانید به موفقیتهای بلندمدت دست یابید.
منبع مورد استفاده در این مقاله: Medium
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.