MongoDB: أنواع الفهارس والميزات المتقدمة

آخر تحديث: 2026-08-26

ميزات الفهرسة المتقدمة — إتقان قواعد TTL والقواعد الجزئية وقواعد ESR لإنشاء نظام فهرسة على مستوى الإنتاج.

1. ما ستتعلمه


100%
graph TB
    A[Index Types] --> B[unique<br/>Unique Index]
    A --> C[sparse<br/>Sparse Index]
    A --> D[TTL<br/>Automatic Expiration]
    A --> E[partial<br/>Selected Indexes]
    A --> F[compound<br/>Composite Index]

    B --> B1[Ensure Uniqueness<br/>Repeated Throw Errors]
    C --> C1[Skip null<br/>Space-saving]
    D --> D1[Automatic Deletion<br/>Scheduled Cleanup]
    E --> E1[Indexed subset only<br/>Performance + Savings]

    style D fill:#d4edda
    style E fill:#d4edda

2. الفهرس الفريد (unique)

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

كيفية العمل: يقوم فهرس فريد بفرض قيود التفرد داخل شجرة B+. في كل مرة يتم فيها إدراج أو تحديث، يتحقق المحرك أولاً مما إذا كان هناك مفتاح بقيمة مماثلة موجودًا بالفعل في الفهرس؛ وإذا كان الأمر كذلك، فإنه يطلق استثناء E11000 duplicate key error. يتطلب الفهرس الفريد المركب أن تكون مجموعة الحقول فريدة (بينما يجوز تكرار الحقول الفردية).

حالات الاستخدام:

البعد الفهرس العادي الفهرس الفريد
قيود القيم يُسمح بالتكرار لا يُسمح بالتكرار
إدراج فحص تحديث شجرة B+ فقط تحديث شجرة B+ + فحص التفرد
أداء الكتابة اختبار الأداء أبطأ قليلاً (+5٪ من عبء التكافؤ)
رسالة الخطأ لا شيء E11000 خطأ في تكرار المفتاح
فريد جزئيًا غير مدعوم تم تنفيذه باستخدام partialFilterExpression
JAVASCRIPT
// === Create a unique index ===
db.users.createIndex({ email: 1 }, { unique: true });
// email Field values must be unique.

// === Composite Unique Index ===
db.products.createIndex({ sku: 1, variant: 1 }, { unique: true });
// (sku, variant) The combination must be unique.

// === Unique Index + Selected Fields ===
db.users.createIndex(
  { email: 1 },
  { unique: true, partialFilterExpression: { email: { $exists: true } } }
);
// Only for existing email Apply a unique constraint to the field's documentation

تحليل النقاط الرئيسية:

  1. يسمح الفهرس الفريد بوجود القيمة null، ولكن لا يمكن أن توجد سوى قيمة واحدة null في المجموعة بأكملها (تُعتبر القيمة «null» نفس القيمة).
  2. يتيح استخدام partialFilterExpression تطبيق قيد التفرد على بعض المستندات فقط، مما يحل مشكلة التفرد الفارغ.
  3. قبل إنشاء فهرس فريد، يجب ألا تحتوي المجموعة على أي قيم مكررة؛ وإلا فسيفشل الإنشاء.


3. الفهارس المتفرقة

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

كيفية العمل: عند إنشاء فهرس متفرق، يتحقق المحرك من وجود الحقل المفهرس ومن أنه ليس فارغًا بعد إدراج المستند؛ ولا يقوم بإدراج مدخل فهرسي في شجرة B+ إلا في حالة استيفاء هذين الشرطين. وأثناء إجراء الاستعلام، في حالة استخدام فهرس متفرق، لن تتضمن النتائج المستندات التي تحتوي على حقول مفقودة (لأنها غير موجودة في الفهرس).

حالات الاستخدام:

