[[["容易理解","easyToUnderstand","thumb-up"],["確實解決了我的問題","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["難以理解","hardToUnderstand","thumb-down"],["資訊或程式碼範例有誤","incorrectInformationOrSampleCode","thumb-down"],["缺少我需要的資訊/範例","missingTheInformationSamplesINeed","thumb-down"],["翻譯問題","translationIssue","thumb-down"],["其他","otherDown","thumb-down"]],["上次更新時間:2025-08-17 (世界標準時間)。"],[],[],null,["# Life of a Spanner Query\n\nClient\n------\n\nSpanner supports [SQL queries](/spanner/docs/reference/standard-sql/query-syntax). Here's a sample query: \n\n SELECT s.SingerId, s.FirstName, s.LastName, s.SingerInfo\n FROM Singers AS s\n WHERE s.FirstName = @firstName;\n\nThe construct `@firstName` is a reference to a query parameter. You can use a\nquery parameter anywhere a literal value can be used. Using parameters in\nprogrammatic APIs is strongly recommended. Use of query parameters helps avoid\n[SQL injection](https://en.wikipedia.org/wiki/SQL_injection) attacks and the resulting queries are more likely\nto benefit from various server-side caches. See [Caching](#caching), below.\n\nQuery parameters must be bound to a value when the query is executed. For\nexample: \n\n Statement statement =\n Statement.newBuilder(\"SELECT s.SingerId...\").bind(\"firstName\").to(\"Jimi\").build();\n try (ResultSet resultSet = dbClient.singleUse().executeQuery(statement)) {\n while (resultSet.next()) {\n ...\n }\n }\n\nOnce Spanner receives an API call, it analyzes the query and bound\nparameters to determine which Spanner server node should process the\nquery. The server sends back a stream of result rows that are consumed by the\ncalls to `ResultSet.next()`.\n\nQuery execution\n---------------\n\nQuery execution begins with the arrival of an \"execute query\" request at some\nSpanner server. The server performs the following steps:\n\n- Validate the request\n- Parse the query text\n- Generate an initial query algebra\n- Generate an optimized query algebra\n- Generate an executable query plan\n- Execute the plan (check permissions, read data, encode results, etc.)\n\n[](../images/query_execution.png)\n\nParsing\n-------\n\nThe SQL parser analyzes the query text and converts it to an [abstract syntax\ntree](https://en.wikipedia.org/wiki/Abstract_syntax_tree). It extracts the basic query structure `(SELECT ...\nFROM ... WHERE ...)` and does syntactic checks.\n\nAlgebra\n-------\n\nSpanner's [type system](/spanner/docs/reference/standard-sql/data-types) can represent scalars, arrays,\nstructures, etc. The query algebra defines operators for table scans, filtering,\nsorting/grouping, all sorts of joins, aggregation, and much more. The initial\nquery algebra is built from the output of the parser. Field name references in\nthe parse tree are resolved using the database schema. This code also checks for\nsemantic errors (e.g., incorrect number of parameters, type mismatches, and so\nforth).\n\nThe next step (\"query optimization\") takes the initial algebra and generates a\nmore-optimal algebra. This might be simpler, more efficient, or just more-suited\nto the capabilities of the execution engine. For example, the initial algebra\nmight specify just a \"join\" while the optimized algebra specifies a \"hash join\".\n\nExecution\n---------\n\nThe final executable query plan is built from the rewritten algebra. Basically,\nthe executable plan is a [directed acyclic graph](https://en.wikipedia.org/wiki/Directed_acyclic_graph) of\n\"iterators\". Each iterator exposes a sequence of values. Iterators may consume\ninputs to produce outputs (e.g., sort iterator). Queries that involve a single\n[split](/spanner/docs/schema-and-data-model#database-splits) can be executed by a single server (the one that holds the data).\nThe server will scan ranges from various tables, execute joins, perform\naggregation, and all other operations defined by the query algebra.\n\nQueries that involve multiple splits will be factored into multiple pieces. Some\npart of the query will continue to be executed on the main (root) server. Other\npartial subqueries are handed-off to leaf nodes (those that own the splits being\nread). This hand-off can be recursively applied for complex queries, resulting\nin a tree of server executions. All servers agree on a timestamp so that the\nquery results are a consistent snapshot of the data. Each leaf server sends back\na stream of partial results. For queries involving aggregation, these could be\npartially-aggregated results. The query root server processes results from the\nleaf servers and runs the remainder of the query plan. For more information, see\n[Query execution plans](/spanner/docs/query-execution-plans).\n\nWhen a query involves multiple splits, Spanner can execute the query in\nparallel across the splits. The degree of parallelism depends on the\nrange of data that the query scans, the query execution plan, and the\ndistribution of data across splits.\nSpanner automatically sets the maximum degree of parallelism for a\nquery based on its instance size and [instance configuration](/spanner/docs/instance-configurations)\n(regional or multi-region) in order to achieve optimal query performance and\navoid [overloading the CPU](/spanner/docs/introspection/investigate-cpu-utilization).\n\nCaching\n-------\n\nMany of the artifacts of query processing are automatically cached and re-used\nfor subsequent queries. This includes query algebras, executable query plans,\netc. The caching is based on the query text, names and types of bound\nparameters, and so on. This is why using bound parameters (like `@firstName` in\nthe example above) is better than using literal values in the query text. The\nformer can be cached once and reused regardless of the actual bound value. See\n[Optimizing Spanner Query Performance](/spanner/docs/whitepapers/improving-query-performance) for more details.\n\nError handling\n--------------\n\nThe stream of result rows from the `executeQuery` method can be interrupted for\nany number of reasons: transient network errors, handoff of a [split](/spanner/docs/schema-and-data-model#database-splits)\nfrom one server to another (e.g., load balancing), server restarts (e.g.,\nupgrading to a new version), etc. To help recover from these errors,\nSpanner sends opaque \"resume tokens\" along with batches of partial\nresult data. These resume tokens can be used when retrying the query to continue\nwhere the interrupted query left off. If you are using the Spanner\nclient libraries, this is done automatically; thus, users of the client library\ndo not need to worry about this type of transient failure."]]