现已推出具有 MongoDB 兼容性的 Firestore 企业版!
了解详情。
使用範圍和不等式篩選器,將查詢最佳化至多個欄位
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
本頁面提供索引策略範例,可用於對多個欄位使用範圍和不等於篩選器的查詢,以建立有效率的查詢體驗。
最佳化查詢前,請先瞭解相關概念。
使用「查詢說明」功能最佳化查詢
如要判斷查詢和索引是否最佳化,可以使用 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");
查詢只會掃描 95000 個索引項目,然後傳回五份文件。由於查詢述詞不符合條件,系統會讀取大量索引項目,但會將這些項目篩除。
// 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
子句,在 experience
限制之前排序 salary
限制。
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"
}
}
}
後續步驟
除非另有註明,否則本頁面中的內容是採用創用 CC 姓名標示 4.0 授權,程式碼範例則為阿帕契 2.0 授權。詳情請參閱《Google Developers 網站政策》。Java 是 Oracle 和/或其關聯企業的註冊商標。
上次更新時間:2025-08-16 (世界標準時間)。
[null,null,["上次更新時間:2025-08-16 (世界標準時間)。"],[],[],null,["\u003cbr /\u003e\n\nThis page provides examples of indexing strategy that you can use for queries\nwith range and inequality filters on multiple fields to create an efficient\nquery experience.\n\nBefore you optimize your queries, read about [the related concepts](/docs/firestore/query-data/multiple-range-fields).\n\nOptimize queries with Query Explain\n\nTo determine if your query and indexes are optimal, you can use [Query\nExplain](/docs/firestore/query-explain) to get the query plan summary and execution statistics\nof the query: \n\nJava \n\n Query q = db.collection(\"employees\").whereGreaterThan(\"salary\",\n 100000).whereGreaterThan(\"experience\", 0);\n\n ExplainResults\u003cQuerySnapshot\u003e explainResults = q.explain(ExplainOptions.builder().analyze(true).build()).get();\n ExplainMetrics metrics = explainResults.getMetrics();\n\n PlanSummary planSummary = metrics.getPlanSummary();\n ExecutionStats executionStats = metrics.getExecutionStats();\n\n System.out.println(planSummary.getIndexesUsed());\n System.out.println(stats.getResultsReturned());\n System.out.println(stats.getExecutionDuration());\n System.out.println(stats.getReadOperations());\n System.out.println(stats.getDebugStats());\n\nNode.js \n\n let q = db.collection(\"employees\")\n .where(\"salary\", \"\u003e\", 100000)\n .where(\"experience\", \"\u003e\",0);\n\n let options = { analyze : 'true' };\n let explainResults = await q.explain(options);\n\n let planSummary = explainResults.metrics.planSummary;\n let stats = explainResults.metrics.executionStats;\n\n console.log(planSummary);\n console.log(stats);\n\nThe following example shows how the use of correct index ordering reduces the\nnumber of index entries that Cloud Firestore scans.\n\nSimple queries\n\nWith the [earlier example](/docs/firestore/query-data/multiple-range-fields#indexing_considerations) of a collection of employees, the simple query\nthat runs with the `(experience ASC, salary ASC)` index is as follows: \n\nJava \n\n db.collection(\"employees\")\n .whereGreaterThan(\"salary\", 100000)\n .whereGreaterThan(\"experience\", 0)\n .orderBy(\"experience\")\n .orderBy(\"salary\");\n\nThe query scans 95000 index entries only to return five documents. Since the query\npredicate isn't satisfied, a large number of index entries are read but are\nfiltered out. \n\n```scilab\n// Output query planning info\n{\n \"indexesUsed\": [\n {\n \"properties\": \"(experience ASC, salary ASC, __name__ ASC)\",\n \"query_scope\": \"Collection\"\n }\n ],\n\n // Output Query Execution Stats\n \"resultsReturned\": \"5\",\n \"executionDuration\": \"2.5s\",\n \"readOperations\": \"100\",\n \"debugStats\": {\n \"index_entries_scanned\": \"95000\",\n \"documents_scanned\": \"5\",\n \"billing_details\": {\n \"documents_billable\": \"5\",\n \"index_entries_billable\": \"95000\",\n \"small_ops\": \"0\",\n \"min_query_cost\": \"0\"\n }\n }\n}\n```\n\nYou can infer from domain expertise that most employees will have at least some\nexperience but few will have a salary that is more than 100000. Given this\ninsight, you can see that the `salary` constraint is more selective than the\n`experience` constraint. To influence the index that Cloud Firestore uses to\nexecute the query, specify an `orderBy` clause that orders the `salary`\nconstraint before the `experience` constraint. \n\nJava \n\n db.collection(\"employees\")\n .whereGreaterThan(\"salary\", 100000)\n .whereGreaterThan(\"experience\", 0)\n .orderBy(\"salary\")\n .orderBy(\"experience\");\n\nWhen you explicitly use the `orderBy()` clause to add the predicates,\nCloud Firestore uses the `(salary ASC, experience ASC)` index to run the query.\nSince the selectivity of the first range filter is higher in this query\ncompared to the earlier query, the query runs faster and is more cost efficient. \n\n```scilab\n// Output query planning info\n{\n \"indexesUsed\": [\n {\n \"properties\": \"(salary ASC, experience ASC, __name__ ASC)\",\n \"query_scope\": \"Collection\"\n }\n ],\n\n // Output Query Execution Stats\n \"resultsReturned\": \"5\",\n \"executionDuration\": \"0.2s\",\n \"readOperations\": \"6\",\n \"debugStats\": {\n \"index_entries_scanned\": \"1000\",\n \"documents_scanned\": \"5\",\n \"billing_details\": {\n \"documents_billable\": \"5\",\n \"index_entries_billable\": \"1000\",\n \"small_ops\": \"0\",\n \"min_query_cost\": \"0\"\n }\n }\n}\n```\n\nWhat's next\n\n- Learn about [Query Explain](/docs/firestore/query-explain).\n- Learn about [indexing best practices](/docs/firestore/query-data/index-overview#indexing_best_practices)."]]