使用 Cloud SQL Data API 执行 SQL 语句

本页面介绍了如何使用 Data API 针对 Cloud SQL 实例上的数据库执行 SQL 语句。借助 Data API,您可以使用 Cloud SQL Admin API 和 gcloud CLI 在已启用 Data API 访问权限的任何实例上运行 SQL 语句。

您可以将 Data API 与使用公共 IP 地址、专用服务访问通道或 Private Service Connect 的实例搭配使用。Data API 支持所有类型的 SQL 语句,包括数据操纵语言 (DML)、数据定义语言 (DDL) 和数据查询语言 (DQL)。Data API 非常适合运行小型快速的管理语句,例如创建数据库角色或用户以及进行小规模的架构更新。您还可以使用 Data API 来启用 PostgreSQL 扩展程序。

准备工作

在实例上执行 SQL 语句之前,请执行以下步骤。

配置数据库用户

Data API 需要以数据库用户身份进行身份验证,才能执行 SQL 语句。 您可以内置用户、IAM 用户、IAM 服务账号或 IAM 群组的身份进行身份验证。

如需使用 IAM 进行身份验证,请执行以下操作:

  1. 为实例配置 IAM 数据库身份验证
  2. 向实例添加 IAM 用户、服务账号或群组
  3. 向账号授予执行 SQL 语句所需的角色或权限。您可以在创建账号更新账号时分配数据库角色。如果您已创建具有最低权限的自定义数据库角色,请将其分配给相应账号。否则,请为该账号分配预定义的 cloudsqlsuperuser 角色,使用 Data API 创建权限较低的新自定义数据库角色,然后将新角色授予该账号,以取代 cloudsqlsuperuser

如需使用密码以内置用户身份进行身份验证,请执行以下操作:

  1. 创建密码不为空的用户账号。 您还可以使用默认用户 postgres
  2. 向账号授予执行 SQL 语句所需的角色或权限。您可以在创建账号更新账号时分配数据库角色。如果您已创建具有最低权限的自定义数据库角色,请将其分配给相应账号。否则,请为该账号分配预定义的 cloudsqlsuperuser 角色,使用 Data API 创建权限较低的新自定义数据库角色,然后将新角色授予该账号,以取代 cloudsqlsuperuser
  3. 使用 Secret Manager 创建区域级密钥来存储密码。出于安全考虑,Data API 会在 API 请求中要求提供 Secret 的资源名称,而不是密码。区域性密钥应存储在与 Cloud SQL 实例相同的区域中。即使使用 Secret Manager 的全球端点创建的密文存储在同一区域中,也不受支持。
  4. 向 Data API 的调用方授予 roles/secretmanager.secretAccessor。最佳实践是定义 IAM 条件,以允许用户访问特定 Secret,但不允许其访问项目中的其他 Secret。

所需的角色或权限

用于调用 Data API 的用户或服务账号必须具有执行 SQL 语句的权限,即 cloudsql.instances.executesql。以下预定义角色之一包含此权限:

  • Cloud SQL Admin (roles/cloudsql.admin)
  • Cloud SQL Instance User (roles/cloudsql.instanceUser)
  • Cloud SQL Studio User (roles/cloudsql.studioUser)

您还可以为包含 cloudsql.instances.executesql 权限的用户或服务账号定义 IAM 自定义角色。IAM 自定义角色支持此权限。

使用 Secret Manager 密钥进行身份验证时,用户或服务账号还必须拥有访问该密钥的权限,即 secretmanager.versions.access。以下预定义角色包含此权限:

  • Secret Manager Secret Accessor (roles/secretmanager.secretAccessor)
  • Secret Manager Admin (roles/secretmanager.admin)

启用或停用 Data API

如需使用 Data API,您必须为每个实例启用该 API。 您可以随时停用 Data API。