100%
graph LR
    subgraph "Collection of Documents"
        D1["{sku:'A', discount:10}"]
        D2["{sku:'B'}"]
        D3["{sku:'C', discount:null}"]
        D4["{sku:'D', discount:20}"]
    end

    subgraph "Regular Index"
        I1["A→D1, B→D2, C→D3, D→D4"]
    end

    subgraph "Sparse Index"
        I2["10→D1, 20→D4<br/>(only 2 entries)"]
    end

    style I2 fill:#d4edda
السيناريو التوصية السبب
غالبًا ما تكون الحقول مفقودة (مثل الحقول الاختيارية) فهرس متفرق يوفر المساحة من خلال فهرسة المستندات التي تحتوي على قيم فقط
يجب أن تحتوي الحقول على قيم الفهرس العادي لا داعي للتخطي؛ الفهرس المتفرق لا يقدم أي ميزة
فريد + يسمح بوجود عدة قيم فارغة فهرس فريد متفرق لا يتم تضمين القيم الفارغة في عمليات التحقق من التفرد
يجب أن تُرجع الاستعلامات المستندات ذات القيم الفارغة الفهرس العادي الفهارس المتفرقة تتجاهل المستندات ذات القيم الفارغة
JAVASCRIPT
// === Sparse Index:Skip null Field ===
db.products.createIndex({ discount: 1 }, { sparse: true });
// Index only discount Field Documentation

// === Sparse Index vs Regular Index ===
// Regular Index:All documents are indexed(Including null)
// Sparse Index:Only non- null Indexing Documents

تحليل النقاط الرئيسية:

  1. لا تشمل الفهارس المتفرقة الوثائق التي تفتقد إلى حقول معينة؛ ولن تعرض find({discount: null}) الوثائق التي تفتقد إلى ذلك الحقل.
  2. تركيبة «متفرقة + فريدة»: تسمح بعدم وجود هذا الحقل في مستندات متعددة مع ضمان أن تكون القيم الموجودة فريدة
  3. تُعد الفهارس الجزئية مجموعة شاملة للفهارس المتفرقة (وهي أكثر مرونة)؛ ويُنصح باستخدام الفهارس الجزئية أولاً.


4. فهارس TTL (انتهاء الصلاحية التلقائي)

شرح المفهوم: مؤشر TTL (Time-To-Live) هو آلية الانتهاء والحذف التلقائية في MongoDB، والتي تقوم تلقائيًا بحذف المستندات التي تجاوزت فترة زمنية محددة استنادًا إلى حقل التاريخ. ولا يتطلب ذلك أي عملية تنظيف يدوية أو مهام مجدولة؛ حيث يتولى محرك قاعدة البيانات هذه المهمة تلقائيًا في الخلفية — مما يجعله أداة قوية لإدارة الجلسات وتنظيف السجلات.

كيفية العمل: يضيف فهرس TTL خيطًا للتنظيف في الخلفية إلى شجرة B+. يعمل هذا الخيط كل 60 ثانية، ويقوم بمسح حقول التاريخ في الفهرس، وحساب currentTime - fieldValue > expireAfterSeconds، وحذف جميع المستندات منتهية الصلاحية. تتسبب عملية الحذف بحد ذاتها في عبء إضافي على الكتابة، وقد يؤدي وجود عدد كبير من المستندات منتهية الصلاحية إلى ارتفاع مفاجئ في ضغط الكتابة.

100%
sequenceDiagram
    participant App as Applications
    participant TTL as TTLBackground Threads
    participant IX as TTLIndexB+Tree
    participant DOC as Collection of Documents

    App->>DOC: Insert {token:'abc', createdAt: T1}
    DOC->>IX: Index Entries createdAt=T1

    Note over TTL: Every 60 seconds

    loop Every 60 seconds
        TTL->>IX: Scan createdAt values
        IX-->>TTL: Back to All Entries
        TTL->>TTL: Calculate the current time - createdAt
        alt Expired ( > expireAfterSeconds )
            TTL->>DOC: Delete Expired Documents
            DOC->>IX: Delete the corresponding index entry
        else Not expired
            Note over TTL: Skip
        end
    end

