مستوى المقال: محترف — مبني على افتراض إنك بتشتغل على PostgreSQL 14 أو أحدث، عندك فهم مسبق بـ B-tree index و EXPLAIN ANALYZE، وجدول واحد على الأقل تجاوز 100 مليون صف.
PostgreSQL Partitioning: حوّل query من 8 ثواني لـ 118ms بـ 4 سطور SQL
لو الـ SELECT على آخر 7 أيام في جدول events بياخد 8 ثواني، planner مش بيختار index غلط — هو بيمشي على شجرة index ضخمة عشان يلاقي الصفوف. Declarative Partitioning بيخلي planner يقفز للقسم اللي فيه آخر 7 أيام فقط ويتجاهل الباقي. التحسين بياخد 4 سطور SQL، والثمن: schema migration كبيرة لمرة واحدة، وbalance بين عدد الأقسام وكفاءة الـ planner.
المشكلة باختصار
عندك جدول واحد events فيه 218 مليون صف، عمود created_at عليه B-tree index، والـ query بسيط:
SELECT user_id, event_type, COUNT(*)
FROM events
WHERE created_at >= NOW() - INTERVAL '7 days'
GROUP BY 1, 2;
زمن التنفيذ المقاس على PostgreSQL 16 على instance بـ 32GB رام و8 vCPU: 8.4 ثانية. بعد VACUUM ANALYZE: 8.1 ثانية. بعد إضافة composite index على (created_at, event_type): 7.6 ثانية. الـ I/O العالي مش بسبب البيانات نفسها، هو بسبب إن الـ index tree ضخم والـ buffer cache مش كافي يحتفظ بالـ hot pages.
مثال للمبتدئ: مكتبة المخازن
تخيل مخزن واحد فيه 218 ألف ملف ورقي، كلهم متخزنين بترتيب التاريخ. لو طلبت "ملفات الأسبوع الأخير"، الموظف لازم يقف قدام رف ضخم ويعدّ الملفات حتى لو فيه فهرس على الحائط. الفهرس بيقوله الملف رقم كام، لكن المشي للملف نفسه بياخد وقت لأن الرف طويل ومتشعب.
دلوقتي قسّم نفس المخزن لـ 12 خزانة، خزانة لكل شهر. لو طلبت ملفات الأسبوع الأخير، الموظف يفتح خزانة واحدة بس ويتجاهل الـ 11 الباقيين. ده بالظبط اللي partitioning بيعمله مع الـ DB — بيقسّم الجدول الواحد لـ "خزائن" منطقية، والـ planner زي الموظف الذكي اللي بيختار الخزانة المطلوبة فقط.
التعريف العلمي
Declarative Partitioning في PostgreSQL هو ميزة على مستوى schema بتسمح بتقسيم جدول واحد لعدة child tables تسمى partitions، بناءً على قيمة عمود واحد أو أكثر يسمى partition key. الـ query planner بيستخدم metadata الخاصة بكل partition (تسمى partition constraints) عشان يحدد أي partition محتمل يحتوي على صفوف مطابقة، ويتجاهل الباقي. هذا الإجراء يسمى partition pruning، ويتم في وقت التخطيط (plan time) أو وقت التنفيذ (execution time) بناءً على نوع الـ predicate في الـ WHERE clause.