控制台

  1. 在 Google Cloud 控制台中,前往 Cloud SQL 实例页面。

    转到“Cloud SQL 实例”

  2. 如需打开实例的概览页面,请点击实例名称。
  3. 从 SQL 导航菜单中选择连接
  4. 点击网络标签页。
  5. 选中允许 Data API 复选框。
  6. 点击保存

gcloud

如需在实例上启用 Data API 访问权限,请使用带有 --data-api-access=ALLOW_DATA_API 标志的 gcloud sql instances patch 命令:

gcloud sql instances patch INSTANCE_NAME --data-api-access=ALLOW_DATA_API

如需停用 Data API 访问权限,请使用 --data-api-access=DISALLOW_DATA_API 标志:

gcloud sql instances patch INSTANCE_NAME --data-api-access=DISALLOW_DATA_API

INSTANCE_NAME 替换为要启用或停用 Data API 的实例的名称。

REST

如需在实例上启用 Data API 访问权限,请向 instances.patch 端点发送 PATCH 请求:

PATCH https://sqladmin.googleapis.com/sql/v1beta4/projects/PROJECT_ID/instances/INSTANCE_NAME

请求正文应包含设置为 ALLOW_DATA_APIdataApiAccess 字段:

{
  "dataApiAccess": "ALLOW_DATA_API"
}

如需停用 Data API 访问权限,请将 dataApiAccess 设置为 DISALLOW_DATA_API

执行 SQL 语句

您可以使用 gcloud CLI 或 REST API 对 Cloud SQL 实例上的数据库执行 SQL 语句。

使用 IAM 进行身份验证

您可以使用 IAM 数据库身份验证执行 SQL 语句。

gcloud

如需使用 gcloud CLI 对实例上的数据库执行 SQL 语句,请使用 gcloud sql instances execute-sql 命令。

gcloud sql instances execute-sql INSTANCE_NAME \
--database=DATABASE_NAME \
--sql=SQL_STATEMENT \
--partial-result-mode=PARTIAL_RESULT_MODE

进行以下替换:

  • INSTANCE_NAME:实例的名称。
  • DATABASE_NAME:实例中数据库的名称。
  • SQL_STATEMENT:要执行的 SQL 语句。如果语句包含空格或 shell 特殊字符,则必须用引号将其引起来。
  • PARTIAL_RESULT_MODE:可选。控制结果不完整时的响应方式。可以是 ALLOW_PARTIAL_RESULTFAIL_PARTIAL_RESULTPARTIAL_RESULT_MODE_UNSPECIFIED。请参阅修改截断行为

您还可以根据需要添加 --project=PROJECT_ID 标志。

Terraform

您可以使用 Terraform 上的 Data API 来预配数据库资源,例如数据库、表、扩展程序、用户和权限授予,而无需手动连接到实例。如需在 Terraform 上执行 SQL 脚本,请使用 google_sql_provision_script Terraform 资源。

resource "google_sql_database_instance" "instance" {
  name             = "my-instance"
  database_version = "POSTGRES_17"

  settings {
    tier            = "db-perf-optimized-N-2"
    data_api_access = "ALLOW_DATA_API"  # This allows the use of Data API.
    database_flags {
      name  = "cloudsql.iam_authentication"
      value = "on"
    }
  }
}

/*
 * Create a database user for your account and grant roles so it has privilege to
 * access the database. Set the type to CLOUD_IAM_USER for huamn account or
 * CLOUD_IAM_SERVICE_ACCOUNT for service account. If a service account is used
 * and the instance is Postgres, trim the ".gserviceaccount.com"
 * suffix to avoid exceeding the username length limit.
*/
resource "google_sql_user" "iam_user" {
  name     = "account-used-to-apply-this-config@example.com"
  instance = google_sql_database_instance.instance.name
  type     = "CLOUD_IAM_USER"

  # Roles granted to the user. For least privilege, you can create smaller roles
  # and then assign them to this user in place of `cloudsqlsuperuser`.
  database_roles = ["cloudsqlsuperuser"]
}

resource "google_sql_database" "database" {
  name     = "my-database"
  instance = google_sql_database_instance.instance.name
}