حالات الاستخدام:

السيناريو مدة الصلاحية بالثواني القيمة النموذجية
جلسة المستخدم 30 دقيقة 1,800
رمز التحقق 10 دقائق 600
بيانات السجل تُحتفظ بها لمدة 90 يومًا 7,776,000
رمز مؤقت ساعة واحدة 3,600
سجل تحديد معدل يوم واحد 86,400

⚠️ حد TTL:

القيد الوصف الحل
لا يمكن أن يكون فهرسًا مركبًا لا يمكن أن يستند TTL إلا إلى حقل تاريخ واحد بالنسبة للشروط المركبة، استخدم فهرسًا جزئيًا + عملية تنظيف على مستوى التطبيق
يجب أن يكون الحقل من نوع «تاريخ» لا يُسمح باستخدام أنواع «رقم» أو «سلسلة» استخدم new Date() لتخزين الوقت
تأخير الحذف يقوم الخيط الخلفي بالمسح مرة كل 60 ثانية الحد الأقصى للتأخير هو 60 ثانية؛ والوقت ليس دقيقًا
لا يمكن ضمان دقة عملية الحذف قد يتم حذف أعداد كبيرة من المستندات منتهية الصلاحية على دفعات ضمان القدرة على تحمل الأعطال على مستوى طبقة الأعمال
JAVASCRIPT
// === Create TTL Index(30 Automatically Deleted by the Queen)===
db.sessions.createIndex(
  { createdAt: 1 },
  { expireAfterSeconds: 30 * 24 * 60 * 60 }
);

// === Edit TTL ===
db.runCommand({
  collMod: 'sessions',
  index: { keyPattern: { createdAt: 1 }, expireAfterSeconds: 7 * 24 * 60 * 60 }
});

// === Cancel TTL(Set as false)===
db.runCommand({
  collMod: 'sessions',
  index: { keyPattern: { createdAt: 1 }, expireAfterSeconds: -1 }
});

السيناريوهات النموذجية:



5. الفهارس الجزئية

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

كيفية العمل: عند إنشاء فهرس جزئي، يقوم المحرك بإدراج المستندات التي تستوفي partialFilterExpression فقط في شجرة B+Tree. وأثناء تنفيذ الاستعلام، لن يختار المُحسِّن هذا الفهرس إلا إذا كانت شروط الاستعلام «تغطي» تعبير التصفية الجزئي (partialFilterExpression) (أي أن تكون شروط الاستعلام مجموعة فرعية من شروط التصفية أو مكافئة لها)؛ وإلا، فلن يتم استخدامه.

حالات الاستخدام:

100%
graph TB
    subgraph "Gathering(10000Document)"
        A[All Documents<br/>10000 items]
    end

    subgraph "Regular Index"
        B[Index Entries<br/>10000 items<br/>~10MB]
    end

    subgraph "PartialIndex<br/>isActive=true, stock>0"
        C[Index Entries<br/>3000 items<br/>~3MB]
    end

    A --> B
    A --> C

    style C fill:#d4edda
معايير المقارنة الفهرس العادي الفهرس الجزئي الفهرس المتفرق
شروط التصفية لا شيء يدعم $eq/$gt/$gte/$lt/$lte/$exists/$type/$and وجود الحقل فقط
توفير المساحة 0% 30–70% يعتمد على نسبة البيانات المفقودة
المرونة المعيار ⭐⭐⭐ الأكثر مرونة ⭐ الأكثر تقييدًا
قيود الاستعلام لا شيء يجب أن تتطابق شروط الاستعلام مع شروط التصفية يجب أن تتضمن الاستعلامات شروطًا متعلقة بالحقول
موصى به الافتراضي ✅ مفضل للاستخدام في بيئة الإنتاج لسيناريوهات بسيطة فقط
التعبير الدعم
$eq / $gt / $gte / $lt / $lte
$exists: true
$type
$and
$or / $in / $nin
JAVASCRIPT
// === Selected Indexes:Index only documents that meet the criteria ===
db.products.createIndex(
  { category: 1, price: 1 },
  {
    partialFilterExpression: {
      isActive: true,
      stock: { $gt: 0 }
    }
  }
);
// Index only products currently for sale(isActive=true, stock>0)

