בדף הזה מוסבר הפלט של שאילתה שהופעלה באמצעות 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
סריקה מלאה ולא מסודרת של אוסף. הפרמטר הזה משמש כשמריצים שאילתה ללא אינדקס משויך.
הערך של order יכול להיות 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