resource "google_sql_provision_script" "script" {
  # You can inline the script or import from a file like script  = file("${path.module}/script.sql")
  # When modified, the whole script will be executed again. It's recommended to
  # make the script idempotent with patterns like create if not exists ... or
  # if not exists (select ...) then ... end if.
  script  = "CREATE TABLE IF NOT EXISTS table1 ( col VARCHAR(16) NOT NULL );"

  instance = google_sql_database_instance.instance.name
  database = google_sql_database.database.name
  description = "sql script to create tables"

  # The identity account used to apply your Terraform config must exist as an
  # IAM user or IAM service account in the instance. Terraform connects to the
  # instance via IAM database authentication to execute the script.
  depends_on = [google_sql_user.iam_user]
}

应用更改

如需在 Google Cloud 项目中应用 Terraform 配置,请完成以下部分中的步骤。

准备 Cloud Shell

  1. 启动 Cloud Shell
  2. 设置要应用 Terraform 配置的默认 Google Cloud 项目。

    您只需为每个项目运行一次以下命令,即可在任何目录中运行它。

    export GOOGLE_CLOUD_PROJECT=PROJECT_ID

    如果您在 Terraform 配置文件中设置显式值,则环境变量会被替换。

准备目录

每个 Terraform 配置文件都必须有自己的目录(也称为“根模块”)。

  1. Cloud Shell 中,创建一个目录,并在该目录中创建一个新文件。文件名必须具有 .tf 扩展名,例如 main.tf。在本教程中,该文件称为 main.tf
    mkdir DIRECTORY && cd DIRECTORY && touch main.tf
  2. 如果您按照教程进行操作,可以在每个部分或步骤中复制示例代码。

    将示例代码复制到新创建的 main.tf 中。

    (可选)从 GitHub 中复制代码。如果端到端解决方案包含 Terraform 代码段,则建议这样做。

  3. 查看和修改要应用到您的环境的示例参数。
  4. 保存更改。
  5. 初始化 Terraform。您只需为每个目录执行一次此操作。
    terraform init

    (可选)如需使用最新的 Google 提供程序版本,请添加 -upgrade 选项:

    terraform init -upgrade

应用更改

  1. 查看配置并验证 Terraform 将创建或更新的资源是否符合您的预期:
    terraform plan

    根据需要更正配置。

  2. 通过运行以下命令并在提示符处输入 yes 来应用 Terraform 配置:
    terraform apply

    等待 Terraform 显示“应用完成!”消息。

  3. 打开您的 Google Cloud 项目以查看结果。在 Google Cloud 控制台的界面中找到资源,以确保 Terraform 已创建或更新它们。

删除更改

删除 google_sql_provision_script 资源不会删除其创建的数据库内资源。如需删除这些列,您可以在脚本中明确添加 drop ... if exists 等语句,然后应用更改。

REST

如需使用 REST API 对实例上的数据库执行 SQL 语句,请向 executeSql 端点发送 POST 请求:

POST https://sqladmin.googleapis.com/sql/v1beta4/projects/PROJECT_ID/instances/INSTANCE_NAME/executeSql

请求正文应包含数据库名称和 SQL 语句:

{
  "database": "DATABASE_NAME",
  "sqlStatement": "SQL_STATEMENT",
  "partialResultMode": "PARTIAL_RESULT_MODE"
  "autoIamAuthn": true
}

进行以下替换:

  • PROJECT_ID:您的项目 ID。
  • INSTANCE_NAME:实例的名称。
  • DATABASE_NAME:实例中数据库的名称。
  • SQL_STATEMENT:要执行的 SQL 语句。
  • PARTIAL_RESULT_MODE:可选。控制当结果超过 10 MB 时 API 的响应方式。可以是 FAIL_PARTIAL_RESULTALLOW_PARTIAL_RESULTPARTIAL_RESULT_MODE_UNSPECIFIED。 请参阅修改截断行为

使用密码进行身份验证