// === Space-Saving Indexes ===
// Regular Index:1 Index all documents
// Partial Index: Only index 3000 products currently for sale (Saves 70% space)

▶ المثال 1: الفهرسة الجزئية في الممارسة العملية

JAVASCRIPT
// ShopHub:Index only products that are for sale and in stock,Savings 70% Index Space
db.products.insertMany([
  { sku: 'A001', category: 'Electronics', price: 599, isActive: true, stock: 50 },
  { sku: 'A002', category: 'Electronics', price: 299, isActive: false, stock: 0 },
  { sku: 'A003', category: 'Books', price: 29, isActive: true, stock: 100 },
  { sku: 'A004', category: 'Books', price: 49, isActive: true, stock: 0 }
]);

// Partial Index only isActive=true AND stock>0 the document(A001, A003)
db.products.createIndex(
  { category: 1, price: 1 },
  { partialFilterExpression: { isActive: true, stock: { $gt: 0 } } }
);

// The query must include filter Conditions for a hit
db.products.find({
  category: 'Electronics',
  isActive: true,
  stock: { $gt: 0 },
  price: { $gte: 100 }
}).explain();
// winningPlan.stage: IXSCAN ✅

// Missing filter Conditions → Missed
db.products.find({ category: 'Electronics', price: { $gte: 100 } }).explain();
// winningPlan.stage: COLLSCAN(Do not use partial Index)

الإخراج:

TEXT 📖 للعرض فقط
الاستعلام مع شروط التصفية: winningPlan.stage: IXSCAN ✅
الاستعلام بدون شروط التصفية: winningPlan.stage: COLLSCAN (لا يستخدم الفهرس الجزئي)
تم توفير 70% من مساحة الفهرس بفهرسة المنتجات النشطة فقط.


6. قواعد ESR

Equality → Sort → Range: القاعدة الذهبية لترتيب الحقول في الفهرس المركب.

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

كيف يعمل:

100%
graph TB
    subgraph "ESR Index {status, createdAt, price}"
        A["Equality: status='paid'<br/>→ Locate all paid Document"] --> B["Sort: createdAt: -1<br/>→ The index is sorted,Memory-Free Sorting"]
        B --> C["Range: price >= 100<br/>→ Range Scan,Interrupt Subsequent Fields"]
    end

    subgraph "Counterexample:RSE Index {price, status, createdAt}"
        D["Range: price >= 100<br/>→ Scan a large number of index entries"] --> E["Sort: status<br/>→ Memory-based sorting required"]
        E --> F["Equality: createdAt<br/>→ The index can no longer be used"]
    end

    style A fill:#d4edda
    style B fill:#cce5ff
    style C fill:#fff3cd
    style D fill:#f8d7da
    style E fill:#f8d7da
    style F fill:#f8d7da

جدول مقارنة قواعد ESR:

الترتيب النوع مثال الوظيفة
الأول المساواة category: 'Electronics' تضييق نطاق الخيارات بسرعة
الثاني المساواة isActive: true تضييق نطاق الموضوع أكثر
3 الفرز sort: { createdAt: -1 } يستخدم الطبيعة المرتبة للفهرس لتجنب عملية الفرز
الرابع النطاق price: { $gte: 100 } مسح النطاق، وضعه في النهاية

عواقب مخالفة قواعد ESR:

