使用範圍和不等式篩選器,將查詢最佳化至多個欄位

本頁面提供索引策略範例,您可以針對多個欄位的查詢使用範圍和不相等篩選器,藉此打造高效率的查詢體驗。

最佳化查詢之前,請先參閱相關概念

使用查詢說明最佳化查詢

如要判斷查詢和索引是否最佳化,您可以使用 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"
        }
    }
}

您可以從專業領域推斷,大多數員工至少都會有一些經驗,但薪水超過 100000 的員工很少。如有這種情況,您會發現 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"
        }
    }
}

後續步驟