يتطلب مستوى: مبتدئ
الـ Index في قواعد البيانات: ليه استعلامك بطيء وإزاي تسرّعه بسطر واحد
لو استعلام بسيط زي البحث عن مستخدم بالإيميل بياخد أكثر من نص ثانية على جدول فيه مليون صف، المشكلة مش في السيرفر ولا في لغة البرمجة. المشكلة إن قاعدة البيانات بتقرا كل صف واحد واحد. الحل سطر SQL واحد اسمه Index، وبيوصّل نفس الاستعلام من 480 مللي ثانية لأقل من 1 مللي ثانية.
المشكلة باختصار
عندك جدول users فيه مليون صف. بتكتب استعلام يدوّر على إيميل معيّن. بدون index، القاعدة بتعمل حاجة اسمها Sequential Scan، يعني بتفتح كل صف من الأول للآخر وتقارن الإيميل لحد ما تلاقيه. لو الصف اللي انت عايزه في الآخر، دفعت تمن قراءة المليون صف كلهم. المشكلة دي بتفضل مخبّية وانت شغّال على بيانات قليلة، وبتظهر فجأة أول ما تكبر: نفس الاستعلام كان سريع على 1000 صف، وبقى بطيء على مليون.
يعني إيه Index؟ خلّيني أبسّطها الأول
تخيّل كتاب 900 صفحة وعايز تلاقي فيه كلمة معيّنة. لو مفيش فهرس في آخر الكتاب، هتقلّب صفحة صفحة لحد ما توصل، ممكن بعد وقت طويل. الفهرس بيقولك على طول: الكلمة دي موجودة في صفحة 12 و207 و688. فتفتح الصفحات دي دايركت من غير ما تقلّب الكتاب كله.
الـ Index في قاعدة البيانات هو نفس الفكرة بالظبط. هو نسخة مرتّبة من العمود اللي بتدوّر بيه، ومعاها مؤشّر لمكان الصف الأصلي على الديسك. علميًا، أغلب قواعد البيانات بتخزّن الـ index في هيكل اسمه B-tree، وهي شجرة متوازنة بتنزل من الجذر لفرع لورقة في 3 أو 4 قفزات بس. يعني بدل ما تقرا مليون صف، بتقرا حوالي 3 صفحات فهرس وتوصل للصف. ده الفرق بين مقارنة تتعمل مليون مرة ومقارنة تتعمل تلات مرات.
الحل: أضف أول index وقيس بنفسك
قبل ما تضيف أي حاجة، اتفرّج على اللي بيحصل فعلاً باستخدام EXPLAIN ANALYZE. الأمر ده بيوريك الخطة اللي القاعدة هتمشي عليها والزمن الحقيقي للاستعلام، من غير تخمين.
-- قبل: القاعدة بتعمل Seq Scan على مليون صف
EXPLAIN ANALYZE
SELECT * FROM users WHERE email = 'ali@example.com';
-- Seq Scan on users ... actual time=480.312 ms
-- أضف الفهرس (سطر واحد)
CREATE INDEX idx_users_email ON users (email);
-- بعد: نفس الاستعلام بقى Index Scan
EXPLAIN ANALYZE
SELECT * FROM users WHERE email = 'ali@example.com';
-- Index Scan using idx_users_email ... actual time=0.912 ms
الأرقام دي مقاسة على PostgreSQL 16 بجدول فيه مليون صف: من 480 مللي ثانية لـ 0.9 مللي ثانية، يعني أسرع حوالي 533 مرة. ركّز إن ده مش تقدير، ده رقم مكتوب في مخرجات EXPLAIN ANALYZE قدامك في السطر actual time.
الـ trade-off: مفيش حاجة ببلاش
الـ index مش سحر، وله تمن لازم تعرفه بدل ما تفاجأ بيه بعدين. أول تكلفة: الـ index بياخد مساحة على الديسك، غالبًا بين 10% و30% من حجم الجدول لكل index. تاني تكلفة وأهم: كل INSERT وUPDATE وDELETE على العمود المفهرس بيخلّي القاعدة تحدّث شجرة الـ B-tree كمان، مش الجدول بس.