אופטימיזציה של שאילתות באמצעות מסננים של טווח ואי-שוויון בכמה שדות

בדף הזה מוצגות דוגמאות לאסטרטגיית הוספה לאינדקס שאפשר להשתמש בהן בשאילתות עם מסנני טווח ואי-שוויון בכמה שדות, כדי ליצור חוויית שאילתה יעילה.

לפני שמבצעים אופטימיזציה של השאילתות, כדאי לקרוא על המושגים שקשורים לכך.

אופטימיזציה של שאילתות באמצעות Query Explain

כדי לבדוק אם השאילתה והאינדקסים שלכם הם אופטימליים, אתם יכולים להשתמש בQuery Explain כדי לקבל את סיכום תוכנית השאילתה וסטטיסטיקות הביצוע של השאילתה:

JavaNode.js
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());
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);

בדוגמה הבאה אפשר לראות איך שימוש בסדר אינדקס נכון מקטין את מספר רשומות האינדקס ש-Cloud 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. כדי להשפיע על האינדקס שבו Cloud Firestore משתמש כדי להריץ את השאילתה, מציינים פסקה orderBy שמסדרת את האילוץ salary לפני האילוץ experience.

Java
db.collection("employees")
  .whereGreaterThan("salary", 100000)
  .whereGreaterThan("experience", 0)
  .orderBy("salary")
  .orderBy("experience");

כשמשתמשים באופן מפורש בסעיף orderBy() כדי להוסיף את התנאים, Cloud 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"
        }
    }
}

המאמרים הבאים