התכונה Query Explain מאפשרת לשלוח Cloud Firestore שאילתות לשרת העורפי ולקבל בתמורה נתונים סטטיסטיים מפורטים על הביצועים של הרצת השאילתות בשרת העורפי. היא פועלת כמו הפעולה EXPLAIN [ANALYZE]
במערכות רבות של מסדי נתונים רלציוניים.
אפשר לשלוח בקשות להסבר על שאילתות באמצעות ספריות הלקוח של שרת Firestore.
תוצאות ההסבר של השאילתה עוזרות להבין איך השאילתות מבוצעות, ומציגות חוסר יעילות ומיקום של צווארי בקבוק סבירים בצד השרת.
הסבר לשאילתה:
- מספק תובנות לגבי שלב תכנון השאילתה, כדי שתוכלו להתאים את האינדקסים של השאילתה ולשפר את היעילות.
- האפשרות 'ניתוח' עוזרת להבין את העלות והביצועים של כל שאילתה, ומאפשרת לכם לחזור במהירות על דפוסי שאילתות שונים כדי לבצע אופטימיזציה של השימוש בהם.
הסבר על האפשרויות של Query Explain: ברירת מחדל וניתוח
אפשר לבצע פעולות של Query Explain באמצעות האפשרות default או האפשרות analyze.
באפשרות ברירת המחדל, Query Explain מתכנן את השאילתה, אבל מדלג על שלב ההפעלה. הפונקציה תחזיר מידע על שלב התכנון. אפשר להשתמש בכלי הזה כדי לבדוק אם לשאילתה יש את האינדקסים הנדרשים, ולהבין באילו אינדקסים נעשה שימוש. לדוגמה, כך תוכלו לוודא ששאילתה מסוימת משתמשת באינדקס מורכב במקום לבצע חיתוך בין הרבה אינדקסים שונים.
באמצעות האפשרות analyze, Query Explain מנתח את שתי התוכניות ומריץ את השאילתה. השאילתה הזו מחזירה את כל המידע שצוין קודם לגבי התכנון, יחד עם נתונים סטטיסטיים מזמן הריצה של ביצוע השאילתה. המידע הזה יכלול את פרטי החיוב של השאילתה, וגם תובנות ברמת המערכת לגבי הביצוע של השאילתה. אתם יכולים להשתמש בכלים האלה כדי לבדוק הגדרות שונות של שאילתות ואינדקסים, ולבצע אופטימיזציה של העלות והחביון שלהם.
מה העלות של Query Explain?
כשמשתמשים באפשרות ברירת המחדל של Query Explain, לא מתבצעות פעולות אינדקס או קריאה. לא משנה מה מורכבות השאילתה, נגבה תשלום על פעולת קריאה אחת.
כשמשתמשים ב-Query Explain עם האפשרות analyze, מתבצעות פעולות של אינדקס וקריאה, ולכן תחויבו על השאילתה כרגיל. אין חיוב נוסף על פעילות הניתוח, רק החיוב הרגיל על השאילתה שמופעלת.
שימוש באפשרות ברירת המחדל של Query Explain
אפשר להשתמש בספריות הלקוח כדי לשלוח בקשה לאפשרות ברירת מחדל.
שימו לב שהבקשות מאומתות באמצעות IAM, עם אותן הרשאות של פעולות רגילות של שאילתות. המערכת מתעלמת מטכניקות אימות אחרות, כמו Firebase Authentication. מידע נוסף זמין במדריך בנושא IAM לספריות לקוח של שרתים.
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)"}, ] }
מידע נוסף זמין במאמר הסבר על דוח השאילתות.
שימוש באפשרות analyze של Query Explain
אפשר להשתמש בספריות הלקוח כדי לשלוח בקשה לאפשרות ניתוח.
שימו לב שהבקשות מאומתות באמצעות IAM, עם אותן הרשאות של פעולות רגילות של שאילתות. המערכת מתעלמת מטכניקות אימות אחרות, כמו Firebase Authentication. מידע נוסף זמין במדריך בנושא IAM לספריות לקוח של שרתים.
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", } } }
מידע נוסף זמין במאמר הסבר על דוח השאילתות.
פירוש התוצאות וביצוע שינויים
נבחן עכשיו תרחיש לדוגמה שבו אנחנו שולחים שאילתה לגבי סרטים לפי ז'אנר ומדינה שבה הם הופקו.
לדוגמה, נניח שיש שאילתת SQL ששווה ערך לזו.
SELECT * FROM /movies WHERE category = 'Romantic' AND country = 'USA';
אם נשתמש באפשרות הניתוח, המדדים שיוחזרו יראו שהשאילתה מופעלת בשני אינדקסים של שדה יחיד, (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", } } }