当密码作为区域 Secret 存储在与 Cloud SQL 实例相同的区域中时,您可以使用内置的密码身份验证来执行 SQL 语句。

gcloud

如需使用 gcloud CLI 对实例上的数据库执行 SQL 语句,请使用 gcloud sql instances execute-sql 命令。

gcloud sql instances execute-sql INSTANCE_NAME \
--database=DATABASE_NAME \
--sql=SQL_STATEMENT \
--user=USER \
--password-secret-version=PASSWORD_SECRET_VERSION \
--partial-result-mode=PARTIAL_RESULT_MODE

进行以下替换:

  • INSTANCE_NAME:实例的名称。
  • DATABASE_NAME:实例中数据库的名称。
  • SQL_STATEMENT:要执行的 SQL 语句。如果语句包含空格或 shell 特殊字符,则必须用引号将其引起来。
  • USER:要进行身份验证的数据库用户。
  • PASSWORD_SECRET_VERSION:Secret Manager 中用于存放数据库用户密码的 Secret 的资源名称。 该密钥应为区域级密钥,并存储在与 Cloud SQL 实例相同的区域中。预期资源名称格式为 projects/{project}/locations/{location}/secrets/{secret}/versions/{secret_version}
  • PARTIAL_RESULT_MODE:可选。控制结果不完整时的响应方式。可以是 ALLOW_PARTIAL_RESULTFAIL_PARTIAL_RESULTPARTIAL_RESULT_MODE_UNSPECIFIED。请参阅修改截断行为

Terraform

您可以使用 Terraform 上的 Data API 来预配数据库资源,例如数据库、表、扩展程序、用户和权限授予,而无需手动连接到实例。如需在 Terraform 上执行 SQL 脚本,请使用 google_sql_provision_script Terraform 资源。

resource "google_sql_user" "built_in_user" {
  name     = "tf-user"
  host     = "%"  # Don't set this field for PostgreSQL and SQL Server.
  instance = google_sql_database_instance.instance.name
  password = "changeme"
  type     = "BUILT_IN"
}

# Create a regional secret. Global secrets are not supported even if
# located in one region only.
resource "google_secret_manager_regional_secret" "secret" {
  secret_id = "db-password"

  # Use the same region as the Cloud SQL instance.
  location = "us-central1"
}

resource "google_secret_manager_regional_secret_version" "secret_version" {
  secret = google_secret_manager_regional_secret.secret.id
  secret_data = "changeme"
}

resource "google_sql_provision_script" "script" {
  # You can inline the script or import from a file like script  = file("${path.module}/script.sql")
  # When modified, the whole script will be executed again. It's recommended to
  # make the script idempotent with patterns like create if not exists ... or
  # if not exists (select ...) then ... end if.
  script  = "CREATE TABLE IF NOT EXISTS table1 ( col VARCHAR(16) NOT NULL );"

  instance = google_sql_database_instance.instance.name
  database = google_sql_database.database.name
  description = "sql script to create tables"
  user = google_sql_user.built_in_user.name

  # The location should be the same as the Cloud SQL instance's location.
  password_secret_version = "projects/my-project/locations/us-central1/secrets/db-password/versions/latest"

  # The built-in database user and password secret version must be created
  # first. Cloud SQL will retrieve password from Secret Manager
  # and connect to this user account to execute your script.
  depends_on = [
    google_sql_user.built_in_user,
    google_secret_manager_regional_secret_version.secret_version
  ]
}

应用更改

如需在 Google Cloud 项目中应用 Terraform 配置,请完成以下部分中的步骤。

准备 Cloud Shell

  1. 启动 Cloud Shell
  2. 设置要应用 Terraform 配置的默认 Google Cloud 项目。

    您只需为每个项目运行一次以下命令,即可在任何目录中运行它。

    export GOOGLE_CLOUD_PROJECT=PROJECT_ID

    如果您在 Terraform 配置文件中设置显式值,则环境变量会被替换。

准备目录

