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

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

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

אופטימיזציה של שאילתות באמצעות 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);

בדוגמה הבאה אפשר לראות איך השימוש בסדר הנכון של האינדקס מפחית את מספר הרשומות באינדקס ש-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"
        }
    }
}

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