أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

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

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

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

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

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

الرئيسيةالدوراتالعروضالمدونةالدخول
Optimizing بالعربي

Database Indexes للمبتدئ: من 8 ثواني لـ 5 مللي ثانية بسطر SQL

📅 ٨ مايو ٢٠٢٦⏱ 5 دقائق قراءة
Database Indexes للمبتدئ: من 8 ثواني لـ 5 مللي ثانية بسطر SQL

لو SELECT بسيط على جدول 1.2 مليون صف بياخد 8.4 ثانية وأنت متأكد إن السيرفر قوي، المشكلة مش في الـ RAM ولا الـ CPU. المشكلة إن قاعدة البيانات بتقلّب الجدول صف صف زي حد بيبص في 1.2 مليون ورقة بإيده. الـ Index بسطر SQL واحد بينزّل الزمن لـ 5 مللي ثانية، 1690 ضعف أسرع.

هذا المقال للمستوى: مبتدئ

Database Indexes: من 8 ثواني لـ 5 مللي ثانية بدون لمس السيرفر

رفوف مكتبة منظمة ترمز لفكرة فهرسة قواعد البيانات بترتيب يسهّل البحث السريع

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

عندك جدول users فيه 1.2 مليون مستخدم، وعملت أبسط استعلام ممكن:

SQL
SELECT * FROM users WHERE email = 'ahmed@example.com';

الاستعلام بياخد 8.4 ثانية على PostgreSQL 16 على لابتوب 16GB رام و SSD سريع. السبب مش حجم البيانات. السبب إن الـ DB بتعمل عملية اسمها Sequential Scan: بتقرا الجدول من أوله لآخره، صف صف، وبتقارن كل email حتى تلاقي اللي محتاجاه. لو السطر اللي بتدوّر عليه في آخر الجدول، لازم تقرا 1.2 مليون صف كاملة قبل ما تلاقيه.

المثال البسيط: قاموس المدرسة

تخيّل إنك بتدوّر على كلمة "احترام" في قاموس فيه 50,000 كلمة، لكن الكلمات مش مرتّبة أبجدياً، متناثرة بشكل عشوائي. هتقعد تقلّب صفحة صفحة لمدة ساعة ونصف. ده بدون Index.

دلوقتي تخيّل نفس القاموس بس الكلمات مرتّبة أبجدياً. بتفتح في النص، تشوف "م" يبقى لازم ترجع لورا. تفتح في الربع الأول، تشوف "ا"، تكمّل في "اح"، بعدين "احت"، وفي خلال 15 ثانية بتلاقي الكلمة. ده الـ Index.

الـ Index في قاعدة البيانات هو نفس الفكرة: هيكل بيانات منفصل عن الجدول، فيه قيم العمود اللي اخترته (مثلاً email) مرتّبة، وكل قيمة معاها مؤشّر (pointer) للسطر الأصلي في الجدول. الـ DB بتدوّر في الـ Index، تلاقي القيمة، تجيب المؤشّر، وتروح للسطر مباشرةً.

التعريف العلمي بدقة

الـ Index الافتراضي في PostgreSQL نوعه B-tree (شجرة متوازنة بـ branching factor عالي). الشجرة دي مكوّنة من عقد، كل عقدة فيها مجموعة قيم مرتّبة + مؤشّرات للعقد الفرعية. الفايدة الرياضية: للبحث عن قيمة، بتنزل من الجذر للأوراق في log₂(N) خطوة بدل N.

الفرق رياضي بحت، مش متعلق بنوع السيرفر:

  • Sequential Scan على 1.2M صف = 1,200,000 مقارنة في أسوأ حالة.
  • B-tree lookup على 1.2M صف = log₂(1,200,000) ≈ 21 مقارنة فقط.

الفرق النظري ~57,000 ضعف. الفرق العملي أقل (1,690x في الاختبار) بسبب overhead القراءة من القرص و cache hits، لكن المبدأ نفسه.

الكود الكامل قابل للنسخ

على PostgreSQL 16، خطوة بخطوة:

SQL
-- 1. قياس قبل الـ Index
EXPLAIN ANALYZE
SELECT * FROM users WHERE email = 'ahmed@example.com';

-- النتيجة:
-- Seq Scan on users (cost=0.00..32841.00 rows=1 width=84)
-- Execution Time: 8423.521 ms

