使用 Cloud SQL Data API 執行 SQL 陳述式

本頁面說明如何使用 Data API,對 Cloud SQL 執行個體上的資料庫執行 SQL 陳述式。透過 Data API,您可以使用 Cloud SQL Admin API 和 gcloud CLI,在已啟用 Data API 存取權的任何執行個體上執行 SQL 陳述式。

您可以在使用公開 IP 位址、私人服務連線或 Private Service Connect 的執行個體上使用 Data API。Data API 支援所有類型的 SQL 陳述式,包括資料操縱語言 (DML)、資料定義語言 (DDL) 和資料查詢語言 (DQL)。Data API 適合執行小型且快速的管理陳述式,例如建立資料庫角色或使用者,以及進行小型結構定義更新。

事前準備

如要在執行個體上執行 SQL 陳述式,請按照下列步驟操作。

設定資料庫使用者

Data API 必須以資料庫使用者的身分進行驗證,才能執行 SQL 陳述式。

如要使用密碼以內建使用者身分進行驗證,請按照下列步驟操作:

  1. 建立使用者帳戶並設定密碼。您也可以使用預設使用者 sqlserver。
  2. 授予帳戶執行 SQL 陳述式所需的角色或權限。如果使用者不是 sqlserver,請授予使用者 db_owner 角色。
  3. 使用 Secret Manager 建立區域性密鑰來儲存密碼。為確保安全,Data API 會在 API 要求中要求提供密鑰的資源名稱,而不是密碼。區域密鑰應與 Cloud SQL 執行個體位於相同區域。即使是儲存在相同區域,使用 Secret Manager 全域端點建立的密鑰也不受支援。
  4. 授予 Data API 的呼叫端 roles/secretmanager.secretAccessor。最佳做法是定義 IAM 條件,允許使用者存取特定密鑰,但無法存取專案中的其他密鑰。

必要角色或權限

用於呼叫 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)

您也可以為使用者或服務帳戶定義 IAM 自訂角色,其中包含 cloudsql.instances.executesql 權限。IAM 自訂角色支援這項權限。

使用 Secret Manager 密鑰進行驗證時,使用者或服務帳戶也必須具備存取密鑰的權限 secretmanager.versions.access。這項權限包含在下列其中一個預先定義的角色中:

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

啟用或停用 Data API

如要使用 Data API,必須為每個執行個體啟用這項功能。 您隨時可以停用 Data API。

控制台

  1. 前往 Google Cloud 控制台的「Cloud SQL Instances」(Cloud SQL 執行個體) 頁面。

    前往 Cloud SQL 執行個體

  2. 點選執行個體名稱,開啟執行個體的「總覽」頁面。
  3. 在 SQL 導覽選單中,選取「連線」。
  4. 按一下 [網路] 分頁標籤。
  5. 勾選「允許 Data API」核取方塊。
  6. 按一下 [儲存]。

gcloud

如要在執行個體上啟用 Data API 存取權,請使用 gcloud sql instances patch 指令搭配 --data-api-access=ALLOW_DATA_API 旗標:

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 存取權,請將 PATCH 要求傳送至 instances.patch 端點:

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

要求主體應包含設為 ALLOW_DATA_API 的 dataApiAccess 欄位:

{
  "dataApiAccess": "ALLOW_DATA_API"
}

如要停用 Data API 存取權,請將 dataApiAccess 設為 DISALLOW_DATA_API。

執行 SQL 陳述式

您可以使用 gcloud CLI 或 REST API,針對 Cloud SQL 執行個體上的資料庫執行 SQL 陳述式。

使用密碼驗證

如果密碼以區域密碼的形式儲存在 Secret Manager 中,且與 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 陳述式。如果陳述式含有空格或殼層特殊字元,就必須加上引號。
  • USER:要驗證身分的資料庫使用者。
  • PASSWORD_SECRET_VERSION:Secret Manager 密鑰的資源名稱,內含資料庫使用者的密碼。密鑰應為區域密鑰,並儲存在與 Cloud SQL 執行個體相同的區域。預期的資源名稱格式為 projects/{project}/locations/{location}/secrets/{secret}/versions/{secret_version}。
  • PARTIAL_RESULT_MODE:選填。控管結果不完整時的回應方式。可以是 ALLOW_PARTIAL_RESULT、FAIL_PARTIAL_RESULT 或 PARTIAL_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 顯示「Apply complete!」訊息。

  3. 開啟 Google Cloud 專案即可查看結果。在 Google Cloud 控制台中,前往 UI 中的資源,確認 Terraform 已建立或更新這些資源。

