本文說明如何偵測及偵錯資料庫中的熱點。您可以使用 GoogleSQL 和 PostgreSQL,存取分割區中熱點的統計資料。
Spanner 會將資料儲存為連續鍵空間,並依資料表和索引的主鍵排序。分割是資料表或索引集中的資料列範圍。分割的起點稱為「分割起點」。分割限制會設定分割的結束時間。分割作業會包含分割起始值,但不包含分割限制。
在 Spanner 中,資源使用率不均是指傳送至同一個伺服器的要求過多,導致伺服器資源飽和,延遲時間可能過長。受資源使用率不均影響的分割稱為「熱門」或「溫和」分割。
分割熱點統計資料 (系統中識別為 CPU_USAGE_SCORE) 是指受伺服器可用資源限制的分割負載測量結果。這項指標會以百分比表示。如果分割的負載有超過 50% 受到可用資源限制,則該分割會視為暖分割。如果分割的負載有 100% 受到限制,則該分割會被視為熱門分割。這類熱分割也可能影響其處理要求的延遲時間。
分割區的 CPU_USAGE_SCORE 可以保持不變,也可以根據存取分割區的工作負載和分割區邊界變化而隨時間變動。
根據暖分割和熱分割的資源限制,Spanner 可能會使用依負載進行分割,在鍵空間中平均分配負載。暖分割和熱分割可跨執行個體伺服器移動,以達到負載平衡。Spanner 會在背景執行依負載分割作業,盡量減少對延遲的影響。不過,由於應用程式中存在反面模式,即使多次嘗試分割,Spanner 可能也無法平衡負載。統計資料檢視畫面中的「UNSPLITTABLE_REASONS」欄會提供具體原因,說明為何無法進一步分割熱門或熱門程度中等的分割區。因此,如果持續出現暖或熱分割,且時間至少達 10 分鐘,可能需要進一步疑難排解,並進行潛在的應用程式變更,尤其是出現 UNSPLITTABLE_REASONS 時。
Spanner 熱分割統計資料可協助您找出發生資源使用率不均情況的分割,並瞭解這種情況可能持續的原因。這些統計資料搭配 UNSPLITTABLE_REASONS 程式碼,有助於診斷需要採取哪些行動來解決熱點問題。然後視需要變更應用程式或結構定義。
如何查看熱門分割統計資料
Spanner 會在 SPANNER_SYS結構定義中提供熱門分割統計資料。SPANNER_SYS 資料可透過 GoogleSQL 和 PostgreSQL 介面存取。您可以透過下列方式存取這項資料:
- 資料庫的 Spanner Studio 頁面 (位於 Google Cloud 控制台中)。
gcloud spanner databases execute-sql指令。executeSql或executeStreamingSql方法。
Spanner 提供的下列單一讀取方法不支援 SPANNER_SYS:
- 從資料表中的單一資料列或多個資料列執行強式讀取。
- 從資料表中的單一資料列或多個資料列執行過時讀取。
- 從次要索引中的單一資料列或多個資料列讀取。
熱門分割統計資料
您可以使用下列檢視畫面追蹤熱門分割:
SPANNER_SYS.SPLIT_STATS_TOP_MINUTE:顯示 1 分鐘間隔內熱門的分割畫面。SPANNER_SYS.SPLIT_STATS_TOP_10MINUTE:顯示 10 分鐘間隔內任何時間點的熱門片段。SPANNER_SYS.SPLIT_STATS_TOP_HOUR:顯示 1 小時間隔內任何時間點的熱門分段。
這些檢視畫面具有下列屬性:
- 每個檢視畫面都包含檢視畫面名稱所指定的非重疊時間間隔長度的資料。
- 間隔是基於時鐘時間:
- 1 分鐘間隔的結束時間是目前這一分鐘。
- 10 分鐘間隔的結束時間是目前這個小時的第 10 分鐘,例如 11:10:00、11:20:00。
- 1 小時間隔的結束時間是目前這個小時。
- 每隔一段時間,Spanner 就會從所有伺服器收集資料,然後在不久後透過
SPANNER_SYS檢視畫面提供資料。舉例來說,在上午 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 會依分割區將統計資料分組。
- 每個資料列都包含統計資料,包括
CPU_USAGE_SCORE百分比 (指出分割區的熱度或暖度),以及 Spanner 在指定間隔期間擷取統計資料的每個分割區。 SPANNER_SYS.SPLIT_STATS_TOP_MINUTE檢視畫面會提供每分鐘的詳細分段統計資料。使用這個檢視畫面,詳細偵錯近期事件。SPANNER_SYS.SPLIT_STATS_TOP_10MINUTE和SPANNER_SYS.SPLIT_STATS_TOP_HOUR檢視畫面分別提供 10 分鐘和 1 小時間隔的匯總檢視畫面。您可以使用這些檢視畫面進行趨勢分析,或調查過去幾天或幾週的問題。如要進一步瞭解匯總,請參閱「查看事件匯總」。- 如果 Spanner 無法儲存間隔期間的所有熱門資料分組,系統會優先處理在指定間隔期間
CPU_USAGE_SCORE百分比最高的資料分組。如果沒有傳回任何分割畫面,表示沒有任何熱門分割畫面。
資料保留
Spanner 在任何時間點為每個檢視區塊保留的資料量上限如下:
SPANNER_SYS.SPLIT_STATS_TOP_MINUTE:涵蓋前 24 小時的間隔。SPANNER_SYS.SPLIT_STATS_TOP_10MINUTE:涵蓋前 4 天的間隔。SPANNER_SYS.SPLIT_STATS_TOP_HOUR:涵蓋前 30 天的間隔。
這些保留期限無法延長或縮短,且您無法禁止 Spanner 收集熱分割統計資料。
- 如要刪除統計資料,您必須刪除正在追蹤的資料庫,或等待統計資料超出保留期限。
- 如要長期保留統計資料,請定期將資料從熱分割統計資料檢視區複製出來。
查看結構定義
下表顯示熱分割統計資料的結構定義:
| 資料欄名稱 | 類型 | 說明 |
|---|---|---|
INTERVAL_END |
TIMESTAMP |
分割處於暖或熱狀態的時間間隔結束時間。 |
SPLIT_START |
STRING |
分割內資料列範圍的起始鍵。分割起始位置也有可能是 <begin>,代表鍵空間的開頭。 |
SPLIT_LIMIT |
STRING |
分割內資料列範圍的極限鍵。極限鍵也有可能是 <end>,代表鍵空間的結尾。 |
CPU_USAGE_SCORE |
INT64 |
CPU_USAGE_SCORE百分比。如果百分比為 50%,表示有熱門或非常熱門的歌曲。CPU_USAGE_SCORE |
AFFECTED_TABLES |
STRING ARRAY |
所含資料列可能儲存於分割的資料表。 |
UNSPLITTABLE_REASONS |
STRING ARRAY |
識別無法透過以負載為準的分割方式緩解的熱點類型,通常是因為反模式所致。如果出現任何原因,表示可能需要使用者介入,例如調整結構定義或工作負載。空陣列表示系統在這段間隔期間未偵測到任何無法分割的條件,或是高負載時間過短,Spanner 無法判斷是否無法分割。詳情請參閱UNSPLITTABLE_REASONS類型。 |
分割起始和分割限制鍵
分割是資料庫的連續資料列範圍,由「開始」和「限制」鍵定義。分割可以是單一資料列、窄資料列範圍或寬資料列範圍,且分割可包含多個資料表或索引。
SPLIT_START 和 SPLIT_LIMIT 欄會識別暖分割或熱分割的主鍵。
結構定義範例
以下結構定義是本頁主題的範例表格。
GoogleSQL
CREATE TABLE Users (
UserId INT64 NOT NULL,
FirstName STRING(MAX),
LastName STRING(MAX),
) PRIMARY KEY(UserId);
CREATE INDEX UsersByFirstName ON Users(FirstName DESC);
CREATE TABLE Threads (
UserId INT64 NOT NULL,
ThreadId INT64 NOT NULL,
Starred BOOL,
) PRIMARY KEY(UserId, ThreadId),
INTERLEAVE IN PARENT Users ON DELETE CASCADE;
CREATE TABLE Messages (
UserId INT64 NOT NULL,
ThreadId INT64 NOT NULL,
MessageId INT64 NOT NULL,
Subject STRING(MAX),
Body STRING(MAX),
) PRIMARY KEY(UserId, ThreadId, MessageId),
INTERLEAVE IN PARENT Threads ON DELETE CASCADE;
CREATE INDEX MessagesIdx ON Messages(UserId, ThreadId, Subject),
INTERLEAVE IN Threads;
PostgreSQL
CREATE TABLE users
(
userid BIGINT NOT NULL PRIMARY KEY,-- INT64 to BIGINT
firstname VARCHAR(max),-- STRING(MAX) to VARCHAR(MAX)
lastname VARCHAR(max)
);
CREATE INDEX usersbyfirstname
ON users(firstname DESC);
CREATE TABLE threads
(
userid BIGINT NOT NULL,
threadid BIGINT NOT NULL,
starred BOOLEAN, -- BOOL to BOOLEAN
PRIMARY KEY (userid, threadid),
CONSTRAINT fk_threads_user FOREIGN KEY (userid) REFERENCES users(userid) ON
DELETE CASCADE -- Interleave to Foreign Key constraint
);
CREATE TABLE messages
(
userid BIGINT NOT NULL,
threadid BIGINT NOT NULL,
messageid BIGINT NOT NULL PRIMARY KEY,
subject VARCHAR(max),
body VARCHAR(max),
CONSTRAINT fk_messages_thread FOREIGN KEY (userid, threadid) REFERENCES
threads(userid, threadid) ON DELETE CASCADE
-- Interleave to Foreign Key constraint
);
CREATE INDEX messagesidx ON messages(userid, threadid, subject), REFERENCES
threads(userid, threadid);
假設您的鍵空間如下所示:
| 主鍵 |
|---|
<begin> |
Users() |
Threads() |
Users(2) |
Users(3) |
Threads(3) |
Threads(3,"a") |
Messages(3,"a",1) |
Messages(3,"a",2) |
Threads(3, "aa") |
Users(9) |
Users(10) |
Threads(10) |
UsersByFirstName("abc") |
UsersByFirstName("abcd") |
<end> |
拆分範例
以下顯示一些分割範例,協助您瞭解分割畫面。
SPLIT_START 和 SPLIT_LIMIT 可能代表資料表或索引的資料列,也可能是 <begin> 和 <end>,代表資料庫鍵空間的界限。SPLIT_START 和 SPLIT_LIMIT 也可能包含截斷的鍵,也就是資料表中任何完整鍵的前置鍵。舉例來說,Threads(10) 是插入 Users(10) 的任何 Threads 列的前置字元。
| SPLIT_START | SPLIT_LIMIT | AFFECTED_TABLES | 說明 |
|---|---|---|---|
Users(3) |
Users(10) |
UsersByFirstName、Users、Threads、Messages、MessagesIdx |
分割作業會從包含 UserId=3 的資料列開始,並在包含 UserId = 10 的資料列前結束。分割包含 Users 資料表列,以及 UserId=3 到 10 的所有交錯資料表列。 |
Messages(3,"a",1) |
Threads(3,"aa") |
Threads、Messages、MessagesIdx |
分割作業會從含有 UserId=3、ThreadId="a" 和 MessageId=1 的資料列開始,並在含有 UserId=3 和 ThreadsId = "aa" 鍵的資料列前結束。分割包含 Messages(3,"a",1) 和 Threads(3,"aa") 之間的所有資料表。由於 split_start 和 split_limit 交錯於同一個頂層資料表資料列,因此分割會包含起始值和限制之間的交錯資料表資料列。請參閱「schemas-overview」,瞭解交錯式資料表的共置方式。 |
Messages(3,"a",1) |
<end> |
UsersByFirstName、Users、Threads、Messages、MessagesIdx |
分割作業會從訊息資料表中,鍵為 UserId=3、ThreadId="a" 和 MessageId=1 的資料列開始。分割會包含 split_start 到 <end> 的所有資料列,也就是資料庫鍵空間的結尾。split_start 後方所有資料表 (例如 Users(4)) 的資料列都會納入分割作業。 |
<begin> |
Users(9) |
UsersByFirstName、Users、Threads、Messages、MessagesIdx |
分割作業會從 <begin> 開始,也就是資料庫鍵空間的開頭,並在 UserId=9 Users 資料列的前一個資料列結束。因此,分割作業會包含 Users 前的所有資料表列,以及 Users 資料表 UserId=9 前的所有資料列,還有交錯式資料表的資料列。 |
Messages(3,"a",1) |
Threads(10) |
UsersByFirstName、Users、Threads、Messages、MessagesIdx |
分割作業從 Users(3) 中交錯的 Messages(3,"a", 1) 開始,並在 Threads(10) 前方的資料列結束。Threads(10) 是截斷的分割索引鍵,也是 Users(10) 中交錯的 Threads 資料表任何索引鍵的前置字串。 |
Users() |
<end> |
UsersByFirstName、Users、Threads、Messages、MessagesIdx |
分割作業會從 Users() 的截斷分割鍵開始,該鍵位於 Users 資料表的任何完整鍵之前。分割作業會持續進行,直到資料庫中可能的鍵空間結束為止。因此,affected_tables 涵蓋 Users 資料表、交錯資料表和索引,以及使用者之後可能出現的所有資料表。 |
Threads(10) |
UsersByFirstName("abc") |
UsersByFirstName、Users、Threads、Messages、MessagesIdx |
分割作業會從 Threads 列的 UserId = 10 開始,並在索引 UsersByFirstName 結束,也就是 "abc" 前的鍵。 |
UNSPLITTABLE_REASONS 類型
如果 Spanner 無法透過依負載分割來減輕熱點問題,SPLIT_STATS_TOP_* 檢視畫面中的「UNSPLITTABLE_REASONS」欄會列出下列一或多個原因:
HOT_ROW
說明:高負載集中在單一資料列。Spanner 無法在個別資料列中新增分割點。
常見原因:
- 對單一鍵執行大量作業 (讀取、寫入或更新)。
- 集中存取單一資料列的結構定義設計。
緩解策略:
- 減少熱分割的 QPS。
- 重新設計結構定義來分配負載。例如,跨多個資料列的分片計數器。
- 查看結構定義設計最佳做法。
MOVING_HOT_SPOT
說明:隨著時間推移,高負載的鍵範圍會發生變化,通常是循序變化。由於熱點會在 Spanner 分割先前受影響的範圍前重新定位,因此以負載為準的分割方式無效。
常見原因:
- 插入的開頭索引鍵部分單調遞增或遞減,例如提交時間戳記。
- 在資料表的鍵空間中依序讀取點。
緩解策略:
- 在寫入密集型工作負載中,請避免使用單調遞增或遞減的索引鍵做為主鍵的第一部分。如需詳細的緩解策略,請參閱「結構定義設計最佳做法」。方法包括使用 UUID 或在索引鍵前加上雜湊。
LARGE_SCAN_HOT_SPOT
說明:由於頻繁或耗用大量資源的作業會掃描整個鍵值範圍,導致分割區負載過高。包括範圍讀取 (包括交易期間發出的讀取) 或查詢。Spanner 不會過度分割這類作業涵蓋的範圍,以免這些掃描作業的效能可能降低,因為如果資料在許多小分割區中過度分散,就可能發生這種情況。
常見原因:
- 查詢或讀取作業對經常存取的資料執行大範圍掃描。
- 需要掃描範圍的 WHERE 子句 DML 陳述式 (
UPDATE、DELETE)。 - 缺少合適的索引,導致掃描基本資料表。
緩解策略:
- 最佳化 SQL 陳述式 (
SELECT、UPDATE、DELETE),減少掃描的資料列數。 - 建立適當的索引來支援常見的查詢和 DML 述詞,盡量減少掃描的資料列數。
UNISOLATABLE_HOT_ROW
說明:Spanner 發現高負載的狹窄鍵,但由於沒有合適的分割點,因此無法插入新的分割點來隔離該鍵。這個案例與 HOT_ROW 類似,但 SPLIT_START
和 SPLIT_LIMIT 不會完全隔離熱點。
常見原因:
- 單一資料列或共用索引鍵前置字串的相鄰資料列,出現大量區域負載。
緩解策略:
- 分析所回報
SPLIT_START和SPLIT_LIMIT內金鑰的應用程式存取模式。 - 緩解策略通常與
HOT_ROW重疊,重點在於減少問題狹窄鍵範圍的直接作業負載。
UNSPECIFIED
說明:分割區負載過高,無法分割,但原因不屬於其他特定類別。這可能發生在複雜的負載情境中,或是因為內部系統行為。
緩解策略:
- 調查存取熱門分割區內資料表 (列於
AFFECTED_TABLES) 的應用程式工作負載、查詢或交易,這些項目顯示負載增加。 - 使用查詢洞察和交易洞察等工具,找出耗費資源的作業。
- 評估工作負載,並確保您採用結構定義設計最佳做法和 SQL 最佳做法。
- 如果經過上述最佳化作業後,熱點問題仍持續超過 10 分鐘,請建立支援案件。
查看事件匯總
SPANNER_SYS.SPLIT_STATS_TOP_10MINUTE 和 SPANNER_SYS.SPLIT_STATS_TOP_HOUR 檢視畫面中的項目代表各自時間範圍內 1 分鐘間隔的匯總資料:
CPU_USAGE_SCORE:顯示 10 分鐘或 1 小時時間範圍內,任何 1 分鐘間隔中記錄到的最高CPU_USAGE_SCORE。
UNSPLITTABLE_REASONS:這個陣列是所有不重複的聯集,
UNSPLITTABLE_REASONS這些不重複的項目是在視窗內所有 1 分鐘間隔中,
針對分割畫面觀察到的項目。
如果至少有一個 1 分鐘間隔的CPU_USAGE_SCORE達到 50% 以上,這些檢視畫面就會顯示分割畫面。
匯總範例
檢查從 Users(101) 到 Users(102) 的分割。下表顯示 10:00:00 到 10:10:00 這段 10 分鐘期間,MINUTE 檢視畫面中可能出現的項目:
INTERVAL_END |
SPLIT_START |
SPLIT_LIMIT |
CPU_USAGE_SCORE |
AFFECTED_TABLES |
UNSPLITTABLE_REASONS |
|---|---|---|---|---|---|
| 10:01:00 | 使用者(101) | 使用者(102) | 60 | [Messages,Users,Threads] | [] |
| 10:02:00 | 使用者(101) | 使用者(102) | 95 | [Messages,Users,Threads] | [HOT_ROW] |
| 10:03:00 | 使用者(101) | 使用者(102) | 80 | [Messages,Users,Threads] | [HOT_ROW] |
| 10:04:00 | 使用者(101) | 使用者(102) | 55 | [Users,Threads] | [] |
| 10:06:00 | 使用者(101) | 使用者(102) | 70 | [Users,Threads] | [LARGE_SCAN_HOT_SPOT] |
| 10:07:00 | 使用者(101) | 使用者(102) | 65 | [Users,Threads] | [LARGE_SCAN_HOT_SPOT] |
| 10:09:00 | 使用者(101) | 使用者(102) | 52 | [Users,Threads] | [] |
這個分割區在 10:10:00 結束的間隔中,對應的匯總項目會是:10MINUTE
INTERVAL_END |
SPLIT_START |
SPLIT_LIMIT |
CPU_USAGE_SCORE |
AFFECTED_TABLES |
UNSPLITTABLE_REASONS |
|---|---|---|---|---|---|
| 10:10:00 | 使用者(101) | 使用者(102) | 95 | [Messages,Users,Threads] | [HOT_ROW, LARGE_SCAN_HOT_SPOT] |
CPU_USAGE_SCORE:95 是這個時間範圍內,1 分鐘檢視畫面中CPU_USAGE_SCORE資料欄的最大值。UNSPLITTABLE_REASONS:[HOT_ROW, LARGE_SCAN_HOT_SPOT]是 1 分鐘檢視畫面中UNSPLITTABLE_REASONS資料欄內所有不重複原因的聯集。
這個範例顯示 10MINUTE 檢視畫面如何彙整最密集的負載,以及這段期間內遇到的所有無法分割問題。HOUR 檢視畫面會遵循相同的匯總邏輯,時間範圍為 60 分鐘。
尋找熱門藝人
您可以使用下列 SQL 陳述式擷取熱分割統計資料。您可以使用用戶端程式庫、Google Cloud CLI 或Google Cloud 控制台執行這些 SQL 陳述式。
SELECT
t.interval_end,
t.split_start,
t.split_limit,
t.cpu_usage_score,
t.affected_tables,
t.unsplittable_reasons
FROM
SPANNER_SYS.SPLIT_STATS_TOP_DURATION AS t
WHERE
-- Optional: Filter by a specific interval end time
-- t.interval_end = 'INTERVAL_END_TIME'
ORDER BY
t.interval_end DESC, t.cpu_usage_score DESC;
更改下列內容:
DURATION:根據觀察期選擇MINUTE、10MINUTE或HOUR。例如:SPANNER_SYS.SPLIT_STATS_TOP_HOUR。INTERVAL_END_TIME:請替換為觀察期結束時間的TIMESTAMP。例如:2072-06-08 08:30:00Z。
解讀查詢結果
如需完整的 UNSPLITTABLE_REASONS 代碼清單和可能的診斷結果,請參閱「UNSPLITTABLE_REASONS 類型」。舉例來說,查詢輸出內容可能如下所示:
SPLIT_START |
SPLIT_LIMIT |
CPU_USAGE_SCORE |
AFFECTED_TABLES |
UNSPLITTABLE_REASONS |
|---|---|---|---|---|
| 執行緒(10) | Threads(10, "aa") | 100 | 訊息、討論串 | [UNISOLATABLE_HOT_ROW] |
| Messages(631, "abc", 1) | Messages(631, "abc", 3) | 100 | 訊息 | [HOT_ROW] |
| 使用者(620) | <end> | 100 | 訊息、使用者、討論串 | [MOVING_HOT_SPOT] |
| 使用者(101) | 使用者(102) | 90 | 訊息、使用者、討論串 | [HOT_ROW] |
| 使用者(13) | 使用者(76) | 82 | 訊息、使用者、討論串 | [LARGE_SCAN_HOT_SPOT] |
| Threads(12, "zebra") | 使用者(14) | 76 | 訊息、使用者、討論串 | [] |
從這些結果,您可以推斷出下列問題:
- Threads(10) to Threads(10, "aa"): Hot at 100% with
[UNISOLATABLE_HOT_ROW]. 單一鍵、Threads資料表中的鍵範圍前置字串或交錯式資料表是熱點,且 Spanner 無法進一步分割範圍。 - Messages(631, "abc", 1) 至 Messages(631, "abc", 3):熱門程度 100%,並有
[HOT_ROW]。這個使用者和執行緒的負載集中在 MessageId 1 和 2。 - 使用者(620) 至
<end>:熱門程度 100%,且有[MOVING_HOT_SPOT]。這通常表示插入模式的 User ID 會單調增加或減少,導致鍵空間結尾持續處於熱點狀態。 - 使用者(101) 至使用者(102):熱門程度為 90%,並有
[HOT_ROW]。負載集中在單一 Users 資料列 UserId = 101 及其交錯的子項。 - 使用者(13) 至使用者(76):熱門程度為 82%,
[LARGE_SCAN_HOT_SPOT]。這表示您經常或以高昂的代價掃描這個範圍內的使用者 ID。 - Threads(12, "zebra") to Users(14):使用率為 76%,屬於溫暖。系統未在這個時間間隔內偵測到任何無法分割的原因。如果負載持續或增加,Spanner 可能仍會分割這個資料庫。
使用熱門分割統計資料排解熱點問題
本節說明如何偵測及排解熱點問題。
選取要調查的時間範圍
檢查 Spanner 資料庫的延遲指標,找出應用程式發生高延遲和 CPU 使用率偏高的時間範圍。舉例來說,系統可能會顯示問題發生時間為 2072 年 5 月 18 日晚上 10:50 左右。
檢查無法分割的原因
Spanner 會透過依負載進行分割來平衡負載,因此建議您調查持續超過 10 分鐘的熱點,尤其是具有 UNSPLITTABLE_REASONS 的熱點。如果出現 UNSPLITTABLE_REASONS,表示 Spanner 無法分割熱分割,可能需要變更結構定義或工作負載,才能減輕熱點問題。
您可以查詢 UNSPLITTABLE_REASONS,如以下範例查詢所示:
SELECT
reason,
COUNT(*) AS occurrences
FROM
SPANNER_SYS.SPLIT_STATS_TOP_MINUTE AS t,
UNNEST(t.unsplittable_reasons) AS reason
WHERE
t.cpu_usage_score >= 50
AND ARRAY_LENGTH(t.unsplittable_reasons) > 0
AND t.interval_end >= "2072-05-18T17:40:00Z" -- Start of window
AND t.interval_end <= "2072-05-18T17:50:00Z" -- End of window
GROUP BY
reason
ORDER BY
occurrences DESC;
如果出現 UNSPLITTABLE_REASONS,表示需要進一步偵錯。
您也可以使用 Cloud Monitoring 監控無法分割的原因。請使用 unsplittable_reason_count 指標。詳情請參閱「Spanner 指標」。
找出 CPU_USAGE_SCORE 最高的分組及其 UNSPLITTABLE_REASONS
在本範例中,我們執行下列 SQL,找出 CPU_USAGE_SCORE 層級最高的資料列範圍,以及對應的 UNSPLITTABLE_REASONS:
GoogleSQL
SELECT t.split_start,
t.split_limit,
t.cpu_usage_score,
t.affected_tables,
t.unsplittable_reasons
FROM SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE t.cpu_usage_score >= 50
AND t.interval_end = "interval_end_date_time";
請將 interval_end_date_time 換成間隔的日期和時間,格式為 YYYY-MM-DDTHH:MM:SSZ。例如:2072-05-18T17:40:00Z。
PostgreSQL
SELECT t.split_start,
t.split_limit,
t.cpu_usage_score,
t.affected_tables,
t.unsplittable_reasons
FROM spanner_sys.split_stats_top_minute t
WHERE t.cpu_usage_score >= 50
AND t.interval_end = 'interval_end_date_time'::timestamptz;
請將 interval_end_date_time 換成間隔的日期和時間,格式為 YYYY-MM-DDTHH:MM:SSZ。例如:2072-05-18T17:40:00Z。
先前的 SQL 會輸出下列內容:
SPLIT_START |
SPLIT_LIMIT |
CPU_USAGE_SCORE |
AFFECTED_TABLES |
UNSPLITTABLE_REASONS |
|---|---|---|---|---|
Users(180) |
<end> |
85 |
Messages,Users,Threads |
[MOVING_HOT_SPOT] |
Users(24) |
Users(76) |
76 |
Messages,Users,Threads |
[HOT_ROW, LARGE_SCAN_HOT_SPOT] |
Threads(10) |
UsersByFirstName("abc") |
100 |
UsersByFirstName, Users, Threads, Messages, MessagesIdx |
[] |
從這份結果表格中,我們可以看到有三個熱分割,其中兩個無法分割。如果熱點持續存在一段時間,就值得進一步調查。UNSPLITTABLE_REASONS如要瞭解各項原因的意義和解決方法,請參閱UNSPLITTABLE_REASONS類型。
緩解熱點的最佳做法
注意:如果負載增加,且您最近擴充了執行個體,Spanner 可能需要幾分鐘執行負載平衡作業,延遲時間才會縮短。
如果負載平衡無法減少延遲,下一步是找出熱點的原因。之後,您可以選擇減少熱點工作負載,或是最佳化應用程式結構和邏輯,避免出現熱點。
找出原因
- 使用鎖定和交易深入分析,找出鎖定等待時間較長的交易,其中資料列範圍的起始鍵位於熱門分割區內。
- 使用查詢洞察找出從含有熱門分割的資料表讀取資料,且近期延遲時間增加,或延遲時間與 CPU 比率較高的查詢。
- 使用「最耗時的有效查詢」,找出從含有熱門分割的資料表讀取資料,且延遲時間高於預期的查詢。
請注意以下特殊情況:
- 檢查存留時間 (TTL)
是否最近啟用。如果舊資料有大量分割,TTL 可能會在大量刪除期間提高
CPU_USAGE_SCORE層級。在這種情況下,初始刪除作業完成後,問題應會自動解決。
最佳化工作負載
後續步驟
- 瞭解結構定義設計最佳做法。
- 瞭解 Key Visualizer。
- 查看結構定義設計範例。
- 瞭解如何使用分割洞察資訊主頁偵測熱點。