אופטימיזציה של שאילתות עם מסנני טווח ואי-שוויון בכמה שדות
בדף הזה מופיעות דוגמאות לאסטרטגיית הוספה לאינדקס שאפשר להשתמש בהן בשאילתות עם מסנני טווח ואי-שוויון בכמה שדות, כדי ליצור חוויית שאילתה יעילה.
לפני שמבצעים אופטימיזציה של השאילתות, כדאי לקרוא על המושגים שקשורים לכך.
אופטימיזציה של שאילתות באמצעות Query Explain
כדי לבדוק אם השאילתה והאינדקסים שלכם הם אופטימליים, אתם יכולים להשתמש בQuery Explain כדי לקבל את סיכום תוכנית השאילתה ואת נתוני הביצוע של השאילתה:
Java
Query q = db.collection("employees").whereGreaterThan("salary",
100000).whereGreaterThan("experience", 0);
ExplainResults<QuerySnapshot> explainResults = q.explain(ExplainOptions.builder().analyze(true).build()).get();
ExplainMetrics metrics = explainResults.getMetrics();
PlanSummary planSummary = metrics.getPlanSummary();
ExecutionStats executionStats = metrics.getExecutionStats();
System.out.println(planSummary.getIndexesUsed());
System.out.println(stats.getResultsReturned());
System.out.println(stats.getExecutionDuration());
System.out.println(stats.getReadOperations());
System.out.println(stats.getDebugStats());
Node.js
let q = db.collection("employees")
.where("salary", ">", 100000)
.where("experience", ">",0);
let options = { analyze : 'true' };
let explainResults = await q.explain(options);
let planSummary = explainResults.metrics.planSummary;
let stats = explainResults.metrics.executionStats;
console.log(planSummary);
console.log(stats);
בדוגמה הבאה אפשר לראות איך שימוש בסדר אינדקס נכון מקטין את מספר רשומות האינדקס ש-Firestore סורק.
שאילתות פשוטות
בדוגמה הקודמת של אוסף עובדים, השאילתה הפשוטה שמופעלת עם האינדקס (experience ASC, salary ASC) היא:
Java
db.collection("employees")
.whereGreaterThan("salary", 100000)
.whereGreaterThan("experience", 0)
.orderBy("experience")
.orderBy("salary");
השאילתה סורקת 95,000 רשומות באינדקס רק כדי להחזיר חמישה מסמכים. מכיוון שהתנאי של השאילתה לא מתקיים, המערכת קוראת מספר גדול של רשומות באינדקס, אבל מסננת אותן.
// Output query planning info { "indexesUsed": [ { "properties": "(experience ASC, salary ASC, __name__ ASC)", "query_scope": "Collection" } ], // Output Query Execution Stats "resultsReturned": "5", "executionDuration": "2.5s", "readOperations": "100", "debugStats": { "index_entries_scanned": "95000", "documents_scanned": "5", "billing_details": { "documents_billable": "5", "index_entries_billable": "95000", "small_ops": "0", "min_query_cost": "0" } } }
מניסיון בתחום אפשר להסיק שלרוב העובדים יש לפחות ניסיון מסוים, אבל רק למעטים יש משכורת של יותר מ-100,000. בהתאם לתובנה הזו, אפשר לראות שהאילוץ salary הוא סלקטיבי יותר מהאילוץ experience. כדי להשפיע על האינדקס ש-Firestore משתמש בו להפעלת השאילתה, צריך לציין משפט orderBy שמסדר את האילוץ salary לפני האילוץ experience.
Java
db.collection("employees")
.whereGreaterThan("salary", 100000)
.whereGreaterThan("experience", 0)
.orderBy("salary")
.orderBy("experience");
כשמשתמשים באופן מפורש בסעיף orderBy() כדי להוסיף את התנאים, Firestore משתמש באינדקס (salary ASC, experience ASC) כדי להריץ את השאילתה. מכיוון שהסלקטיביות של מסנן הטווח הראשון גבוהה יותר בשאילתה הזו בהשוואה לשאילתה הקודמת, השאילתה רצה מהר יותר ועלותה נמוכה יותר.
// Output query planning info { "indexesUsed": [ { "properties": "(salary ASC, experience ASC, __name__ ASC)", "query_scope": "Collection" } ], // Output Query Execution Stats "resultsReturned": "5", "executionDuration": "0.2s", "readOperations": "6", "debugStats": { "index_entries_scanned": "1000", "documents_scanned": "5", "billing_details": { "documents_billable": "5", "index_entries_billable": "1000", "small_ops": "0", "min_query_cost": "0" } } }