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

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

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

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

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