توضّح هذه الصفحة ناتج طلب بحث تم تنفيذه باستخدام Query Explain. للتعرّف على كيفية تنفيذ طلب بحث باستخدام Query Explain، راجِع تحليل تنفيذ طلب البحث باستخدام Query Explain.
المفاهيم الشائعة
يتم استخدام المفاهيم والمصطلحات الشائعة التالية في شجرة التنفيذ.
الصفوف والسجلات
يُستخدم المصطلحان صف وسجلّ للإشارة بشكل عام إلى مستند أو إدخال في الفهرس.
المتغيرات
يشير $ إلى متغيّر يتم إنشاؤه أو الرجوع إليه في شجرة التنفيذ. على سبيل المثال: $foo_1. تُستخدَم هذه المتغيّرات عادةً للإشارة إلى محتوى مستند أو قيمة تعبير تم تقييمه أثناء تنفيذ طلب بحث.
يمكن أن تظهر المتغيّرات الداخلية التالية في عُقد التنفيذ:
$__key__: المفتاح هو معرّف داخلي لمستند. وهو معرّف مطلق وفريد يتضمّن المشروع وقاعدة البيانات والمسار الكامل للمستند.$__id__- المعرّف هو معرّف فريد لمستند ضمن مجموعته. هذه السمة فريدة ضمن مجموعة واحدة.$rid: رقم تعريف الصف هو معرّف داخلي لمستند في وحدة التخزين. هذه السمة فريدة ضمن مجموعة واحدة.
لنفترض أنّ هناك مثالاً يتم فيه استخدام عقدة Compute لاحتساب __id__ من المستند __key__:
Compute
| $__id__1: _id($__key__)
| records returned: 1
القيود والنطاقات
تستخدِم بعض عُقد البحث السمتَين constraints وranges لوصف نطاق القيم التي يتم البحث فيها. تستخدم هذه السمات تنسيق شجرة نطاق يتضمّن قائمة بالقيم. تتطابق هذه القيم مع القائمة المرتبة للمفاتيح
التي تظهر في تعريف الفهرس. على سبيل المثال، يتوافق النطاق الأول الذي يظهر
في الشجرة، هنا (1..5]، مع القيود المفروضة على المفتاح الأول،
هنا a، في القائمة المرتبة للمفاتيح:
| index: type=CollectionGroupIndex, id=CICAgOjXh#EK, keys=[a ASC, b ASC, __key__ ASC]
| constraints: /
|----(1..5]
|----[1L]
يشير كل مستوى من المسافة البادئة إلى القيد الذي ينطبق على المفتاح التالي في القائمة. تمثّل الأقواس المربعة نطاقًا شاملاً، بينما تمثّل الأقواس الدائرية نطاقًا حصريًا. في هذه الحالة، يتم تحويل القيد إلى 1 < "a" <= 5 و"b" = 1.
في المثال التالي الذي يتضمّن فروعًا متعددة لـ a،
يتوافق القيد مع 1 < a <= 5 OR a = 10:
| constraints: /
|----(1L, 5L]
|----[10L]
المتغيّرات الرئيسية
في بعض عُقد الفحص (مثل SequentialScan)، تتوفّر قائمة بالمفاتيح كجزء من السمة index، بالإضافة إلى السمة keys المنفصلة في العقدة Scan. تشير السمة keys في العقدة Scan إلى اسم المتغيّر لكل مفتاح في تعريف الفهرس، بالترتيب. يمكن استخدام المتغيّرات للإشارة إلى قيم وقت التشغيل للحقل الذي تم البحث فيه في موضع أعلى في شجرة التنفيذ.
في المثال التالي، يتم ربط قيمة الحقل user للمستند الحالي بالمتغير $user_1، وقيمة الحقل date_placed بالمتغير $date_placed_1.
index: type=CollectionGroupIndex, id=CICAgOjXh4EK, keys=[user ASC, date_placed ASC, __key__ ASC]
keys: [user ASC, date_placed ASC, __key__ ASC]
عُقد التنفيذ
يمكن أن تحتوي شجرة تنفيذ الاستعلام على العُقد التالية.
SeekingScan
تمثّل عملية بحث ديناميكية قد لا تكون الصفوف التي يتم عرضها ضمن نطاق تسلسلي واحد للفهرس، ويجب إجراء عمليات بحث متعدّدة ومختلفة لتلبية طلب البحث.
على سبيل المثال، يتطلّب الاستعلام الذي يتضمّن a ويكون فيه b مساويًا 1، والذي يعمل على فهرس ["a" ASC, "b" ASC]، إجراء عملية فحص وعرض نطاق منفصل وغير متسلسل على الأرجح لكل قيمة مميزة من a.
هذا الإجراء أكثر كفاءة من عملية بحث كاملة في TableScan، ولكنه أقل كفاءة من عملية بحث واحدة في SequentialScan ضمن فهرس مركّب من ["b" ASC, "a" ASC].
• SeekingScan
| constraints: /
|----(-∞..+∞)
|----[1L]
| index: type=CollectionGroupIndex, id=CAE, keys=[user ASC, quantity ASC, __key__ ASC]
| keys: [user ASC, quantity ASC, __key__ ASC]
| properties: Selection { user }
| records returned: 1
| records scanned: 1
SequentialScan
تمثّل عملية فحص لنطاق ثابت ومتسلسل من الصفوف في مساحة التخزين يمكن تنفيذها في عملية قراءة واحدة.
يشير key ordering length إلى عدد المفاتيح التي يجب الاحتفاظ بها
وعرضها بترتيب المفاتيح الأصلي. بالنسبة إلى مخطط [k1, k2, k3]، يعني طول ترتيب المفتاح 0 أنّه يمكن عرض نتائج البحث بأي ترتيب، ويعني 1 أنّه يمكن ترتيب النتائج حسب k1، ولكن يمكن عرض الصفوف التي تتضمّن القيمة نفسها في k1 بأي ترتيب، ويعني 3 أنّه يمكن عرض المستندات بترتيب مرتّب تمامًا.
• SequentialScan
| index: type=CollectionGroupIndex, id=CAE, keys=[user ASC, date_placed ASC, __key__ ASC]
| key ordering length: 3
| keys: [user ASC, date_placed ASC, __key__ ASC]
| limit: 10
| properties: Selection { a }
| ranges: /
| records returned: 1
| records scanned: 1
UniqueScan
تمثّل هذه السمة عملية فحص لنطاق ثابت ومتسلسل من الصفوف في وحدة التخزين مع إزالة الصفوف المكرّرة في الذاكرة.
• UniqueScan
| index: type=CollectionGroupIndex, id=CAE, keys=[user ASC, date_placed ASC, __key__ ASC]
| keys: [user ASC, date_placed ASC, __key__ ASC]
| properties: Selection { a }
| ranges: /
|----(-∞..+∞)
| records returned: 1
| records scanned: 1
IndexSeek
تمثّل عملية فحص ديناميكية قد يتم فيها تحديد معلَمات الصفوف التي يتم عرضها حسب بيانات وقت التشغيل، وقد لا تكون ضمن نطاق تسلسلي واحد للفهرس، وقد يتم إجراء عمليات فحص مميزة متعددة لتلبية طلب البحث.
على سبيل المثال، طلب بحث يكون فيه user مساويًا $user_id وdate_placed مساويًا "2025-08-10" يتم تنفيذه على فهرس ["user" ASC, "date_placed" ASC]، سيستخدم قيمة المتغيّر $user_id في وقت التشغيل والشرط "2025-08-10" على date_placed للحدّ من نطاقات البحث.
• IndexSeek
| index: type=CollectionGroupIndex, id=CAE, keys=[user ASC, date_placed ASC, __key__ ASC]
| fields: [$user_1 ASC, $date_placed_1 ASC, $rid ASC]
| key: $key_1
| filter: equal($user_1, $user_id) AND equal($date_placed_1, "2025-08-10")
| records returned: 1
| records scanned: 1
جلب
تتم إعادة ربط معرّف الصف المقدَّم بمحتوى الصف الفعلي من وحدة التخزين الأساسية. يجب استخدام Fetch إذا كانت العقدة الرئيسية (أو نتيجة طلب البحث النهائي) تتطلّب مجموعة فرعية من الحقول من المستندات.
• Fetch
| order: PRESERVE_INPUT_ORDER
| peak memory usage: 4.00 KiB (4,096 B)
| properties: *
| records returned: 1
LookupById
تُجري عملية ربط من خلال البحث عن المستندات في مجموعة خارجية حسب معرّفاتها. يتم الحصول على المعرّفات المطلوب البحث عنها من حقل في المستندات المصدر. تتم إضافة نتائج البحث كحقل جديد إلى المستندات المدخلة.
• LookupById
| local_field: $localField_1
| foreign_datasource: (default)#/**/foreign
| output: $output_1
TableScan
عملية فحص كاملة وغير مرتّبة لمجموعة يتم استخدامها عند تنفيذ طلب بحث بدون فهرس مرتبط.
يمكن أن يكون الترتيب إما STABLE أو UNDEFINED، حيث يشير STABLE إلى ترتيب
تحديدي.
• TableScan
| order: STABLE
| properties: *
| records returned: 1
| records scanned: 1
| source: (default)#/**/collection
NestedLoopJoin
تُجري عملية ربط بين مجموعتَين من البيانات (يسار ويمين) من خلال تكرار كل صف من الإدخال الأيسر، ثم البحث في الإدخال الأيمن عن الصفوف المطابقة لكل صف أيسر استنادًا إلى join_condition.
يشير join_type إلى نوع الربط. على سبيل المثال، يعني LEFT_OUTER
أنّه يتم تضمين جميع الصفوف من الإدخال الأيسر مرة واحدة على الأقل في الإخراج.
إذا لم يتطابق صف على اليسار مع أي صف في الإدخال على اليمين استنادًا إلى join_condition، سيظل مضمّنًا، مع قيم فارغة للأعمدة من الإدخال على اليمين.
• NestedLoopJoin
| join_type: LEFT_OUTER
| join_condition: equal($left, $right)
|
└── • left tree
| ...
└── • right tree
...
HashAggregate
تنفيذ العمليات المجمّعة المستندة إلى التجزئة يتطلّب ذلك إنشاء المجموعة الكاملة في الذاكرة قبل عرض النتيجة، ويجب ألا يتجاوز الحدّ الأقصى لذاكرة طلب البحث.
• HashAggregate
| aggregations: [sum($b_1) AS total]
| groups: [$a_1]
| peak memory usage: 4.00 KiB (4,096 B)
| records returned: 0
StreamAggregate
عقدة تجميع متخصصة تحتفظ بالحالة لمجموعة واحدة فقط في كل مرة، ما يقلل من الحد الأقصى لاستخدام الذاكرة. يتم استخدام هذا الخيار عندما تعرض العقدة الفرعية الأساسية المجموعات بالتسلسل. على سبيل المثال، عند التجميع حسب القيم المميزة لحقل أثناء استخدام فهرس في هذا الحقل.
• StreamAggregate
| keys: [foo ASC, bar ASC]
| properties: Selection { baz }
| aggregations: [$sum($foo_1) AS baz]
MajorSort
تُجري عملية ترتيب على مجموعة ثابتة من السمات. يتم إنشاء جميع السجلات في الذاكرة مرة واحدة، ويتم عرض القيم التي تم ترتيبها حسب الترتيب، ويتم تحديد حجم مجموعة الترتيب من خلال الحد الأقصى لذاكرة طلب البحث.
عند توفير حد لاحق، يتم استخدام خوارزمية ترتيب أعلى k لتقليل استخدام الذاكرة. باستخدام هذه الطريقة، يمكن إجراء عمليات ترتيب على مجموعة كبيرة من السجلات بشكل عشوائي، طالما أنّ الذاكرة المستخدمة لتخزين العناصر k التي تم أخذها في الاعتبار لا تتجاوز الحدّ الأقصى.
• MajorSort
| fields: [a ASC, b DESC]
| limit: 10
| peak memory usage: 4.00 KiB (4,096 B)
| records returned: 1
Concat
تدمج هذه الدالة نتائج عُقد فرعية متعددة وتعرض النتيجة للعقدة الرئيسية. لا تزيل هذه العقدة التكرار من النتائج التي تظهر في عدة عناصر فرعية، كما أنّ ترتيب النتائج المعروضة غير ثابت.
• Concat
├── • Fetch
...
├── • Fetch
الحوسبة
تقيّم هذه الدالة مجموعة من التعبيرات، وتعيّن النتائج لمجموعة من المتغيرات.
• Compute
| $user_1: user
| $full_name_1: str_concat($first_name_1, " ", $last_name_1)
| $address_1: UNSET
| records returned: 1
فلتر
تعرض الصفوف بشكل انتقائي إذا كانت تتطابق مع التعبير المقدَّم فقط.
• Filter
| expression: $eq(foo, "bar")
| records returned: 1
RecordCount
تحسب هذه السمة عدد الصفوف التي تنتجها العقدة الفرعية وترسل العدد الحالي إلى المتغيّر المحدّد في السمة count.
• RecordCount
| count: $row_number_1
| records returned: 1
القيم
تنتج هذه الدالة سلسلة من القيم الحرفية التي يمكن العمل عليها. يتم استخدامها بشكل أساسي عند تقديم مجموعة أو قائمة مستندات كمدخل لطلب بحث.
• Values
| expression: [{__key__=/col/1}, {__key__=/col/2}]
Unnest
تؤدي إلى إلغاء تداخل القيمة التي تنتجها العقدة الفرعية.
• Unnest
| expression: foo AS unnested_foo
الحدّ
تحدّ من عدد الصفوف المعروضة للعقدة الرئيسية.
• Limit
| limit: 10
| records returned: 1
الإزاحة
تتخطّى عددًا محدّدًا من الصفوف التي تنتجها العقدة الفرعية.
• Offset
| offset: 10
| records returned: 1