-- 2. إنشاء الـ Index (سطر واحد)
CREATE INDEX idx_users_email ON users(email);

-- 3. قياس بعد الـ Index
EXPLAIN ANALYZE
SELECT * FROM users WHERE email = 'ahmed@example.com';

-- النتيجة:
-- Index Scan using idx_users_email on users
-- Execution Time: 4.987 ms

سطر CREATE INDEX واحد. النتيجة: 1690x أسرع. لازم تلاحظ كلمة Index Scan في خطة الاستعلام بدل Seq Scan؛ دي اللي بتأكدلك إن الـ Index اتستخدم فعلاً.

شاشة تحليلات تعرض زمن استجابة قاعدة بيانات قبل وبعد إضافة فهرس على عمود بحث

متى الـ Index بيشتغل ومتى لا

الـ Index مش سحر. بيشتغل في حالات محددة، وبيتجاهله الـ planner في حالات تانية:

  • WHERE email = 'x@y.com' ← بيشتغل (equality match مباشر).
  • WHERE email LIKE 'ahm%' ← بيشتغل (prefix match، بداية معروفة).
  • WHERE email LIKE '%example.com' ← ما بيشتغلش (suffix match، الـ B-tree مرتّبة من اليمين، مش من الشمال).
  • WHERE LOWER(email) = 'a@b.com' ← ما بيشتغلش إلا لو عملت expression index: CREATE INDEX ON users(LOWER(email)).

Trade-offs حقيقية لازم تعرفها

الـ Index مش مجاني. كل سطر CREATE INDEX ليه ثمن:

  1. مساحة قرص. Index على عمود email في جدول 1.2M صف بياخد ~80MB إضافية. على 10 indexes، الجدول ممكن يبقى ضعف حجمه.
  2. بطء INSERT و UPDATE و DELETE. كل عملية كتابة لازم تحدّث كل index على الجدول. على benchmarks فعلية، INSERT بقى أبطأ بـ 12-18% بعد إضافة 4 indexes.
  3. صيانة دورية. الـ Indexes بتتعرّض لـ bloat بعد كتير من الـ updates، فلازم REINDEX كل فترة، وده بيقفل الجدول لو مستخدمتش CONCURRENTLY.

الافتراض هنا: عندك جدول قراءته أكتر بكتير من كتابته (نسبة 80/20 أو أعلى). لو الجدول write-heavy، الحساب بيتغيّر.

متى لا تستخدم Index

  • الجدول صغير (أقل من 10,000 صف). Sequential Scan أسرع لأن الـ planner بيحسب إن قراءة الجدول كله من الذاكرة أرخص من البحث في الـ Index.
  • عمود بقيم متكررة بشدة. مثلاً عمود is_active فيه true على 95% من الصفوف. الـ Index هنا تقريباً عديم الفايدة، الـ DB هتفضل تعمل scan.
  • جداول write-heavy والقراءات نادرة. زي logs و audit_trail. تكلفة تحديث الـ Index في كل INSERT هتفوق فايدة الـ SELECT اللي بتحصل مرة في اليوم.
  • أعمدة بتتغير قيمتها كتير. Index على عمود بيتعدّل في كل request هيخلق bloat بسرعة.

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

افتح PostgreSQL عندك دلوقتي ونفّذ الاستعلام ده:

SQL
SELECT schemaname, tablename, indexname, idx_scan, pg_size_pretty(pg_relation_size(indexrelid)) AS size
FROM pg_stat_user_indexes
ORDER BY idx_scan ASC;

لو لقيت Indexes بـ idx_scan = 0، دي Indexes بتشغل مساحة وبتبطّأ الكتابة بدون أي فايدة. احذفها بـ DROP INDEX idx_name; ولاحظ الـ INSERT بيرجع أسرع. ابعتلي مخرجات الاستعلام لو في حاجة مش واضحة.

المصادر

  • PostgreSQL 16 Documentation - Indexes: postgresql.org/docs/16/indexes.html
  • Bayer & McCreight, "Organization and Maintenance of Large Ordered Indexes" (1972) - الورقة الأصلية للـ B-tree.
  • Markus Winand, "Use The Index, Luke!" - use-the-index-luke.com
  • PostgreSQL Wiki - Index Maintenance: wiki.postgresql.org/wiki/Index_Maintenance

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

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

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