现已推出具有 MongoDB 兼容性的 Firestore 企业版!
了解详情。
优化对多个字段使用范围和不等式过滤条件的查询
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
本页面提供了一些索引编制策略的示例,可在对多个字段使用范围和不等式过滤条件的查询中使用这些策略来打造高效的查询体验。
在优化查询之前,请先了解一些相关概念。
使用查询解释优化查询
如需确定您的查询和索引是否最优,您可以使用查询解释获取查询计划摘要和查询执行统计信息:
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 个索引条目,仅返回了 5 个文档。由于不满足查询谓词,因此滤除了大量所读取的索引条目。
// 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"
}
}
}
您可以通过相关领域专业知识推断,大多数员工至少会有一些经验,但很少有人会有超过 10 万美元的薪水。鉴于这一分析洞见,您可以看到 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"
}
}
}
后续步骤
如未另行说明,那么本页面中的内容已根据知识共享署名 4.0 许可获得了许可,并且代码示例已根据 Apache 2.0 许可获得了许可。有关详情,请参阅 Google 开发者网站政策。Java 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-08-16。
[null,null,["最后更新时间 (UTC):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)."]]