الترتيب غير الصحيح العواقب التفسير
النطاق قبل تحقيق المساواة نطاق المسح واسع جدًّا totalKeysExamined أكبر بكثير من nReturned
الفرز حسب النطاق لا يمكن استخدام فهرس للفرز تتم مرحلة SORT (الفرز في الذاكرة)
تخطي مرحلة المساواة والبدء في الفرز مباشرةً الفرز دون نقطة بداية محددة المسح الكامل للفهرس + الفرز
JAVASCRIPT
// === Search:Equivalence Filtering + Sort + Scope ===
db.products.find({
  category: 'Electronics',          // Equality
  isActive: true                    // Equality
}).sort({ createdAt: -1 })          // Sort
  .limit(20);

// Price Range
db.products.find({
  category: 'Electronics',
  createdAt: { $gte: new Date('2026-01-01') }  // Range
}).sort({ rating: -1 });

// === Best Index ===
db.products.createIndex({
  category: 1,         // E - Equivalent
  isActive: 1,         // E - Equivalent
  createdAt: -1,       // S - Sort(Index Direction Matching)
  rating: -1           // R - Scope(Save it for last)
});
الترتيب النوع مثال
الأول المساواة category: 'Electronics'
الثاني المساواة isActive: true
الثالث الفرز sort: { createdAt: -1 }
الرابع المدى createdAt: { $gte: ... }

▶ المثال 2: مقارنة عملية لقواعد ESR

JAVASCRIPT
// TechCorp Order System:Comparison ESR Correct vs Execution Plan with Incorrect Ordering
db.orders.insertMany([
  { userId: 'user_001', status: 'paid', createdAt: new Date('2026-07-01'), total: 100 },
  { userId: 'user_002', status: 'pending', createdAt: new Date('2026-07-02'), total: 200 },
  { userId: 'user_001', status: 'paid', createdAt: new Date('2026-07-03'), total: 50 }
]);

// ❌ Index Errors: Range before Sort
db.orders.createIndex({ userId: 1, total: 1, status: 1, createdAt: -1 }, { name: 'idx_wrong' });
db.orders.find({ userId: 'user_001', status: 'paid' })
  .sort({ createdAt: -1 }).explain('executionStats');
// appear SORT stage(Memory Sorting),totalKeysExamined much greater than nReturned

// ✅ Correct Indexing:ESR Order
db.orders.dropIndex('idx_wrong');
db.orders.createIndex({ userId: 1, status: 1, createdAt: -1, total: 1 }, { name: 'idx_esr' });
db.orders.find({ userId: 'user_001', status: 'paid' })
  .sort({ createdAt: -1 }).explain('executionStats');
// No SORT stage, totalKeysExamined ≈ nReturned

الإخراج:

TEXT 📖 للعرض فقط
الفهرس الخاطئ (RSE): تظهر مرحلة SORT (فرز في الذاكرة)، totalKeysExamined أكبر بكثير من nReturned
الفهرس الصحيح (ESR): لا توجد مرحلة SORT، totalKeysExamined ≈ nReturned
تحسين الأداء: إزالة الفرز في الذاكرة وتقليل عدد مفاتيح الفهرس المفحوصة.


7. أفضل الممارسات لتصميم الفهارس

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

مبادئ التصميم:

  1. التصميم القائم على الاستعلامات — قم أولاً بتحليل explain() وسجل الاستعلامات البطيئة، ثم قم بإنشاء الفهارس
  2. أولوية ESR — يتبع ترتيب الحقول في الفهرس المركب الترتيب التالي: المساواة → الفرز → النطاق
  3. إعطاء الأولوية للانتقائية العالية — الحقول التي تحتوي على العديد من القيم الفريدة (مثل userId) أكثر ملاءمة للفهرسة من الحقول ذات الانتقائية المنخفضة (مثل isActive)
  4. تغطية الفهرس — ضع في اعتبارك استخدام تغطية الفهرس للاستعلامات عالية التكرار لتجنب عمليات البحث في الجداول
  5. التنظيف الدوري — استخدم $indexStats للبحث عن الفهارس غير المستخدمة وحذفها
