يتطلب هذا المقال مستوى: متوسط. محتاج تكون كتبت استعلامات SQL بسيطة وتعرف يعني إيه جدول وصف وعمود. مش لازم تكون خبير في قواعد البيانات.
الـ Index في قواعد البيانات: ليه استعلام واحد بياخد ثانيتين وبفهرس واحد يبقى 3 مللي ثانية
لو استعلام بسيط على جدول كبير بياخد ثانيتين، المشكلة غالبًا مش في السيرفر ولا في الرام. المشكلة إن قاعدة البيانات بتقرأ كل صف في الجدول عشان تلاقي اللي انت عايزه. الحل سطر واحد: CREATE INDEX. هنا هتفهم ليه بيفرق، وإمتى ميفرقش.
المشكلة باختصار
عندك جدول orders فيه 10 مليون صف. بتعمل استعلام يجيب طلبات عميل معيّن بالـ customer_id. من غير index، قاعدة البيانات بتعمل حاجة اسمها Full Table Scan: بتفتح أول صف، تبص عليه، تعدّي، وهكذا لحد آخر صف. يعني 10 مليون مقارنة عشان تلاقي 12 صف بس. ده بياخد حوالي ثانيتين، وبيتكرر مع كل مستخدم بيفتح صفحته.
الفكرة ببساطة: فهرس الكتاب
تخيّل كتاب من 900 صفحة عايز تلاقي فيه كلمة "الأوتوميشن". عندك طريقتين.
الأولى: تفتح صفحة 1، تدوّر بعينك، متلاقيش، تقلب لـ 2، وهكذا لحد ما توصل. ممكن تقلب 900 صفحة. دي الـ Full Scan.
الثانية: تروح لآخر الكتاب، تلاقي الفهرس مرتّب أبجديًا، تنطّ للحرف "أ"، تلاقي "الأوتوميشن: صفحة 421". فتحت مكانين بس: الفهرس والصفحة. دي فكرة الـ Index.
الـ index مش نسخة تانية من الكتاب. هو جدول صغير مرتّب بيقولك "القيمة دي فين". قاعدة البيانات بتبنيه وبتحدّثه لوحدها.
وعلميًا: إيه هو الـ B-Tree
أشهر نوع index هو الـ B-Tree (شجرة متوازنة). مش قائمة مرتّبة عادية، ده شجرة من الطبقات. فوق فيه عقدة الجذر، تحتها عقد، وتحت دول الأوراق اللي فيها القيم الفعلية ومؤشرات على أماكن الصفوف.
لما تدوّر على customer_id = 84213، قاعدة البيانات بتبدأ من الجذر، تقارن، تنزل للفرع الصح، تقارن تاني، تنزل، لحد ما توصل للورقة. عدد القفزات دي بيساوي عمق الشجرة، وهو تقريبًا log عدد الصفوف. عشان الـ B-Tree عريضة (كل عقدة فيها مئات المفاتيح)، جدول بـ 10 مليون صف بيحتاج 3 أو 4 قفزات بس. يعني بدل 10 مليون مقارنة، بتعمل 4. ده الفرق بين O(n) و O(log n).
جرّبها بنفسك: قبل وبعد
في PostgreSQL استخدم EXPLAIN ANALYZE عشان تشوف الخطة والزمن الحقيقي:
-- الجدول فيه 10 مليون صف، من غير index على customer_id
EXPLAIN ANALYZE
SELECT * FROM orders WHERE customer_id = 84213;
-- Seq Scan on orders (rows=10000000)
-- Execution Time: 2100.44 ms
-- نبني index واحد
CREATE INDEX idx_orders_customer ON orders (customer_id);
-- نفس الاستعلام بالظبط
EXPLAIN ANALYZE
SELECT * FROM orders WHERE customer_id = 84213;
-- Index Scan using idx_orders_customer (rows=12)
-- Execution Time: 3.02 ms
من 2100 مللي ثانية لـ 3 مللي ثانية. تحسّن حوالي 700 مرة، وكل اللي عملته سطر واحد. لو عندك موقع بـ 50 ألف زائر في اليوم وكل واحد بيفتح صفحة طلباته، ده الفرق بين سيرفر بيلهث وسيرفر مرتاح.
الـ trade-offs
الـ index مش ببلاش. لازم تعرف الثمن قبل ما ترشّه على كل عمود.
- بيبطّئ الكتابة. كل
INSERTأوUPDATEأوDELETEلازم يحدّث الـ index كمان. عمود عليه 5 indexes معناه إن كل إدخال بيعمل 6 عمليات كتابة بدل واحدة. - بياخد مساحة. الـ index على عمود واحد ممكن ياخد حجم قريب من حجم العمود نفسه. index على 10 مليون صف ممكن يكون مئات الميجابايتات.
- الافتراض إن القراءة أكتر من الكتابة. الشرح ده مبني على جدول بيتقري منه كتير (زي جدول طلبات أو مستخدمين). لو الجدول بيتكتب فيه أكتر ما بيتقري، المعادلة بتتقلب.
متى لا تستخدم الـ Index
الـ index مش دايمًا الحل. متعملوش في الحالات دي:
- الجداول الصغيرة. جدول بـ 500 صف بيتقري كله من الرام في أقل من مللي ثانية. الـ Full Scan هنا أسرع من الـ index أصلاً، وقاعدة البيانات غالبًا هتتجاهل الـ index لوحدها.
- الأعمدة اللي قيمها متكررة جدًا. عمود
is_activeقيمته 0 أو 1 بس. الـ index عليه بيرجّع نص الجدول تقريبًا، فمفيش فايدة. - الجداول كثيفة الكتابة. زي جدول logs بيتكتب فيه آلاف الصفوف في الثانية وبيتقري نادرًا. هنا الـ index بيبقى عبء مش مكسب.
الخطوة التالية
افتح أبطأ استعلام عندك وحط قبله EXPLAIN ANALYZE. لو لقيت Seq Scan على جدول كبير في عمود بتفلتر بيه في WHERE، ده مرشّح قوي لـ index. ابنيه، أعد نفس الاستعلام، وقارن الـ Execution Time. لو نزل، تمام. لو مانزلش، ده معناه إن الاستعلام مش بيستخدم الـ index، وساعتها لازم تبص على سبب تاني.
مصادر
- توثيق PostgreSQL الرسمي عن الفهارس: postgresql.org/docs/current/indexes.html
- توثيق PostgreSQL عن EXPLAIN: postgresql.org/docs/current/using-explain.html
- كتاب "Use The Index, Luke" لـ Markus Winand عن الـ B-Tree و SQL performance: use-the-index-luke.com
- محاضرات CMU Intro to Database Systems عن هياكل الفهرسة: 15445.courses.cs.cmu.edu