每个 Terraform 配置文件都必须有自己的目录(也称为“根模块”)。

  1. Cloud Shell 中,创建一个目录,并在该目录中创建一个新文件。文件名必须具有 .tf 扩展名,例如 main.tf。在本教程中,该文件称为 main.tf
    mkdir DIRECTORY && cd DIRECTORY && touch main.tf
  2. 如果您按照教程进行操作,可以在每个部分或步骤中复制示例代码。

    将示例代码复制到新创建的 main.tf 中。

    (可选)从 GitHub 中复制代码。如果端到端解决方案包含 Terraform 代码段,则建议这样做。

  3. 查看和修改要应用到您的环境的示例参数。
  4. 保存更改。
  5. 初始化 Terraform。您只需为每个目录执行一次此操作。
    terraform init

    (可选)如需使用最新的 Google 提供程序版本,请添加 -upgrade 选项:

    terraform init -upgrade

应用更改

  1. 查看配置并验证 Terraform 将创建或更新的资源是否符合您的预期:
    terraform plan

    根据需要更正配置。

  2. 通过运行以下命令并在提示符处输入 yes 来应用 Terraform 配置:
    terraform apply

    等待 Terraform 显示“应用完成!”消息。

  3. 打开您的 Google Cloud 项目以查看结果。在 Google Cloud 控制台的界面中找到资源,以确保 Terraform 已创建或更新它们。

删除更改

删除 google_sql_provision_script 资源不会删除其创建的数据库内资源。如需删除这些列,您可以在脚本中明确添加 drop ... if exists 等语句,然后应用更改。

REST

如需使用 REST API 对实例上的数据库执行 SQL 语句,请向 executeSql 端点发送 POST 请求:

POST https://sqladmin.googleapis.com/sql/v1beta4/projects/PROJECT_ID/instances/INSTANCE_NAME/executeSql

请求正文应包含数据库名称和 SQL 语句:

{
  "database": "DATABASE_NAME",
  "sqlStatement": "SQL_STATEMENT",
  "user": "USER",
  "passwordSecretVersion": "PASSWORD_SECRET_VERSION",
  "partialResultMode": "PARTIAL_RESULT_MODE"
}

进行以下替换:

  • PROJECT_ID:您的项目 ID。
  • INSTANCE_NAME:实例的名称。
  • DATABASE_NAME:实例中数据库的名称。
  • SQL_STATEMENT:要执行的 SQL 语句。
  • USER:要进行身份验证的数据库用户。
  • PASSWORD_SECRET_VERSION:Secret Manager 中用于存放数据库用户密码的 Secret 的资源名称。 该密钥应为区域级密钥,并存储在与 Cloud SQL 实例相同的区域中。预期资源名称格式为 projects/{project}/locations/{location}/secrets/{secret}/versions/{secret_version}
  • PARTIAL_RESULT_MODE:可选。控制当结果超过 10 MB 时 API 的响应方式。可以是 FAIL_PARTIAL_RESULTALLOW_PARTIAL_RESULTPARTIAL_RESULT_MODE_UNSPECIFIED。 请参阅修改截断行为

修改截断行为

您可以在执行 SQL 时通过在请求中添加 "partialResultMode" 字段来控制如何处理大型结果。此字段接受以下值:

  • FAIL_PARTIAL_RESULT:默认值。如果结果超过 10 MB,或者只能检索到部分结果,则抛出错误。不返回结果。
  • ALLOW_PARTIAL_RESULT:如果结果超过 10 MB,或者由于错误只能检索到部分结果,则返回截断的结果并将 partial_result 设置为 true。不抛出错误。
  • PARTIAL_RESULT_MODE_UNSPECIFIED:未指定模式,实际上与 FAIL_PARTIAL_RESULT 相同。

审核查询

您可以通过在请求中设置 applicationName 字段来跟踪应用名称。数据库将在会话统计信息(例如表 pg_stat_activity)中跟踪应用名称。