100%
graph TB
    A[Analyzing Query Patterns<br/>Slow Query Log] --> B[Identifying High-Frequency Queries]
    B --> C{Query Type?}
    C -->|Equal Value Query| D[Single field/Unique Index]
    C -->|Multiple Condition Combinations| E[Composite Index ESR]
    C -->|Sort+Filter| F[ESR Composite Index]
    C -->|Show only a few fields| G[Index Coverage]
    B --> H[Evaluating Options]
    H -->|High selectivity| I[✅ Create an index]
    H -->|Low selectivity| J[❌ Do not build / use partial]
    I --> K[Create+Verification<br/>explain]
    K --> L[Monitoring Utilization<br/>$indexStats]
    L --> M{Low utilization rate?}
    M -->|Yes| N[Delete Index]
    M -->|No| O[Retain]

    style D fill:#d4edda
    style E fill:#d4edda
    style F fill:#d4edda
    style G fill:#d4edda

(1) النهج الموصى به

JAVASCRIPT
// ✅ Recommendations 1:Single-Field Indexes Cover High-Frequency Queries
db.products.createIndex({ sku: 1 });

// ✅ Recommendations 2:Composite indexes follow ESR Principles
db.orders.createIndex({ userId: 1, status: 1, createdAt: -1 });

// ✅ Recommendations 3:TTL Automatic Cleanup
db.logs.createIndex({ createdAt: 1 }, { expireAfterSeconds: 30 * 86400 });

// ✅ Recommendations 4:Space-Saving Indexes
db.products.createIndex(
  { category: 1 },
  { partialFilterExpression: { isActive: true } }
);

// ✅ Recommendations 5:Unique indexes ensure data integrity
db.users.createIndex({ email: 1 }, { unique: true });

(2) الأنماط السلبية

الأنماط الخاطئة الشائعة وعواقبها:

النمط الخاطئ العواقب أفضل الممارسات
حقول الفهرسة ذات الانتقائية المنخفضة كفاءة الفهرس ضعيفة؛ وقد يقرر مُحسِّن الأداء عدم استخدامه استخدم فهرسًا جزئيًا أو فهرسًا مركبًا
عدد الفهارس كبير جدًّا (>10 لكل مجموعة) انخفاض حاد في أداء الكتابة الاحتفاظ فقط بالفهارس الخاصة بالاستعلامات المتكررة
ترتيب غير صحيح لحقول الفهرس المركب فشل جزئي في الفهرس الامتثال لقواعد ESR
الفهارس غير الضرورية المساحة المهدرة + عبء الكتابة قم بالتنظيف بانتظام باستخدام $indexStats
تم الوصول إلى فهرس غير مُتحقق منه ربما لم يتم استخدام الفهرس على الإطلاق يجب تشغيل EXPLAIN للتحقق بعد الإنشاء
JAVASCRIPT
// ❌ Anti-pattern 1:Indexing Fields with Low Selectivity
db.users.createIndex({ isActive: 1 });
// isActive Only true/false Two values,Low index efficiency

// ❌ Anti-pattern 2:Excessive Indexing
// A set containing more than 20 Index,Write performance has dropped significantly

// ❌ Anti-pattern 3:Incorrect Order of Fields in a Composite Index
db.products.createIndex({ price: 1, category: 1 });
// Wrong: price should be placed after category

// ❌ Anti-pattern 4:Unnecessary Indexes
db.users.createIndex({ lastLoginAt: 1 });
// If you rarely press lastLoginAt Search,Index Waste


8. مراقبة أداء المؤشر

شرح المفهوم: تُعد مراقبة الفهارس جزءًا أساسيًا من العمليات في بيئة الإنتاج. ومن خلال تحليل سجلات الاستعلامات البطيئة وإحصائيات استخدام الفهارس، يمكنك تحديد الفهارس غير المستخدمة (التي تهدر المساحة)، والفهارس غير الفعالة (التي تحتاج إلى تحسين)، والفهارس المفقودة (التي يجب إنشاؤها).

