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

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

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

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

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