您可以使用 Query Insights 跟踪有关查询的更多信息并分析性能问题。 请注意,Query Insights 会显示 ExecuteSql 查询的客户端 IP 为 localhost,因为数据库连接是从 Cloud SQL 实例本身内部建立的。

您还可以使用 pg-audit 出于安全或合规性目的记录查询。

限制

  • 响应的大小上限为 10 MB。如果 partialResultMode 设置为 ALLOW_PARTIAL_RESULT,则超出此大小的结果会被截断,否则会抛出错误。
  • 请求大小上限为 0.5 MB。
  • 您只能对正在运行的 Cloud SQL for PostgreSQL 实例运行 SQL 语句。
  • Cloud SQL 不支持将 Data API 与设置为外部服务器复制的实例搭配使用。
  • 处理时间超过 30 秒的请求会被取消。不支持使用 SET STATEMENT_TIMEOUT 设置更长的语句超时时间。
  • Cloud SQL 限制每个实例的并发 executeSql 请求数量,以防止过载。如果达到限制,后续请求将失败并返回以下错误之一:

    • At most 'x' concurrent queries may be run on this instance. Try again later.
    • Maximum concurrent reads 'x' reached.

    上限 (x) 为每个实例 10 次查询。

  • 每个响应最多可包含 10 条数据库消息或警告。

  • 如果存在语句语法或执行错误,则不会返回任何结果。

  • Data API 无法以密码为空的内置用户身份进行身份验证。

  • 消耗大量内存的语句可能会导致内存不足错误。如需详细了解如何避免这些错误,请参阅管理内存用量的最佳实践。运行内存利用率高的数据库实例通常会导致性能问题、停滞,甚至数据库停机。

  • 当实例上正在进行某些维护操作时,出于数据完整性方面的考虑,Data API 可能会暂时被屏蔽。如果发生这种情况,请稍后重试。

  • 如果您在查询编辑器中同时运行多个语句,并且一个或多个语句导致错误,则所有语句的执行会中止,并且系统会显示第一个出现的错误。
  • 当数据库服务器检测到无效的查询语法时,会在 postgres.log 中生成日志。这些条目显示为 cloudsqladmin 条目,包含无效查询、语法错误的位置以及相应的错误消息。如需从视图中移除这些日志,请配置日志过滤条件以排除 cloudsqladmin 数据库、cloudsqladmin 用户或两者都排除。
  • SQL 脚本及其执行响应可能会在您的客户端与目标实例的位置之间经过中间位置。因此,对于某些 Assured Workloads 项目以及手动强制执行 constraints/sql.restrictNoncompliantResourceCreation 的项目,请求会失败,并显示错误“不支持某些 Assured Workloads 控制措施套餐文件夹中的实例”。

问题排查

本部分介绍了与使用 Data API 相关的问题,以及问题排查步骤。

问题 问题排查
The instance doesn't allow using ExecuteSql to access this instance. You can allow it by patching the instance with {settings: { dataApiAccess: "ALLOW_DATA_API" }} Data API 默认处于停用状态。 在实例上启用 Data API,以解决此问题。
Secret cannot be provided when auto_iam_authn is true. auto_iam_authn 设置为 true 时,您将使用 IAM 对数据库进行身份验证。 此身份验证方法不需要密码或密钥。 请参阅 使用 IAM 进行身份验证
ExecuteSql API is not supported for instances in certain Assured Workloads control packages folders yet. SQL 脚本及其执行响应可能会在您的客户端与目标实例所在位置之间的中间位置进行传输。因此,某些 Assured Workloads 项目中的实例的请求会失败。如果您的项目未加入 Assured Workloads,但 constraints/sql.restrictNoncompliantResourceCreation 是手动强制执行的,请让您组织的管理员移除该限制条件,这样新创建的实例上的问题就会得到解决。
IAM authentication is not enabled for the instance 将实例配置为使用 IAM 身份验证,以解决此问题。
The database is currently unavailable. 实例可能正在重启、进行维护或处于不健康状态。请检查实例的状态,然后稍后重试。