كيفية العمل: يقوم أداة التحليل المدمجة في MongoDB بتسجيل الاستعلامات البطيئة، بينما يتتبع مسار التجميع $indexStats عدد مرات استخدام كل فهرس والوقت المستغرق في كل استعلام. وتوفر هذه العناصر مجتمعةً نظرة شاملة على حالة الفهرس.

مقاييس الرصد:

المقياس الأمر القيمة السليمة قيمة التحذير
استخدام الفهرس $indexStats العمليات > 1,000/يوم العمليات = 0 (غير مستخدم)
عدد الاستعلامات البطيئة system.profile 0 > 10 في الساعة
حجم الفهرس totalIndexSize() أقل من 50% من البيانات أكثر من 100% من البيانات
تجزئة الفهرس collStats متوسط معدل الملء > 80% < 60%
JAVASCRIPT
// === Slow Query Analysis ===
db.setProfilingLevel(2, { slowms: 100 });
// Records exceeding 100ms Queries

// === View Slow Queries ===
db.system.profile.find({ millis: { $gt: 100 } })
  .sort({ ts: -1 })
  .limit(10);

// === View Index Usage Statistics ===
db.products.aggregate([
  { $indexStats: {} }
]);
// Find unused index

// === Delete Unused Indexes ===
db.products.dropIndex('unused_index_name');

تحليل النقاط الرئيسية:

  1. مستوى التحليل: 0 = معطل، 1 = الاستعلامات البطيئة فقط، 2 = جميع السجلات (يؤثر المستوى 2 على الأداء وهو مخصص لأغراض تصحيح الأخطاء فقط)
  2. إذا كانت قيمة accesses.ops الخاصة بـ $indexStats تساوي 0، فهذا يعني أنها لم تُستخدم مطلقًا منذ بدء تشغيل MongoDB.
  3. بيئة الإنتاج الموصى بها: المستوى 1 + slowms: 100، لتحقيق التوازن بين دقة المراقبة والأداء

▶ مثال: مؤشر TTL + المؤشر الجزئي + ESR في الممارسة العملية

JAVASCRIPT
// Scene 1:TTL Automatically Clear Session Indexes(30 Expires in minutes)
db.sessions.insertMany([
  { userId: 'user_001', token: 'abc', createdAt: new Date() },
  { userId: 'user_002', token: 'xyz', createdAt: new Date(Date.now() - 31 * 60 * 1000) }  // Expired
]);

db.sessions.createIndex(
  { createdAt: 1 },
  { expireAfterSeconds: 30 * 60 }  // 30 minutes
);

// Waiting 60 seconds later,Expired documents are automatically deleted
// db.sessions.find() → Only user_001 The conversation

// Scene 2:Selected Indexes - Index only products currently for sale(Savings 70% Space)
db.products.createIndex(
  { category: 1, price: 1 },
  {
    partialFilterExpression: {
      isActive: true,
      stock: { $gt: 0 }
    }
  }
);

// Some indexes are only used when the query contains filter Use when conditions apply
db.products.find({
  category: 'Electronics',
  isActive: true,    // Must match partialFilterExpression
  stock: { $gt: 0 }, // Must match partialFilterExpression
  price: { $gte: 100, $lte: 500 }
}).explain();
// winningPlan.inputStage.stage: IXSCAN(Partial indexing was used)

// Scene 3:ESR Rules in Practice - Order Inquiry
db.orders.insertMany([
  { userId: 'user_001', status: 'paid', createdAt: new Date('2026-07-01'), total: 100 },
  { userId: 'user_001', status: 'paid', createdAt: new Date('2026-07-02'), total: 200 },
  { userId: 'user_002', status: 'pending', createdAt: new Date('2026-07-03'), total: 50 }
]);

// ESR Best Index:Equality → Sort → Range

الإخراج:

TEXT 📖 للعرض فقط
TTL: تم حذف الجلسات المنتهية صلاحيتها تلقائيًا.
Partial Index: تم توفير 70% من المساحة بفهرسة المنتجات النشطة فقط.
ESR: تم تحسين أداء استعلام الطلبات بإزالة مرحلة الفرز في الذاكرة.

