[[["易于理解","easyToUnderstand","thumb-up"],["解决了我的问题","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["很难理解","hardToUnderstand","thumb-down"],["信息或示例代码不正确","incorrectInformationOrSampleCode","thumb-down"],["没有我需要的信息/示例","missingTheInformationSamplesINeed","thumb-down"],["翻译问题","translationIssue","thumb-down"],["其他","otherDown","thumb-down"]],["最后更新时间 (UTC):2025-08-25。"],[],[],null,["# Understand query performance using Query Explain\n================================================\n\nQuery Explain allows you to submit Firestore in Native Mode queries to the\nbackend and receive detailed performance statistics on backend query execution\nin return. It functions like the `EXPLAIN [ANALYZE]` operation in many\nrelational database systems.\n\nQuery Explain requests can be sent using the [Firestore server client libraries](/firestore/docs/reference/libraries#server_client_libraries).\n\nQuery Explain results help you understand how your queries are\nexecuted, showing you inefficiencies and the location of likely server-side\nbottlenecks.\n\nQuery Explain:\n\n- Provides insights on the query planning phase so you can adjust your query indexes and boost efficiency.\n- Using the analyze option, helps you understand your cost and performance on a per-query basis and lets you quickly iterate through different query patterns in order to optimize their usage.\n\n| **Note:** Query Explain supports polled queries. Streaming queries are not yet supported.\n\nUnderstand Query Explain options: default and analyze\n-----------------------------------------------------\n\nQuery Explain operations can be performed using the *default* option or\n*analyze* option.\n\nWith the default option, Query Explain plans the query, but skips\nover the execution stage. This will return planner stage information. You can\nuse this to check that a query has the necessary indexes and understand which\nindexes are used. This will help you to verify, for example, that a particular\nquery is using a composite index over having to intersect over many different\nindexes.\n\nWith the analyze option, Query Explain both plans and executes the\nquery. This returns all the previously mentioned planner information along with\nstatistics from the query execution runtime. This will include the billing\ninformation of the query along with system-level insights into the query\nexecution. You can use this tooling to test various query and index\nconfigurations to optimize their cost and latency.\n\nWhat does Query Explain cost?\n-----------------------------\n\nWhen you use Query Explain with the default option, no index or read operations\nare performed. Regardless of query complexity, one read operation is charged.\n\nWhen you use Query Explain with the analyze option, index and read operations\nare performed, so you are charged for the query as usual. There is no additional\ncharge for the analysis activity, only the usual charge for the query being\nexecuted.\n\nUse Query Explain with the default option\n-----------------------------------------\n\nYou can use the client libraries to submit a default option request.\n\nNote that requests are authenticated with IAM, using the same\npermissions for regular query operations. Other authentication techniques, like\nFirebase Authentication, are ignored. For more information, see the guide on\n[IAM for server client libraries](https://cloud.google.com/firestore/docs/security/iam). \n\n##### Java (Admin)\n\n\n Query q = db.collection(\"col\").whereGreaterThan(\"a\", 1);\n ExplainOptions options = ExplainOptions.builder().build();\n\n ExplainResults\u003cQuerySnapshot\u003e explainResults = q.explain(options).get();\n ExplainMetrics metrics = explainResults.getMetrics();\n PlanSummary planSummary = metrics.getPlanSummary();\n\n \n##### Node (Admin)\n\n\n const q = db.collection('col').where('country', '=', 'USA');\n const options = { analyze : 'false' };\n\n const explainResults = await q.explain(options);\n\n const metrics = explainResults.metrics;\n const plan = metrics.planSummary;\n\n \nThe exact format of the response depends on the execution environment.\nReturned results can be converted to JSON. For example: \n\n```scdoc\n{\n \"indexes_used\": [\n {\"query_scope\": \"Collection\", \"properties\": \"(category ASC, __name__ ASC)\"},\n {\"query_scope\": \"Collection\", \"properties\": \"(country ASC, __name__ ASC)\"},\n ]\n}\n```\n\nFor more information, see the [Query Explain report reference](./query-explain-report-reference).\n\nUse Query Explain with the analyze option\n-----------------------------------------\n\nYou can use the client libraries to submit an analyze option request.\n\nNote that requests are authenticated with IAM, using the same\npermissions for regular query operations. Other authentication techniques, like\nFirebase Authentication, are ignored. For more information, see the guide on\n[IAM for server client libraries](https://cloud.google.com/firestore/docs/security/iam).\n**Note:** One query execution is analyzed at a time; therefore, query timing results may vary from request to request. The tool can help you spot significant structural inefficiencies, but is not intended to provide aggregate statistics on query performance. \n\n##### Java (Admin)\n\n\n Query q = db.collection(\"col\").whereGreaterThan(\"a\", 1);\n\n ExplainOptions options = ExplainOptions.builder().setAnalyze(true).build();\n\n ExplainResults\u003cQuerySnapshot\u003e explainResults = q.explain(options).get();\n\n ExplainMetrics metrics = explainResults.getMetrics();\n PlanSummary planSummary = metrics.getPlanSummary();\n List\u003cMap\u003cString, Object\u003e\u003e indexesUsed = planSummary.getIndexesUsed();\n ExecutionStats stats = metrics.getExecutionStats();\n\n \n##### Node (Admin)\n\n\n const q = db.collection('col').where('country', '=', 'USA');\n\n const options = { analyze : 'true' };\n\n const explainResults = await q.explain(options);\n\n const metrics = explainResults.metrics;\n const plan = metrics.planSummary;\n const indexesUsed = plan.indexesUsed;\n const stats = metrics.executionStats;\n\n \nThe following example shows the `stats` object returned in addition to `planInfo`.\nThe exact format of the response depends on the execution environment. The\nexample response is in JSON format. \n\n```scdoc\n{\n \"resultsReturned\": \"5\",\n \"executionDuration\": \"0.100718s\",\n \"readOperations\": \"5\",\n \"debugStats\": {\n \"index_entries_scanned\": \"95000\",\n \"documents_scanned\": \"5\"\n \"billing_details\": {\n \"documents_billable\": \"5\",\n \"index_entries_billable\": \"0\",\n \"small_ops\": \"0\",\n \"min_query_cost\": \"0\",\n }\n }\n\n}\n```\n\nFor more information, see the [Query Explain report reference](./query-explain-report-reference).\n\nInterpret results and make adjustments\n--------------------------------------\n\nLet's look at an example scenario in which we query movies by genre and\ncountry of production.\n| **Note:** Query Explain is designed for useful ad hoc analysis; its report format will evolve to maximize ease of reading and understanding, not suitability for machine processing. Some metrics are expected to change as Firestore in Native Mode evolves (i.e., metrics may be added, removed, or updated) and are not covered by the same deprecation policy as other Firestore in Native Mode APIs. For more information, see the [Query Explain report reference](./query-explain-report-reference).\n\nFor illustration, assume the equivalent of this SQL query. \n\n```scdoc\nSELECT *\nFROM /movies\nWHERE category = 'Romantic' AND country = 'USA';\n```\n\nIf we use the analyze option, the returned metrics show the query\nruns on two single-field indexes, `(category ASC, __name__ ASC)` and\n`(country ASC, __name__ ASC)`. It scans 16500 index entries, but returns\nonly 1200 documents. \n\n```scilab\n// Output query planning info\n{\n \"indexes_used\": [\n {\"query_scope\": \"Collection\", \"properties\": \"(category ASC, __name__ ASC)\"},\n {\"query_scope\": \"Collection\", \"properties\": \"(country ASC, __name__ ASC)\"},\n ]\n}\n\n// Output query status\n{\n \"resultsReturned\": \"1200\",\n \"executionDuration\": \"0.118882s\",\n \"readOperations\": \"1200\",\n \"debugStats\": {\n \"index_entries_scanned\": \"16500\",\n \"documents_scanned\": \"1200\"\n \"billing_details\": {\n \"documents_billable\": \"1200\",\n \"index_entries_billable\": \"0\",\n \"small_ops\": \"0\",\n \"min_query_cost\": \"0\",\n }\n }\n}\n```\n\nTo optimize the performance of executing the query, you can create a\nfully-covered composite index `(category ASC, country ASC, __name__ ASC)`.\n\nRunning the query with the analyze option again we can see that the\nnewly-created index is selected for this query, and the query runs much faster\nand more efficiently. \n\n```scilab\n// Output query planning info\n{\n \"indexes_used\": [\n {\"query_scope\": \"Collection\", \"properties\": \"(category ASC, country ASC, __name__ ASC)\"}\n ]\n}\n\n// Output query stats\n{\n \"resultsReturned\": \"1200\",\n \"executionDuration\": \"0.026139s\",\n \"readOperations\": \"1200\",\n \"debugStats\": {\n \"index_entries_scanned\": \"1200\",\n \"documents_scanned\": \"1200\"\n \"billing_details\": {\n \"documents_billable\": \"1200\",\n \"index_entries_billable\": \"0\",\n \"small_ops\": \"0\",\n \"min_query_cost\": \"0\",\n }\n }\n}\n```"]]