优化对多个字段使用范围和不等式过滤条件的查询
本页面提供了一些索引编制策略的示例,可在对多个字段使用范围和不等式过滤条件的查询中使用这些策略来打造高效的查询体验。
在优化查询之前,请先了解一些相关概念。
使用查询解释优化查询
如需确定您的查询和索引是否最优,您可以使用查询解释获取查询计划摘要和查询执行统计信息:
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);
以下示例展示了如何使用正确的索引顺序来减少 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
限制条件更严苛。影响 Firestore 用于
执行查询,指定一个 orderBy
子句来对 salary
进行排序
experience
约束条件前面。
Java
db.collection("employees")
.whereGreaterThan("salary", 100000)
.whereGreaterThan("experience", 0)
.orderBy("salary")
.orderBy("experience");
当您明确使用 orderBy()
子句添加谓词时,
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" } } }