刪除變更

刪除 google_sql_provision_script 資源不會刪除該資源建立的資料庫內資源。如要刪除這些變數,您可以在指令碼中明確新增陳述式 (例如 drop ... if exists),然後套用變更。

REST

如要使用 REST API 對執行個體上的資料庫執行 SQL 陳述式,請將 POST 要求傳送至 executeSql 端點:

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 密鑰的資源名稱,內含資料庫使用者的密碼。密鑰應為區域密鑰,並儲存在與 Cloud SQL 執行個體相同的區域。預期的資源名稱格式為 projects/{project}/locations/{location}/secrets/{secret}/versions/{secret_version}。
  • PARTIAL_RESULT_MODE:選填。控管結果超過 10 MB 時,API 的回應方式。可以是 FAIL_PARTIAL_RESULT、 ALLOW_PARTIAL_RESULT 或 PARTIAL_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 欄位,追蹤應用程式名稱。資料庫會在工作階段統計資料中追蹤應用程式名稱,例如在 sys.dm_exec_sessions 資料表中。

您可以使用查詢洞察追蹤查詢的更多資訊,並分析效能問題。

您也可以使用 SQL Server 資料庫稽核,記錄查詢以確保安全或符合法規。

限制

  • 回覆大小上限為 10 MB。如果 partialResultMode 設為 ALLOW_PARTIAL_RESULT,超過這個大小的結果會遭到截斷,否則會擲回錯誤。
  • 要求大小上限為 0.5 MB。
  • 您只能為正在執行的 SQL Server 適用的 Cloud SQL 執行個體執行 SQL 陳述式。
  • Cloud SQL 不支援搭配 Data API 使用為外部伺服器複製設定的執行個體。
  • 如果要求超過 30 秒未完成,系統就會取消要求。系統不支援使用 SET LOCK_TIMEOUT 設定較高的陳述式逾時時間。
  • 為避免過載,Cloud SQL 會限制每個執行個體的並行 executeSql 要求數量。如果達到上限,後續要求就會失敗,並傳回下列其中一個錯誤:

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

    如果執行個體的總記憶體少於 10 GB,則上限 (x) 為 5 個查詢;如果總記憶體至少有 10 GB,則上限為 10 個查詢。

  • 每個回應最多可包含 10 則資料庫訊息或警告。

  • 如有陳述式語法或執行錯誤,系統不會傳回任何結果。

  • Data API 無法以密碼為空的內建使用者身分進行驗證。

  • 如果執行個體正在進行特定維護作業,為確保資料完整性,系統可能會暫時封鎖 Data API。如果發生這種情況,請稍後再試。

  • 系統不支援 GO 指令。這個指令用於 Microsoft SQL Server 公用程式,表示陳述式批次已結束,可以傳送至 SQL Server。
  • 如果查詢包含二進位資料欄,Data API 就無法顯示。 請改為將二進位值轉換為字串。

    舉例來說,請替換:

    SELECT my_binary_column from my_table2;
    

    替換為:

    SELECT CONVERT(NVARCHAR(4000), my_binary_column, 1) from my_table2;
    
  • 執行多項查詢時,如果其中一項查詢失敗,系統會傳回第一個遇到的錯誤。錯誤發生前,批次中的部分陳述式可能已成功執行。如要避免這個問題,請在 transaction 陳述式中包裝多個查詢:

    BEGIN TRANSACTION
        YOUR_SQL_STATEMENTS
    COMMIT;
    

    更改下列內容:

    • YOUR_SQL_STATEMENTS:您要執行的陳述式,做為這項查詢的一部分
  • SQL 指令碼及其執行回應可能會在用戶端與目標執行個體位置之間的中間位置傳輸。因此,對於特定 Assured Workloads 專案和手動強制執行 constraints/sql.restrictNoncompliantResourceCreation 的專案,要求會失敗並顯示「not supported for instances in certain Assured Workloads control packages folders」(特定 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 是手動強制執行,請要求貴機構的管理員移除限制,新建立的執行個體就會解決問題。
The server principal USERNAME is not able to access the database DATABASE_NAME under the current security context. 使用者不是資料庫成員。以 sqlserver 使用者身分連線至資料庫,然後新增使用者,並授予新使用者資料庫的 db_owner 角色。例如:
  EXEC sp_adduser 'user';
  EXEC sp_addrolemember 'db_owner', 'user'
  
The database is currently unavailable. 執行個體可能正在重新啟動、維護中或處於異常狀態。請檢查執行個體的狀態,然後稍後再試。