قواعد البيانات والأداء: تحسين أداء استعلامات SQL وتجاوز خناق السرعة
المقدمة
تُعد قواعد البيانات العمود الفقري لأغلب التطبيقات. في أول أيام المشروع تعمل كل الاستعلامات بسرعة فائقة لأن حجم البيانات صغير. ثم يزداد عدد المستخدمين وتتراكم السجلات، فتبدأ الاستعلامات البطيئة (Bottlenecks) في إبطاء التطبيق بأكمله.
أول ما يخطر على بال كثير من المطورين هو ترقية مواصفات الخادم. لكن السبب الحقيقي في الغالب يكمن في طريقة كتابة الاستعلامات وغياب الفهارس (Indexes) المناسبة، وهذا ما سنعالجه هنا.
1. فهم خطة التنفيذ (Execution Plan)
قبل تحسين أي استعلام، عليك أن تعرف كيف تعالجه قاعدة البيانات فعلياً. توفر معظم محركات SQL، مثل SQL Server وPostgreSQL، أداة تُسمى Execution Plan تعرض لك الخطوات التي ينفذها المحرك. وفيها ستجد غالباً أحد النمطين التاليين:
Index Seek / Index Scan: بحث سريع وفعّال عبر الفهارس المتاحة.
Table Scan / Clustered Index Scan: قراءة الجدول كاملاً سجلاً بسجل، وهو السبب الأول لبطء الأداء في الجداول الكبيرة.
نصيحة: إذا رأيت Table Scan على جدول يحتوي ملايين السجلات، فهذه إشارة واضحة إلى أن استعلامك يحتاج مراجعة.
2. أفضل الممارسات لتحسين الأداء
أ. الاستخدام الصحيح للفهارس (Indexing)
الفهرس يشبه فهرس الكلمات في آخر كتاب ضخم: بدونه ستضطر لقراءة الكتاب كله لتجد كلمة واحدة.
الفهارس المركبة (Composite Indexes)
إذا كنت تستعلم باستمرار بأكثر من شرط في WHERE، فأنشئ فهرساً واحداً يغطي العمودين معاً:
SELECT * FROM Orders
WHERE Status = ‘Active’ AND CreatedDate > ‘2026-01-01’;
CREATE INDEX IX_Orders_Status_CreatedDate
ON Orders (Status, CreatedDate);
انتبه إلى ترتيب الأعمدة: القاعدة العامة أن تضع الأعمدة المستخدمة بشرط المساواة (=) أولاً، ثم الأعمدة المستخدمة بشروط النطاق (>, = ‘2026-01-01’ AND OrderDate c.Orders)
.ToList(); // استعلام واحد مجمّع
ملاحظة: إذا كانت العلاقات كبيرة أو متعددة، فقد يُنتج Include استعلاماً ضخماً. في هذه الحالة جرّب AsSplitQuery() في EF Core.
ج. اطلب فقط ما تحتاجه
تجنب SELECT * في بيئة الإنتاج. جلب أعمدة غير ضرورية له ثلاث مضار:
يستهلك ذاكرة الخادم.
يزيد الضغط على عرض النطاق الشبكي (Network Bandwidth).
يحرمك من الفهارس الشاملة (Covering Indexes)، وهي فهارس تحوي كل الأعمدة المطلوبة فيُجاب الاستعلام منها مباشرة دون الرجوع للجدول الأصلي.
— بدلاً من
SELECT * FROM Customers WHERE City = ‘Baghdad’;
— استخدم
SELECT Id, Name, Email FROM Customers WHERE City = ‘Baghdad’;
الخلاصة
قبل أن تشتري خادماً أقوى، اتبع هذه الخطوات:
افحص Execution Plan للاستعلامات البطيئة.
أضف الفهارس المناسبة وراعِ ترتيب الأعمدة.
اكتب شروطاً Sargable تسمح للمحرك باستخدام الفهرس.
تخلص من N+1 في طبقة ORM.
اجلب الأعمدة المطلوبة فقط.
غالباً ما يكون التحسين الصحيح لاستعلام واحد أكثر فعالية من أي ترقية عتادية.