התכונה Query Explain מאפשרת לשלוח Cloud Firestore שאילתות אל הקצה העורפי ולקבל בתמורה נתונים סטטיסטיים מפורטים על הביצועים של ביצוע שאילתות בקצה העורפי. היא פועלת כמו הפעולה EXPLAIN [ANALYZE] במערכות רבות של מסדי נתונים רלציוניים.
אפשר לשלוח בקשות Query Explain באמצעות ספריות הלקוח של שרת Firestore.
התוצאות של Query Explain עוזרות להבין איך השאילתות מבוצעות, ומציגות חוסר יעילות ומיקום של צווארי בקבוק סבירים בצד השרת.
הסבר לשאילתה:
- מספק תובנות לגבי שלב תכנון השאילתה, כדי שתוכלו לשנות את האינדקסים של השאילתה ולשפר את היעילות.
- האפשרות 'ניתוח' עוזרת להבין את העלות והביצועים של כל שאילתה, ומאפשרת לחזור במהירות על דפוסי שאילתות שונים כדי לבצע אופטימיזציה של השימוש בהם.
הסבר על האפשרויות של Query Explain: ברירת מחדל וניתוח
אפשר לבצע פעולות של הסבר על שאילתות באמצעות האפשרות ברירת מחדל או האפשרות ניתוח.
באפשרות ברירת המחדל, Query Explain מתכנן את השאילתה, אבל מדלג על שלב ההפעלה. יוחזרו פרטים על השלב בתהליך התכנון. אפשר להשתמש בכלי הזה כדי לבדוק אם לשאילתה יש את האינדקסים הנדרשים, ולהבין באילו אינדקסים נעשה שימוש. לדוגמה, כך תוכלו לוודא ששאילתה מסוימת משתמשת באינדקס מורכב במקום לבצע חיתוך של הרבה אינדקסים שונים.
באמצעות האפשרות analyze, Query Explain מתכנן ומבצע את השאילתה. השאילתה הזו מחזירה את כל המידע על התכנון שצוין קודם, וגם את הנתונים הסטטיסטיים של זמן הריצה של ביצוע השאילתה. המידע הזה יכלול את פרטי החיוב של השאילתה, וגם תובנות ברמת המערכת לגבי הביצוע של השאילתה. אתם יכולים להשתמש בכלים האלה כדי לבדוק הגדרות שונות של שאילתות ואינדקסים, ולבצע אופטימיזציה של העלות והחביון שלהם.
מה העלות של Query Explain?
כשמשתמשים ב-Query Explain עם אפשרות ברירת המחדל, לא מתבצעות פעולות אינדקס או קריאה. לא משנה מה מורכבות השאילתה, נגבית עלות של פעולת קריאה אחת.
כשמשתמשים ב-Query Explain עם האפשרות analyze, מתבצעות פעולות של אינדקס וקריאה, ולכן תחויבו על השאילתה כרגיל. אין חיוב נוסף על פעילות הניתוח, רק החיוב הרגיל על השאילתה שמופעלת.
שימוש באפשרות ברירת המחדל של Query Explain
אפשר להשתמש בספריות הלקוח כדי לשלוח בקשה לאפשרות ברירת מחדל.
שימו לב שהבקשות מאומתות באמצעות IAM, עם אותן הרשאות של פעולות שאילתה רגילות. המערכת מתעלמת מטכניקות אימות אחרות, כמו Firebase Authentication. מידע נוסף זמין במדריך בנושא IAM לספריות לקוח של שרתים.
Java (אדמין)
Query q = db.collection("col").whereGreaterThan("a", 1);
ExplainOptions options = ExplainOptions.builder().build();
ExplainResults<QuerySnapshot> explainResults = q.explain(options).get();
ExplainMetrics metrics = explainResults.getMetrics();
PlanSummary planSummary = metrics.getPlanSummary();
צומת (אדמין)
const q = db.collection('col').where('country', '=', 'USA');
const options = { analyze : 'false' };
const explainResults = await q.explain(options);
const metrics = explainResults.metrics;
const plan = metrics.planSummary;
הפורמט המדויק של התשובה תלוי בסביבת ההפעלה. אפשר להמיר את התוצאות שמתקבלות ל-JSON. לדוגמה:
{
"indexes_used": [
{"query_scope": "Collection", "properties": "(category ASC, __name__ ASC)"},
{"query_scope": "Collection", "properties": "(country ASC, __name__ ASC)"},
]
}מידע נוסף זמין במאמר הפניה לדוח Query Explain.
שימוש באפשרות analyze של Query Explain
אפשר להשתמש בספריות הלקוח כדי לשלוח בקשה לאפשרות ניתוח.
שימו לב שהבקשות מאומתות באמצעות IAM, עם אותן הרשאות של פעולות שאילתה רגילות. המערכת מתעלמת מטכניקות אימות אחרות, כמו Firebase Authentication. מידע נוסף זמין במדריך בנושא IAM לספריות לקוח של שרתים.
Java (אדמין)
Query q = db.collection("col").whereGreaterThan("a", 1);
ExplainOptions options = ExplainOptions.builder().setAnalyze(true).build();
ExplainResults<QuerySnapshot> explainResults = q.explain(options).get();
ExplainMetrics metrics = explainResults.getMetrics();
PlanSummary planSummary = metrics.getPlanSummary();
List<Map<String, Object>> indexesUsed = planSummary.getIndexesUsed();
ExecutionStats stats = metrics.getExecutionStats();
צומת (אדמין)
const q = db.collection('col').where('country', '=', 'USA');
const options = { analyze : 'true' };
const explainResults = await q.explain(options);
const metrics = explainResults.metrics;
const plan = metrics.planSummary;
const indexesUsed = plan.indexesUsed;
const stats = metrics.executionStats;
בדוגמה הבאה מוצג האובייקט stats שמוחזר בנוסף ל-planInfo.
הפורמט המדויק של התשובה תלוי בסביבת ההפעלה. התגובה לדוגמה היא בפורמט JSON.
{
"resultsReturned": "5",
"executionDuration": "0.100718s",
"readOperations": "5",
"debugStats": {
"index_entries_scanned": "95000",
"documents_scanned": "5"
"billing_details": {
"documents_billable": "5",
"index_entries_billable": "0",
"small_ops": "0",
"min_query_cost": "0",
}
}
}מידע נוסף זמין במאמר הפניה לדוח Query Explain.
פירוש התוצאות וביצוע שינויים
נבחן עכשיו תרחיש לדוגמה שבו אנחנו שולחים שאילתה לגבי סרטים לפי ז'אנר ומדינה שבה הם הופקו.
לדוגמה, נניח שיש שאילתת SQL ששווה ערך לזו.
SELECT * FROM /movies WHERE category = 'Romantic' AND country = 'USA';
אם נשתמש באפשרות analyze, המדדים שיוחזרו יראו שהשאילתה מופעלת בשני אינדקסים של שדה יחיד, (category ASC, __name__ ASC) ו-(country ASC, __name__ ASC). הוא סורק 16,500 רשומות באינדקס, אבל מחזיר רק 1,200 מסמכים.
// Output query planning info { "indexes_used": [ {"query_scope": "Collection", "properties": "(category ASC, __name__ ASC)"}, {"query_scope": "Collection", "properties": "(country ASC, __name__ ASC)"}, ] } // Output query status { "resultsReturned": "1200", "executionDuration": "0.118882s", "readOperations": "1200", "debugStats": { "index_entries_scanned": "16500", "documents_scanned": "1200" "billing_details": { "documents_billable": "1200", "index_entries_billable": "0", "small_ops": "0", "min_query_cost": "0", } } }
כדי לשפר את הביצועים של הרצת השאילתה, אפשר ליצור אינדקס מורכב שמכסה את כל השדות (category ASC, country ASC, __name__ ASC).
אם נריץ שוב את השאילתה עם האפשרות analyze, נוכל לראות שהאינדקס החדש שנוצר נבחר עבור השאילתה הזו, והיא רצה הרבה יותר מהר ויעיל.
// Output query planning info { "indexes_used": [ {"query_scope": "Collection", "properties": "(category ASC, country ASC, __name__ ASC)"} ] } // Output query stats { "resultsReturned": "1200", "executionDuration": "0.026139s", "readOperations": "1200", "debugStats": { "index_entries_scanned": "1200", "documents_scanned": "1200" "billing_details": { "documents_billable": "1200", "index_entries_billable": "0", "small_ops": "0", "min_query_cost": "0", } } }