توضّح هذه الصفحة ناتج استعلام تم تنفيذه باستخدام 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
TableAccess
تتم إعادة ربط معرّف الصف المقدَّم بمحتوى الصف الفعلي من وحدة التخزين الأساسية. يجب استخدام TableAccess
إذا كانت العقدة الرئيسية (أو نتيجة طلب البحث النهائي) تتطلّب مجموعة فرعية من الحقول من المستندات.
• TableAccess
| 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: $eq($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
├── • TableAccess
...
├── • TableAccess
الحوسبة
تقيّم هذه الدالة مجموعة من التعبيرات، وتعيّن النتائج لمجموعة من المتغيرات.
• 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
| offset: 10
| records returned: 1