توضّح هذه الصفحة ناتج طلب بحث تم تنفيذه باستخدام أداة 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: $eq($user_1, $user_id) AND $eq($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
TableScan
تمثّل عملية فحص كاملة وغير مرتّبة لمجموعة. تُستخدَم عند تنفيذ طلب بحث بدون فهرس مرتبط.
يمكن أن يكون الترتيب STABLE أو UNDEFINED، ويشير STABLE إلى ترتيب محدّد.
• TableScan
| order: STABLE
| properties: *
| records returned: 1
| records scanned: 1
| source: (default)#/**/collection
تطبيق
تُجري عملية ربط بين مجموعتَين من البيانات (input وmap) من خلال تكرار كل صف من input، ثم فحص النتائج وعرضها من جانب map لكل صف.
يشير join_type إلى نوع عملية الربط. على سبيل المثال، يعني LEFT_OUTER أنّ جميع الصفوف من input يتم تضمينها مرة واحدة على الأقل في الناتج.
إذا لم يعثر صف input على أي نتائج من جانب map، سيظل مضمّنًا، مع قيم null للأعمدة من جانب map.
• Apply
| join_type: LEFT_OUTER
|
└── • input tree
| ...
└── • map 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