בדף הזה מוסבר הפלט של שאילתה שהופעלה באמצעות 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, היא עדיין תיכלל, עם ערכי null בעמודות מהקלט בצד שמאל.
• 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
מבצעת פעולת מיון על קבוצה קבועה של מאפיינים. מממש את כל הרשומות בזיכרון בבת אחת ומחזיר את הערכים הממוינים לפי הסדר. גודל קבוצת המיון מוגבל על ידי מגבלת הזיכרון של השאילתה.
כשמספקים מגבלה עוקבת, נעשה שימוש באלגוריתם מיון top-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
הפונקציה מחשבת קבוצה של ביטויים ומקצה את התוצאות לקבוצה של משתנים.
• 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