الرئيسيةمن أناالدوراتالمدونةسوق الأوامرالمناهج والباقاتالشركاء

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • المناهج والباقات
  • سوق الأوامر
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالمناهجالمدونةالدخول
البرمجة بالعربي

الـ Index: ليه استعلامك بطيء وإزاي تسرّعه مئات المرات

متوسط24 يوليو 20264 دقائق قراءة
الـ Index: ليه استعلامك بطيء وإزاي تسرّعه مئات المرات

مستوى المقال: متوسط — يفترض إنك تعرف تكتب استعلام SELECT بسيط وتشتغل على قاعدة علائقية زي PostgreSQL أو MySQL.

لو استعلام بيدوّر على إيميل واحد في جدول مليون صف بياخد قرب الثانية والسيرفر فاضي، المشكلة مش في السيرفر. عمودك من غير Index، والحل سطر واحد.

الفهرس (Index): إزاي قاعدة البيانات بتلاقي صف واحد وسط مليون في أجزاء من الملي ثانية

رسم توضيحي لشجرة B-tree لفهرس قاعدة بيانات مع مسار بحث أخضر من الجذر 50 إلى الورقة 88 يوضح تحول تعقيد البحث من O(n) إلى O(log n)

المشكلة باختصار

من غير فهرس، قاعدة البيانات بتعمل مسح تسلسلي (Sequential Scan): بتقرأ كل صف في الجدول واحد واحد لحد ما تلاقي اللي انت عايزه. جدول مليون صف؟ مليون قراءة في أسوأ حالة. ده تعقيد O(n): كل ما البيانات تكبر، البطء يكبر معاها خطيًا.

الفكرة ببساطة: فهرس آخر الكتاب

تخيّل كتاب 900 صفحة وعايز موضوع "الـ Deadlock". من غير فهرس، هتقلّب صفحة صفحة من الأول. مع الفهرس في آخر الكتاب، بتفتح على حرف الدال، تلاقي "Deadlock ... ص 612"، وتفتح عليها دايركت. الفهرس مرتّب أبجديًا، فبتوصل بكام قفزة بدل مئات التقليبات.

فهرس قاعدة البيانات نفس الفكرة بالظبط: بنية بيانات منفصلة ومرتّبة، بتخزّن قيمة العمود مع إشارة لمكان الصف على القرص. القاعدة بتبحث في البنية المرتّبة دي، مش في الجدول كله.

إزاي بيشتغل علميًا: شجرة B-tree

الفهرس الافتراضي في PostgreSQL وMySQL هو B-tree، وهي شجرة بحث متوازنة. الشجرة مرتّبة، وكل قفزة من مستوى للمستوى اللي تحته بتقصّ مساحة البحث لجزء صغير. علشان كده البحث بياخد O(log n) مش O(n).

الفرق مش بسيط. مليون صف بالمسح التسلسلي يعني في المتوسط نص مليون قراءة. بشجرة B-tree عمقها 3 أو 4 مستويات، نفس البحث بياخد حوالي 4 قفزات. ده بالظبط اللي بيحوّل الثانية لأجزاء من الملي ثانية.

مثال تنفيذي: قِس الفرق بنفسك

على جدول users فيه مليون صف، شغّل ده في PostgreSQL:

SQL
-- قبل الفهرس
EXPLAIN ANALYZE
SELECT * FROM users WHERE email = 'sara@example.com';
-- Seq Scan on users  (rows=1000000)  actual time=842 ms

-- أضف الفهرس
CREATE INDEX users_email_idx ON users (email);

-- بعد الفهرس
EXPLAIN ANALYZE
SELECT * FROM users WHERE email = 'sara@example.com';
-- Index Scan using users_email_idx  actual time=1.9 ms

أهم أداة هنا هي EXPLAIN ANALYZE: بتوريك خطة التنفيذ الحقيقية اللي القاعدة مشيت عليها، Seq Scan ولا Index Scan، والزمن الفعلي بالملي ثانية. لو شفت Seq Scan على جدول كبير مع شرط WHERE، دي علامة مباشرة إن في فهرس ناقص.

الأرقام دي تقديرية وبتتغيّر حسب جهازك وإعداد القاعدة وحجم الصف، بس النسبة نفسها (تسريع بمئات المرات) واقعية ومتكرّرة في أي جدول كبير بتفلتر على عمود متنوّع.

الـ trade-offs: بتكسب إيه وبتخسر إيه

الفهرس مش مجاني. بتكسب قراءة أسرع بمراحل. بتخسر حاجتين. الأولى: الكتابة بتبقى أبطأ شوية، لأن كل INSERT أو UPDATE أو DELETE لازم يحدّث الجدول والفهرس مع بعض. التانية: مساحة تخزين إضافية، والفهرس ممكن ياخد من 10% لحوالي 50% من حجم الجدول حسب نوع العمود وعدد الفهارس.

الافتراض هنا إن العمود اللي بتفهرسه فيه تنوّع كافٍ في القيم (high cardinality) زي الإيميل أو رقم الطلب. ده اللي بيخلّي الفهرس يقصّ مساحة البحث فعلًا.

الفهرس المركّب: انتبه للترتيب

لو بتفلتر على أكتر من عمود مع بعض، الفهرس المركّب بيفيد: CREATE INDEX ON orders (user_id, created_at);. بس الترتيب مهم جدًا. الفهرس ده بيسرّع البحث بـ user_id وحده، أو بـ user_id مع created_at مع بعض، لكنه مبيسرّعش البحث بـ created_at وحده. القاعدة بتقرأ أعمدة الفهرس من الشمال لليمين، بالظبط زي دليل تليفون مرتّب بالاسم الأول ثم الأخير.

متى لا تستخدم الفهرس

مش كل عمود يستاهل فهرس. تجنّبه في الحالات دي: الجداول الصغيرة (بضع آلاف صف) لأن المسح التسلسلي أسرع أصلًا وأخف على الذاكرة. الأعمدة قليلة التنوّع زي "الجنس" أو "مفعّل/غير مفعّل"، لأن الفهرس هيرجّع نص الجدول تقريبًا فمش هيفرق. والجداول اللي الكتابة فيها أضخم بكتير من القراءة (زي جداول الـ logs)، لأن تكلفة تحديث الفهرس مع كل كتابة هتغلب أي مكسب في القراءة.

الخطوة التالية

افتح أبطأ استعلام عندك دلوقتي، وحط قبله EXPLAIN ANALYZE. لو لقيت Seq Scan على جدول كبير مع شرط WHERE على عمود متنوّع، اعمل فهرس على العمود ده وقارن الزمن قبل وبعد. لو الزمن نزل من مئات الملي ثانية لأجزاء منها، يبقى الفهرس شغّال صح.

المصادر

  • توثيق PostgreSQL الرسمي — Indexes: postgresql.org/docs/current/indexes.html
  • توثيق PostgreSQL — Index Types (B-tree): postgresql.org/docs/current/indexes-types.html
  • توثيق PostgreSQL — Using EXPLAIN: postgresql.org/docs/current/using-explain.html
  • Use The Index, Luke (Markus Winand): use-the-index-luke.com
  • توثيق MySQL — How MySQL Uses Indexes: dev.mysql.com/doc/refman/8.0/en/mysql-indexes.html

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة