查詢統計資料

Spanner 提供內建資料表,保存了許多使用最多 CPU 的查詢和資料操縱語言 (DML) 陳述式,以及所有查詢的匯總 (包括變更串流查詢)。

可用性

SPANNER_SYS 資料只能透過 SQL 介面取得,例如:

  • Google Cloud 控制台中資料庫的 Spanner Studio 頁面

  • gcloud spanner databases execute-sql 指令

  • 「查詢洞察」資訊主頁

  • executeQuery API

Spanner 提供的其他單一讀取方法不支援 SPANNER_SYS

依查詢分組的 CPU 使用率

下列資料表會追蹤特定時間範圍內,CPU 使用率最高的查詢:

  • SPANNER_SYS.QUERY_STATS_TOP_MINUTE:1 分鐘間隔期間內的查詢
  • SPANNER_SYS.QUERY_STATS_TOP_10MINUTE:10 分鐘間隔期間內的查詢
  • SPANNER_SYS.QUERY_STATS_TOP_HOUR:1 小時間隔期間內的查詢

這些資料表具備下列屬性:

  • 每個資料表都包含資料表名稱所指定的非重疊時間間隔長度的資料。

  • 間隔是基於時鐘時間。1 分鐘間隔的結束時間是目前這一分鐘、10 分鐘間隔的結束時間是目前這個小時的每 10 分鐘,而 1 小時間隔的結束時間是目前這個小時。

    舉例來說,在上午 11:59:30,SQL 查詢的最近可用間隔如下:

    • 1 分鐘:上午 11:58:00–11:58:59
    • 10 分鐘:上午 11:40:00–11:49:59
    • 1 小時:上午 10:00:00–10:59:59
  • Spanner 會依照 SQL 查詢的文字將統計資料分組。如果查詢使用查詢參數,Spanner 會將該查詢的所有執行作業組成一個資料列。如果查詢使用字串常值,只有在全部的查詢文字皆相同時,Spanner 才會將統計資料分組;只要有不同的文字,每個查詢都會以個別資料列顯示。針對批次 DML,Spanner 會在產生指紋之前,先刪除連續相同的陳述式,以便將批次轉換為標準格式。

  • 如果有要求代碼,FPRINT 就是要求代碼的雜湊。否則,則為 TEXT 值的雜湊。對於分區 DML,FPRINT 一律是 TEXT 值的雜湊。

  • 每個資料列都包含 Spanner 在指定間隔期間擷取特定 SQL 查詢的統計資料,這些資料列包含此特定 SQL 查詢所有執行作業的統計資料。

  • 如果 Spanner 無法儲存在間隔期間執行的所有查詢,系統會優先處理在指定間隔期間 CPU 使用率最高的查詢。

  • 追蹤的查詢包括已完成、失敗或遭使用者取消的查詢。

  • 部分統計資料僅適用於已執行但未完成的查詢:

    • 所有未成功的查詢的執行次數和平均延遲時間 (以秒為單位)。

    • 逾時查詢的執行次數。

    • 使用者取消或因網路連線問題而失敗的查詢執行次數。

  • 資料表中的所有欄均可為空值。

先前執行的 分區 DML 陳述式查詢統計資料具有下列屬性:

  • 每個成功的分區 DML 陳述式都會嚴格計為「一次」執行。執行失敗、已取消或正在執行的分區 DML 陳述式,其執行計數為零。

  • 系統不會追蹤分區 DML 的 ALL_FAILED_EXECUTION_COUNTALL_FAILED_AVG_LATENCY_SECONDSCANCELLED_OR_DISCONNECTED_EXECUTION_COUNTTIMED_OUT_EXECUTION_COUNT 統計資料。

  • 先前執行的分區 DML 陳述式統計資料,可能會以不同的間隔顯示。SPANNER_SYS.QUERY_STATS_TOP_10MINUTESPANNER_SYS.QUERY_STATS_TOP_HOUR 分別針對在 10 分鐘和 1 小時內完成的分區 DML 陳述式提供匯總檢視畫面。如要查看持續時間超過 1 小時的陳述式統計資料,請參閱查詢範例

資料表結構定義

資料欄名稱 類型 說明
INTERVAL_END TIMESTAMP 包含的查詢執行作業在發生時的時間間隔結束時間。
REQUEST_TAG STRING 這項查詢作業的選用要求標記。如要進一步瞭解如何使用標籤,請參閱「 使用要求標記進行疑難排解」一文。
QUERY_TYPE STRING 指出查詢是 PARTITIONED_QUERY 還是 QUERYPARTITIONED_QUERY 是從 PartitionQuery API 取得的 partitionToken 查詢,或是 分區 DML 陳述式。所有其他查詢和 DML 陳述式都會以 QUERY 查詢類型表示。
TEXT STRING SQL 查詢文字,只顯示約 64KB 的內容。

多個查詢的統計資料如果有相同的標記字串,系統會將這些資料分組在單一列中,並以 REQUEST_TAG 標記與該標記字串相符的資料。這個欄位只會顯示其中一個查詢的文字,且只顯示約 64 KB 的內容。針對批次 DML,系統會將一組 SQL 陳述式扁平化為單一資料列,並使用分隔符號連接。會先刪除連續相同的 SQL 文字,再進行截斷。
TEXT_TRUNCATED BOOL 查詢文字是否只顯示部分內容。
TEXT_FINGERPRINT INT64 如有 REQUEST_TAG 值,指紋為其雜湊;如果沒有,則為 TEXT 值的雜湊。對應至稽核記錄中的 query_fingerprint 欄位
EXECUTION_COUNT INT64 Spanner 在間隔期間看到查詢的次數。
AVG_LATENCY_SECONDS FLOAT64 資料庫內每個查詢執行的平均時間長度,以秒為單位。這個平均值會排除結果集和額外負荷的編碼與傳輸時間。
AVG_ROWS FLOAT64 查詢傳回的平均列數。
AVG_BYTES FLOAT64 查詢傳回的平均資料位元組數,不包含傳輸編碼額外負荷。
AVG_ROWS_SCANNED FLOAT64 查詢掃描的平均列數,不包含已刪除的值。
AVG_CPU_SECONDS FLOAT64 Spanner 在執行該查詢所有作業時的平均 CPU 作業時間秒數。
ALL_FAILED_EXECUTION_COUNT INT64 在間隔期間,查詢失敗的次數。
ALL_FAILED_AVG_LATENCY_SECONDS FLOAT64 資料庫內每個查詢執行失敗的平均時間長度,以秒為單位。這個平均值會排除結果集和額外負荷的編碼與傳輸時間。
CANCELLED_OR_DISCONNECTED_EXECUTION_COUNT INT64 在指定期間內,使用者取消查詢或因網路連線中斷而導致查詢失敗的次數。
TIMED_OUT_EXECUTION_COUNT INT64 在時間間隔期間,查詢逾時的次數。
AVG_BYTES_WRITTEN FLOAT64 陳述式寫入的平均位元組數。
AVG_ROWS_WRITTEN FLOAT64 陳述式修改的平均列數。
STATEMENT_COUNT INT64 匯入此項目的陳述式總和。對於一般查詢和 DML,這項值等於執行次數。針對批次 DML,Spanner 會擷取批次中的陳述式數量。
RUN_IN_RW_TRANSACTION_EXECUTION_COUNT INT64 在讀寫交易中執行查詢的次數。這個欄可協助您判斷是否可以將查詢移至唯讀交易,以免發生鎖定爭用情形。
LATENCY_DISTRIBUTION ARRAY<STRUCT>

查詢執行時間的直方圖。這些值是以秒為單位。

陣列包含單一元素,類型如下:
ARRAY<STRUCT<
  COUNT INT64,
  MEAN FLOAT64,
  SUM_OF_SQUARED_DEVIATION FLOAT64,
  NUM_FINITE_BUCKETS INT64,
  GROWTH_FACTOR FLOAT64,
  SCALE FLOAT64,
  BUCKET_COUNTS ARRAY<INT64>>>

如要進一步瞭解這些值,請參閱「發布」一文。

如要計算分佈的百分位延遲時間,請使用 SPANNER_SYS.DISTRIBUTION_PERCENTILE(distribution, n FLOAT64) 函式,該函式會傳回估計的 n 百分位。如需相關範例,請參閱「找出查詢的第 99 百分位數延遲時間」。

詳情請參閱「百分位數和分佈值指標」。

AVG_MEMORY_PEAK_USAGE_BYTES FLOAT64

在分散式查詢執行期間,平均記憶體尖峰用量 (以位元組為單位)。

您可以使用這項統計資料,找出哪些查詢或資料表資料大小可能會遇到記憶體限制。

AVG_MEMORY_USAGE_PERCENTAGE FLOAT64

在分散式查詢執行期間,所需的平均記憶體用量 (以此查詢允許的記憶體限制百分比表示)。

這項統計資料只會追蹤執行查詢所需的記憶體。部分運算子會使用額外的緩衝記憶體來提升效能。查詢計畫中會顯示使用的額外緩衝記憶體,但不會用於計算 AVG_MEMORY_USAGE_PERCENTAGE,因為緩衝記憶體是用於最佳化,並非必要。

您可以使用這項統計資料,找出即將達到記憶體用量限制,且如果資料大小增加就可能失敗的查詢。為降低查詢失敗的風險,請參閱 SQL 最佳做法,以便將這些查詢最佳化,或將查詢分割成讀取較少資料的部分。

AVG_QUERY_PLAN_CREATION_TIME_SECS FLOAT64

查詢編譯作業的平均 CPU 時間 (以秒為單位),包括建立查詢執行階段的時間。

如果這個欄的值很高,請使用參數化查詢

AVG_FILESYSTEM_DELAY_SECS FLOAT64

查詢從檔案系統讀取資料或遭到輸入/輸出 (I/O) 阻斷的平均時間。

您可以使用這項統計資料,找出檔案系統 I/O 可能造成的高延遲情形。如要緩解這個問題,請新增索引,或在現有索引中新增 STORING (GoogleSQL) 或 INCLUDE (PostgreSQL) 子句

AVG_REMOTE_SERVER_CALLS FLOAT64

查詢完成的遠端伺服器呼叫 (RPC) 平均數量。

您可以使用這項統計資料,找出掃描相同數量資料列的不同查詢,是否有著截然不同的 RPC 數量。對於 RPC 值較高的查詢,您可以新增索引,或是在現有索引中新增 STORING (GoogleSQL) 或 INCLUDE (PostgreSQL) 子句,以便提升查詢效能。

AVG_ROWS_SPOOLED FLOAT64

查詢陳述式寫入暫時磁碟 (非記憶體) 的平均列數。

您可以使用這項統計資料,找出記憶體成本高且無法在記憶體中執行的查詢,這些查詢可能會導致延遲時間過長。如要降低風險,請變更 JOIN 順序,或新增提供必要 SORT索引

AVG_DISK_IO_COST FLOAT64

以 Spanner HDD 磁碟負載而言,這項查詢的平均成本。

您可以使用這個值,比較資料庫中讀取作業的相對 HDD I/O 成本。查詢 HDD 儲存空間中的資料時,系統會根據執行個體的 HDD 磁碟負載容量向您收費。值越高,表示您使用較多 HDD 磁碟負載,且查詢速度可能會比在 SSD 上執行時慢。此外,如果硬碟磁碟負載已達上限,查詢效能可能會進一步受到影響。您可以監控執行個體的總HDD 磁碟負載容量百分比。如要增加 HDD 磁碟負載容量,您可以為執行個體新增更多處理單元或節點。詳情請參閱「變更運算容量」。如要改善查詢效能,請考慮將部分資料移至 SSD。

如果工作負載會大量使用磁碟 I/O,建議您將經常存取的資料儲存在 SSD 儲存空間中。從 SSD 存取的資料不會耗用 HDD 磁碟的負載容量。您可以視需要將特定資料表、資料欄或次要索引儲存在 SSD 儲存空間,同時將不常存取的資料儲存在 HDD 儲存空間。詳情請參閱分層儲存空間總覽

失敗查詢的 EXECUTION_COUNTAVG_LATENCY_SECONDSLATENCY_DISTRIBUTION 包含因語法不正確或發生暫時性錯誤而失敗的查詢,但重試後成功。這些統計資料不會追蹤失敗和取消的分區 DML 陳述式。

匯總統計資料

Spanner 會在特定時間範圍內擷取所有查詢的統計資料,因此也有資料表追蹤所有查詢的匯總資料:

  • SPANNER_SYS.QUERY_STATS_TOTAL_MINUTE:1 分鐘間隔期間內的查詢
  • SPANNER_SYS.QUERY_STATS_TOTAL_10MINUTE:10 分鐘間隔期間內的查詢
  • SPANNER_SYS.QUERY_STATS_TOTAL_HOUR:1 小時間隔期間內的查詢

這些資料表具備下列屬性:

  • 每個資料表都包含資料表名稱所指定的非重疊時間間隔長度的資料。

  • 間隔是基於時鐘時間。1 分鐘間隔的結束時間是目前這一分鐘、10 分鐘間隔的結束時間是目前這個小時的每 10 分鐘,而 1 小時間隔的結束時間是目前這個小時。

    舉例來說,在上午 11:59:30,SQL 查詢的最近可用間隔如下:

    • 1 分鐘:上午 11:58:00–11:58:59
    • 10 分鐘:上午 11:40:00–11:49:59
    • 1 小時:上午 10:00:00–10:59:59
  • 每個資料列都會包含指定間隔期間,資料庫上執行的所有查詢的統計資料的匯總。每個時間間隔只有一列,其中包含已完成的查詢、失敗的查詢,以及使用者取消的查詢。

  • TOTAL 資料表中擷取的統計資料可能包含 Spanner 未在 TOP 資料表中擷取的查詢。

  • 這些資料表中的部分欄會在 Cloud Monitoring 中顯示為指標。公開的指標如下:

    • 查詢執行次數
    • 查詢失敗
    • 查詢延遲時間
    • 傳回的資料列數
    • 掃描的資料列數
    • 傳回的位元組數
    • 查詢 CPU 時間

    詳情請參閱「Spanner 指標」。

資料表結構定義

資料欄名稱 類型 說明
INTERVAL_END TIMESTAMP 包含的查詢執行作業在發生時的時間間隔結束時間。
EXECUTION_COUNT INT64 在時間間隔期間,Spanner 看見該查詢的次數。
AVG_LATENCY_SECONDS FLOAT64 資料庫內每個查詢執行的平均時間長度,以秒為單位。這個平均值會排除結果集和額外負荷的編碼與傳輸時間。
AVG_ROWS FLOAT64 查詢傳回的平均列數。
AVG_BYTES FLOAT64 查詢傳回的平均資料位元組數,不包含傳輸編碼額外負荷。
AVG_ROWS_SCANNED FLOAT64 查詢掃描的平均列數,不包含已刪除的值。
AVG_CPU_SECONDS FLOAT64 Spanner 在執行該查詢所有作業時的平均 CPU 作業時間秒數。
ALL_FAILED_EXECUTION_COUNT INT64 在間隔期間,查詢失敗的次數。
ALL_FAILED_AVG_LATENCY_SECONDS FLOAT64 資料庫內每個查詢執行失敗的平均時間長度,以秒為單位。這個平均值會排除結果集和額外負荷的編碼與傳輸時間。
CANCELLED_OR_DISCONNECTED_EXECUTION_COUNT INT64 在指定期間內,使用者取消查詢或因網路連線中斷而導致查詢失敗的次數。
TIMED_OUT_EXECUTION_COUNT INT64 在時間間隔期間,查詢逾時的次數。
AVG_BYTES_WRITTEN FLOAT64 陳述式寫入的平均位元組數。
AVG_ROWS_WRITTEN FLOAT64 陳述式修改的平均列數。
RUN_IN_RW_TRANSACTION_EXECUTION_COUNT INT64 在讀寫交易中執行查詢的次數。 這一欄有助於判斷是否可以將部分查詢移至唯讀交易,以避免發生鎖定爭用情形。
LATENCY_DISTRIBUTION ARRAY<STRUCT>

各項查詢的執行時間直方圖。這些值以秒為單位。

請按照下列方式指定陣列:
ARRAY<STRUCT<
  COUNT INT64,
  MEAN FLOAT64,
  SUM_OF_SQUARED_DEVIATION FLOAT64,
  NUM_FINITE_BUCKETS INT64,
  GROWTH_FACTOR FLOAT64,
  SCALE FLOAT64,
  BUCKET_COUNTS ARRAY<INT64>>>

如要進一步瞭解這些值,請參閱「分發」一文。

如要計算分佈的百分位延遲時間,請使用 SPANNER_SYS.DISTRIBUTION_PERCENTILE(distribution, n FLOAT64) 函式,該函式會傳回估計的 n 百分位。如需相關範例,請參閱「找出查詢的第 99 百分位數延遲時間」。

詳情請參閱「百分位數和分佈值指標」。

資料保留

Spanner 至少會在下列時間範圍保留每個資料表的資料:

  • SPANNER_SYS.QUERY_STATS_TOP_MINUTESPANNER_SYS.QUERY_STATS_TOTAL_MINUTE:涵蓋前 6 個小時的間隔。

  • SPANNER_SYS.QUERY_STATS_TOP_10MINUTESPANNER_SYS.QUERY_STATS_TOTAL_10MINUTE:涵蓋前 4 天的間隔。

  • SPANNER_SYS.QUERY_STATS_TOP_HOURSPANNER_SYS.QUERY_STATS_TOTAL_HOUR:涵蓋前 30 天的間隔。

查詢範例

本節包含多個擷取查詢統計資料的範例 SQL 陳述式。您可以使用用戶端程式庫Google Cloud CLIGoogle Cloud 控制台來執行這些 SQL 陳述式。

列出特定時間範圍內每個查詢的基本統計資料

下列查詢會傳回前一分鐘中,前幾名查詢的原始資料:

SELECT text,
       request_tag,
       interval_end,
       execution_count,
       avg_latency_seconds,
       avg_rows,
       avg_bytes,
       avg_rows_scanned,
       avg_cpu_seconds
FROM spanner_sys.query_stats_top_minute
ORDER BY interval_end DESC;

列出執行時間超過一小時的分區 DML 陳述式統計資料

下列查詢會傳回執行次數,以及前幾小時內,前幾個分區 DML 查詢所寫入的平均資料列數:

SELECT text,
       request_tag,
       interval_end,
       sum(execution_count) as execution_count
       sum(avg_rows_written*execution_count)/sum(execution_count) as avg_rows_written
FROM spanner_sys.query_stats_top_hour
WHERE starts_with(text, "UPDATE") AND query_type = "PARTITIONED_QUERY"
group by text, request_tag, interval_end
ORDER BY interval_end DESC;

列出 CPU 使用率最高的查詢

下列查詢會傳回前一小時中 CPU 使用率最高的查詢:

SELECT text,
       request_tag,
       execution_count AS count,
       avg_latency_seconds AS latency,
       avg_cpu_seconds AS cpu,
       execution_count * avg_cpu_seconds AS total_cpu
FROM spanner_sys.query_stats_top_hour
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_top_hour)
ORDER BY total_cpu DESC;

找出特定時間範圍內的總執行次數

下列查詢會傳回最近完成的 1 分間隔內所執行的查詢總數:

SELECT interval_end,
       execution_count
FROM spanner_sys.query_stats_total_minute
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_top_minute);

查看查詢的平均延遲時間

下列查詢會傳回特定查詢的平均延遲時間資訊:

SELECT avg_latency_seconds
FROM spanner_sys.query_stats_top_hour
WHERE text LIKE "SELECT x FROM table WHERE x=@foo;";

找出查詢的第 99 個百分位數延遲時間

下列查詢會傳回過去 10 分鐘內執行的查詢,其執行時間的 99 百分位數:

SELECT interval_end, avg_latency_seconds, SPANNER_SYS.DISTRIBUTION_PERCENTILE(latency_distribution[OFFSET(0)], 99.0)
  AS percentile_latency
FROM spanner_sys.query_stats_total_10minute
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_total_10minute)
ORDER BY interval_end;

比較平均延遲時間與第 99 百分位數延遲時間,有助於找出可能的異常查詢,並縮短執行時間。

尋找掃描最多資料的查詢

您可以使用查詢掃描的資料列數,來測量查詢所掃描的資料量。下列查詢會傳回前一小時查詢所掃描的資料列數。

SELECT text,
       execution_count,
       avg_rows_scanned
FROM spanner_sys.query_stats_top_hour
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_top_hour)
ORDER BY avg_rows_scanned DESC;

找出寫入最多資料的陳述式

您可以使用 DML 寫入的資料列數 (或寫入的位元組數),來測量查詢修改的資料量。下列查詢會傳回前一小時執行的 DML 陳述式所寫入的資料列數:

SELECT text,
       execution_count,
       avg_rows_written
FROM spanner_sys.query_stats_top_hour
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_top_hour)
ORDER BY avg_rows_written DESC;

加總所有查詢的 CPU 使用量

下列查詢會傳回前一小時使用的 CPU 時數:

SELECT (avg_cpu_seconds * execution_count / 60 / 60)
  AS total_cpu_hours
FROM spanner_sys.query_stats_total_hour
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_total_hour);

列出特定時間範圍內失敗的查詢

下列查詢會傳回原始資料,包括前一分鐘中,前幾名查詢的執行次數和失敗查詢的平均延遲時間。這些統計資料不會追蹤失敗和已取消的分區 DML 陳述式。

SELECT text,
       request_tag,
       interval_end,
       execution_count,
       all_failed_execution_count,
       all_failed_avg_latency_seconds,
       avg_latency_seconds,
       avg_rows,
       avg_bytes,
       avg_rows_scanned,
       avg_cpu_seconds
FROM spanner_sys.query_stats_top_minute
WHERE all_failed_execution_count > 0
ORDER BY interval_end;

找出特定時間範圍內的總錯誤數

下列查詢會傳回最近完整 1 分鐘間隔內執行失敗的查詢總數。這些統計資料不會追蹤失敗和取消的分區 DML 陳述式。

SELECT interval_end,
       all_failed_execution_count
FROM spanner_sys.query_stats_total_minute
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_top_minute)
ORDER BY interval_end;

列出逾時次數最多的查詢

下列查詢會傳回前一小時中超時次數最高的查詢。

SELECT text,
       execution_count AS count,
       timed_out_execution_count AS timeout_count,
       avg_latency_seconds AS latency,
       avg_cpu_seconds AS cpu,
       execution_count * avg_cpu_seconds AS total_cpu
FROM spanner_sys.query_stats_top_hour
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.query_stats_top_hour)
ORDER BY timed_out_execution_count DESC;

找出特定查詢成功和失敗執行作業的平均延遲時間

下列查詢會傳回特定查詢的平均總延遲時間、成功執行的平均延遲時間,以及執行失敗的平均延遲時間。這些統計資料不會追蹤失敗和取消的分區 DML 陳述式。

SELECT avg_latency_seconds AS combined_avg_latency,
       all_failed_avg_latency_seconds AS failed_execution_latency,
       ( avg_latency_seconds * execution_count -
         all_failed_avg_latency_seconds * all_failed_execution_count
       ) / (
       execution_count - all_failed_execution_count ) AS success_execution_latency
FROM   spanner_sys.query_stats_top_hour
WHERE  text LIKE "select x from table where x=@foo;";

使用查詢統計資料排解 CPU 使用率偏高或查詢延遲時間偏高的問題

當您需要調查 Spanner 資料庫的 CPU 使用率高低,或是想瞭解資料庫中 CPU 使用量高的查詢形狀時,查詢統計資料就很實用。檢查使用大量資料庫資源的查詢,可讓 Spanner 使用者瞭解如何降低營運成本,並改善一般系統延遲時間。

您可以使用 SQL 程式碼或「查詢洞察」資訊主頁,調查資料庫中的問題查詢。以下主題說明如何使用 SQL 程式碼調查這類查詢。

雖然以下範例著重於 CPU 使用率,但您可以按照類似步驟排解查詢延遲問題,並找出延遲時間最長的查詢。只要選取時間間隔,並以延遲時間而非 CPU 用量為依據進行查詢即可。

選取要調查的時間範圍

開始調查時,請找出應用程式開始出現高 CPU 使用率的時間點。舉例來說,如果問題開始發生的時間是 2020 年 7 月 24 日下午 5 點

收集所選時間範圍內的查詢統計資料

選定要開始調查的時間範圍後,我們會查看 QUERY_STATS_TOTAL_10MINUTE 資料表在該時間點附近收集到的統計資料。這項查詢的結果可能會顯示 CPU 和其他查詢統計資料在該時間範圍內的變化情形。

以下查詢會傳回從世界標準時間 16:3017:30 的匯總查詢統計資料。我們在查詢中使用 ROUND,限制小數位數的顯示數量。

SELECT interval_end,
       execution_count AS count,
       ROUND(avg_latency_seconds,2) AS latency,
       ROUND(avg_rows,2) AS rows_returned,
       ROUND(avg_bytes,2) AS bytes,
       ROUND(avg_rows_scanned,2) AS rows_scanned,
       ROUND(avg_cpu_seconds,3) AS avg_cpu
FROM spanner_sys.query_stats_total_10minute
WHERE
  interval_end >= "2020-07-24T16:30:00Z"
  AND interval_end <= "2020-07-24T17:30:00Z"
ORDER BY interval_end;

執行查詢後,會產生下列結果。

interval_end 數量 延遲 rows_returned 位元組 rows_scanned avg_cpu
2020-07-24T16:30:00Z 6 0.06 5.00 536.00 16.67 0.035
2020-07-24T16:40:00Z 55 0.02 0.22 25.29 0.22 0.004
2020-07-24T16:50:00Z 102 0.02 0.30 33.35 0.30 0.004
2020-07-24T17:00:00Z 154 1.06 4.42 486.33 7792208.12 4.633
2020-07-24T17:10:00Z 94 0.02 1.68 106.84 1.68 0.006
2020-07-24T17:20:00Z 110 0.02 0.38 34.60 0.38 0.005
2020-07-24T17:30:00Z 47 0.02 0.23 24.96 0.23 0.004

在前述表格中,我們可以看到平均 CPU 時間 (結果表格中的 avg_cpu 欄) 在結束時間為 17:00 的醒目顯示區間內達到最高。我們也發現平均掃描的資料列數量大幅增加。這表示在 16:50 至 17:00 之間執行了成本較高的查詢。請選擇該間隔,以便在下一個步驟中進一步調查。

找出導致 CPU 使用率偏高的查詢

選取要調查的時間間隔後,我們現在要查詢 QUERY_STATS_TOP_10MINUTE 資料表。這項查詢的結果有助於指出哪些查詢會導致 CPU 使用率偏高。

SELECT text_fingerprint AS fingerprint,
       execution_count AS count,
       ROUND(avg_latency_seconds,2) AS latency,
       ROUND(avg_cpu_seconds,3) AS cpu,
       ROUND(execution_count * avg_cpu_seconds,3) AS total_cpu
FROM spanner_sys.query_stats_top_10MINUTE
WHERE
  interval_end = "2020-07-24T17:00:00Z"
ORDER BY total_cpu DESC;

執行這項查詢後,會傳回下列結果。

指紋 數量 延遲 CPU total_cpu
5505124206529314852 30 3.88 17.635 529.039
1697951036096498470 10 4.49 18.388 183.882
2295109096748351518 1 0.33 0.048 0.048
11618299167612903606 1 0.25 0.021 0.021
10302798842433860499 1 0.04 0.006 0.006
123771704548746223 1 0.04 0.006 0.006
4216063638051261350 1 0.04 0.006 0.006
3654744714919476398 1 0.04 0.006 0.006
2999453161628434990 1 0.04 0.006 0.006
823179738756093706 1 0.02 0.005 0.0056

結果表格中標示的 2 個查詢是平均 CPU 和延遲時間、執行次數和 CPU 總數的異常值。調查這些結果中列出的首個查詢。

比較一段時間內的查詢執行作業

在縮小調查範圍後,我們可以將注意力轉移到 QUERY_STATS_TOP_MINUTE 資料表。透過比較特定查詢在一段時間內的執行情形,我們可以找出傳回的資料列或位元組數量,或掃描的資料列數量,以及 CPU 或延遲時間之間的關聯。偏差可能表示資料不一致。如果掃描的資料列數量持續偏高,可能表示缺少適當的索引,或是彙整順序不佳。

請執行下列以該查詢的 text_fingerprint 為篩選條件的陳述式,調查 CPU 使用率最高和延遲時間最長的查詢。

SELECT interval_end,
       ROUND(avg_latency_seconds,2) AS latency,
       avg_rows AS rows_returned,
       avg_bytes AS bytes_returned,
       avg_rows_scanned AS rows_scanned,
       ROUND(avg_cpu_seconds,3) AS cpu,
FROM spanner_sys.query_stats_top_minute
WHERE text_fingerprint = 5505124206529314852
ORDER BY interval_end DESC;

執行這項查詢會傳回下列結果。

interval_end 延遲 rows_returned bytes_returned rows_scanned CPU
2020-07-24T17:00:00Z 4.55 21 2365 30000000 19.255
2020-07-24T16:00:00Z 3.62 21 2365 30000000 17.255
2020-07-24T15:00:00Z 4.37 21 2365 30000000 18.350
2020-07-24T14:00:00Z 4.02 21 2365 30000000 17.748
2020-07-24T13:00:00Z 3.12 21 2365 30000000 16.380
2020-07-24T12:00:00Z 3.45 21 2365 30000000 15.476
2020-07-24T11:00:00Z 4.94 21 2365 30000000 22.611
2020-07-24T10:00:00Z 6.48 21 2365 30000000 21.265
2020-07-24T09:00:00Z 0.23 21 2365 5 0.040
2020-07-24T08:00:00Z 0.04 21 2365 5 0.021
2020-07-24T07:00:00Z 0.09 21 2365 5 0.030

檢視上述結果,我們發現掃描的資料列數、使用的 CPU 和延遲時間在早上 9 點左右都出現大幅變化。為了瞭解這些數字為何大幅增加,我們將檢查查詢文字,看看結構定義是否有任何變更可能影響查詢。

請使用以下查詢,擷取我們要調查的查詢的查詢文字。

SELECT text,
       text_truncated
FROM spanner_sys.query_stats_top_hour
WHERE text_fingerprint = 5505124206529314852
LIMIT 1;

這會傳回以下結果。

文字 text_truncated
select * from orders where o_custkey = 36901; false

檢查傳回的查詢文字後,我們發現查詢會篩選名為 o_custkey 的欄位。這是 orders 資料表中的非索引鍵欄。實際上,該欄曾經有索引,但在早上 9 點左右遭到刪除,這就是這項查詢費用異動的緣由。我們可以重新加入索引,如果查詢執行頻率不高,則可以決定不使用索引,並接受較高的讀取成本。

我們目前的調查重點是成功完成的查詢,並發現資料庫效能下降的原因之一。在下一個步驟中,我們將著重於失敗或已取消的查詢,並說明如何檢查該資料以取得更多洞察。

調查失敗的查詢

未成功完成的查詢在逾時、取消或以其他方式失敗前,仍會耗用資源。Spanner 會追蹤執行次數,以及失敗查詢和成功查詢所耗用的資源。這些統計資料不會追蹤失敗和已取消的分區 DML 陳述式。

如要檢查失敗的查詢是否對系統使用率有重大影響,我們可以先檢查在指定時間間隔內失敗的查詢數量。

SELECT interval_end,
       all_failed_execution_count AS failed_count,
       all_failed_avg_latency_seconds AS latency
FROM spanner_sys.query_stats_total_minute
WHERE
  interval_end >= "2020-07-24T16:50:00Z"
  AND interval_end <= "2020-07-24T17:00:00Z"
ORDER BY interval_end;
interval_end failed_count 延遲
2020-07-24T16:52:00Z 1 15.211391
2020-07-24T16:53:00Z 3 58.312232

進一步調查後,我們可以使用以下查詢,找出最有可能失敗的查詢。

SELECT interval_end,
       text_fingerprint,
       execution_count,
       avg_latency_seconds AS avg_latency,
       all_failed_execution_count AS failed_count,
       all_failed_avg_latency_seconds AS failed_latency,
       cancelled_or_disconnected_execution_count AS cancel_count,
       timed_out_execution_count AS to_count
FROM spanner_sys.query_stats_top_minute
WHERE all_failed_execution_count > 0
ORDER BY interval_end;
interval_end text_fingerprint execution_count failed_count cancel_count to_count
2020-07-24T16:52:00Z 5505124206529314852 3 1 1 0
2020-07-24T16:53:00Z 1697951036096498470 2 1 1 0
2020-07-24T16:53:00Z 5505124206529314852 5 2 1 1

如上表所示,在不同時間間隔內,使用指紋 5505124206529314852 的查詢多次失敗。有了這類失敗模式,比較成功和失敗執行作業的延遲時間就會很有趣。

SELECT interval_end,
       avg_latency_seconds AS combined_avg_latency,
       all_failed_avg_latency_seconds AS failed_execution_latency,
       ( avg_latency_seconds * execution_count -
         all_failed_avg_latency_seconds * all_failed_execution_count
       ) / (
       execution_count - all_failed_execution_count ) AS success_execution_latency
FROM   spanner_sys.query_stats_top_hour
WHERE  text_fingerprint = 5505124206529314852;
interval_end combined_avg_latency failed_execution_latency success_execution_latency
2020-07-24T17:00:00Z 3.880420 13.830709 2.774832

採用最佳做法

在找出要最佳化的候選查詢後,我們可以查看查詢設定檔,並嘗試使用 SQL 最佳做法進行最佳化。

後續步驟