PostgreSQL Index Types للمحترف: BRIN vs GIN vs GiST vs B-Tree — اختار صح أو اتفرج على الفاتورة
لو كاتب CREATE INDEX على كل عمود في WHERE ومستغرب ليه الـ INSERT بقى أبطأ 4 أضعاف والـ disk اتاكل 38GB زيادة، انت مش بتسرّع الـ DB. انت بتبني فهرس كل الأعمدة بـ B-Tree الافتراضي في حالات نصها كان لازم يبقى BRIN أو GIN. المقال ده هيوفّر عليك يومين debugging على staging وحوالي 220$ شهريًا في فاتورة storage على RDS.
المشكلة باختصار
PostgreSQL بيقدّم 6 أنواع index — B-Tree, Hash, BRIN, GIN, GiST, SP-GiST — وكل واحد مبني لـ access pattern مختلف تمامًا. الـ planner مش بيختارلك بدالك؛ هو بيستخدم اللي انت بنيته. لو بنيت الغلط، الـ planner هيعمل Seq Scan أو هيستخدم الـ index بشكل أسوأ من غيره. الـ trade-off هنا: كل index بيكلّفك write amplification + storage + autovacuum overhead. اختيار النوع الصح بيقفل المعادلة دي.
قبل ما ندخل في التفاصيل: المفهوم بمثال
تخيّل مكتبة فيها 240 مليون كتاب. لو عايز تلاقي كتاب بعنوان معيّن، هتحتاج فهرس أبجدي (ده B-Tree). لو الكتب مرتبة على الرف بترتيب تاريخ النشر وعايز كل كتب 2024، يكفي تعرف بداية ونهاية صف واحد (ده BRIN). لو كل كتاب فيه قائمة موضوعات وعايز كل الكتب اللي بتتكلم عن "Rust"، محتاج فهرس inverted من كل كلمة لقائمة كتب (ده GIN). لو عايز "أقرب 5 كتب جغرافيًا لمكتبتك"، محتاج فهرس مكاني (ده GiST).
الأربعة بيحلوا مشاكل مختلفة. استخدام B-Tree على عمود tsvector أو jsonb بيخلّيك تدفع تكلفة index ضخم بدون أي فايدة لأن الـ planner مش هيقدر يستخدمه أصلًا في @@ ولا @>.
B-Tree: الافتراضي اللي بتنسى تفكر فيه
B-Tree هو نوع index الافتراضي في PostgreSQL وبيغطّي 80% من الـ workloads: =, <, >, BETWEEN, IN, ORDER BY. المهم اللي بينسوه: B-Tree بيدعم Index-Only Scan لو كل الأعمدة المطلوبة موجودة في الـ index (عبر INCLUDE).
-- بدل ما تعمل CREATE INDEX على عمود واحد وتروح للجدول
-- استخدم INCLUDE علشان الـ planner يجاوب من الـ index لوحده
CREATE INDEX idx_orders_status_total
ON orders (status)
INCLUDE (total_amount, customer_id);
-- الـ query ده بقى Index-Only Scan
EXPLAIN ANALYZE
SELECT customer_id, total_amount
FROM orders
WHERE status = 'pending';
-- Planning Time: 0.18 ms
-- Execution Time: 12 ms (بدل 1840 ms على Heap Scan)