db.orders.createIndex({ userId: 1, // E - Equivalence Filtering status: 1, // E - Equivalence Filtering createdAt: -1, // S - Sort(Directional Matching) total: 1 // R - Range Query(Save it for last) });

// Efficient Queries:Orders Paid by the User,In reverse chronological order,Price Range db.orders.find({ userId: 'user_001', // E status: 'paid', // E total: { $gte: 50, $lte: 300 } // R }).sort({ createdAt: -1 }).limit(20) // S .explain('executionStats');

// Output:Use composite indexes exclusively,No additional sorting required // totalKeysExamined: 2, totalDocsExamined: 2, nReturned: 2


> النتيجة: يقوم TTL تلقائيًا بمسح الجلسات المنتهية الصلاحية؛ وتساعد بعض الفهارس في توفير المساحة؛ كما تعمل الفهارس المركبة في ESR على تحسين أداء الاستعلامات.

---
## ❓ أسئلة شائعة

> **س: ما هي المدة التي يستغرقها حذف المستندات من فهرس TTL؟** **ج: يقوم الخيط الخلفي بمسح الفهرس مرة كل 60 ثانية. ويبلغ الحد الأقصى للتأخير 60 ثانية مضافًا إليها مدة صلاحية المستند.**

> **س: الفرق بين الفهارس الجزئية والفهارس المتفرقة؟** **ج: تدعم الفهارس الجزئية شروطًا أكثر تعقيدًا (`$gt/$gte/$and`)، بينما تعتمد الفهارس المتفرقة حصريًّا على وجود الحقل من عدمه. يُنصح باستخدام الفهارس الجزئية (لأنها أكثر مرونة).**

> **س: ما هو اتجاه حقل الفرز في قواعد ESR؟** **ج: يجب أن يتطابق اتجاه الفرز مع اتجاه الفهرس. يستخدم `sort({ createdAt: -1 })` فهرس `createdAt: -1`.**

> **س: متى يتم حذف الفهارس؟** **ج: (1) يدويًّا `dropIndex`؛ (2) حذف المجموعة؛ (3) انتهاء صلاحية الفهرس تلقائيًّا (حقول التاريخ فقط).**

---

## 📖 ملخص

- الفهرس الفريد: يضمن أن تكون قيم الحقول فريدة
- فهرس متفرق: يتخطى الحقول ذات القيمة «null»
- مؤشر TTL: انتهاء الصلاحية والحذف التلقائيان
- الفهرسة الجزئية: لا يتم فهرسة سوى الوثائق التي تستوفي المعايير
- قاعدة ESR: المساواة → الفرز → النطاق
- تصميم الفهارس: قم بإنشاء فهارس للحقول التي تتكرر الاستعلامات عليها بشكل كبير؛ وتوخى الحذر عند إنشاء فهارس للحقول ذات الانتقائية المنخفضة؛ وتأكد من أن الفهارس المركبة تتبع مبدأ ESR.

---

## 📝 تمارين

1. **السؤال الأساسي (⭐)**: قم بإنشاء فهرس فريد على العمود `email` لمجموعة `users`.
2. **السؤال الأساسي (⭐)**: أنشئ فهرس TTL لمجموعة `sessions` (تنتهي صلاحيته بعد 30 دقيقة).
3. **تمرين متقدم (⭐⭐)**: قم بإنشاء فهرس جزئي لمجموعة `products` (يقتصر على المنتجات المعروضة للبيع حاليًا).
4. **مشكلة متقدمة (⭐⭐)**: صمم فهرسًا مثاليًّا لمجموعة `orders` باستخدام قاعدة ESR.
5. **التحدي (⭐⭐⭐)**: تصميم مخطط كامل لفهرسة التجارة الإلكترونية (10 فهارس أو أكثر)، وتحليل الاستخدام باستخدام $indexStats، وحذف الفهارس غير المستخدمة.
Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%