本頁面討論如何使用預設值運算式,在資料表中產生主鍵值。本頁面的資訊適用於 GoogleSQL 方言資料庫和 PostgreSQL 方言資料庫。這些策略的優點如下:
- 避免熱點
- 簡化從其他資料庫遷移的作業
- 在資料庫中封裝主要邏輯,這樣就不必擔心在應用程式中管理邏輯
- 在大多數情況下,可取代自行建立及管理序列的需求
自動產生主鍵的方法
如要自動產生主鍵值,您可以在含有 DEFAULT 運算式的資料欄中使用下列策略:
- 產生 UUID 第 4 版值的 UUID 函式。
IDENTITY欄,可自動為索引鍵和非索引鍵欄產生整數值。- PostgreSQL 中的
SERIAL和 GoogleSQL 中的AUTO_INCREMENT,都是IDENTITY資料欄的 DDL 別名。 - 結構定義物件
SEQUENCE,其中包含bit_reversed_positive選項。SEQUENCE適用於 GoogleSQL 和 PostgreSQL。
通用唯一識別碼 (UUID)
Spanner 可以自動產生 UUID 第 4 版字串,做為主鍵使用。UUID 適用於新應用程式和含有大量資料列的資料表。這些索引鍵大致上會平均分佈在整個索引鍵空間,避免出現大規模的熱點。UUID 生成功能可建立大量值 (2122),且每個值實際上都是不重複的。舉例來說,如要達到 50% 的碰撞機率,您需要 2.71×1018 個值,或每秒 10 億個值,持續 86 年。這可確保您在大型資料表中使用時,不會出現重複值。無論是在資料庫或用戶端產生 UUID,這些 UUID 都是不重複的。建議您盡可能使用 UUID。如果用戶端產生的 UUID 是依據 RFC 4122 序列化為小寫,您可以在同一個資料表中安全地混合使用用戶端和 Spanner 產生的 UUID。
如果資料欄需要預設值,您可以使用 GENERATE_UUID 函式產生預設值。以下範例說明如何建立資料表,其中 FanId 鍵資料欄在值資料欄中具有 GENERATE_UUID 做為預設值。範例中,GoogleSQL STRING 和 PostgreSQL varchar 屬性使用 36 個字元,因為 UUID 有 36 個字元。使用 INSERT with THEN RETURN 陳述式將資料插入 Fans 資料表時,GENERATE_UUID 會為 FanId 產生並傳回 UUID 值。
GoogleSQL
CREATE TABLE Fans (
FanId STRING(36) DEFAULT (GENERATE_UUID()),
Name STRING(MAX),
) PRIMARY KEY (FanId);
PostgreSQL
CREATE TABLE Fans (
FanId varchar(36) DEFAULT spanner.generate_uuid(),
Name text,
PRIMARY KEY (FanId)
);
GoogleSQL
INSERT INTO Fans (Name) VALUES ('Melissa Garcia')
THEN RETURN FanId;
PostgreSQL
INSERT INTO fans (name) VALUES ('Melissa Garcia')
RETURNING (fanid);
這項陳述式會傳回類似下列內容的結果:
| FanId |
|---|
| 6af91072-f009-4c15-8c42-ebe38ae83751 |
如要進一步瞭解 GENERATE_UUID() 函式,請參閱 GoogleSQL 或 PostgreSQL 參考資料頁面。
IDENTITY 個資料欄
使用 IDENTITY 欄,即可自動為索引鍵和非索引鍵欄產生整數值。IDENTITY 欄不需要使用者手動維護基礎序列,也不需要管理欄與基礎序列之間的關係。如果捨棄自動產生的身分欄,系統也會自動刪除基礎序列。
您可以在產生序列時提供起始整數值,或讓 Spanner 為您產生整數序列,藉此使用 IDENTITY 欄。如要提供起始整數值,請使用 START COUNTER WITH 選項,並使用正數 INT64 起始值。Spanner 會使用這個值,為自動產生的內部序列計數器設定下一個值,並在將值插入這個資料欄之前,先反轉位元。
在 Spanner 中,GoogleSQL 和 PostgreSQL 都支援 IDENTITY 資料欄。
GoogleSQL
以下範例說明如何使用 IDENTITY 資料欄,在透過 CREATE TABLE 指令建立新資料表時,為 SingerId 建立自動產生的整數主鍵資料欄:
CREATE TABLE Singers (
SingerId INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE),
Name STRING(MAX),
Rank INT64
) PRIMARY KEY (SingerId);
您也可以使用 START_WITH_COUNTER 選項,指定資料欄的計數器起點。在下列範例中,系統會為 SingerId 建立自動產生的整數資料欄,其中包含位元反轉的正值,以及從 1,000 開始的內部計數器。
CREATE TABLE Singers (
SingerId INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE START COUNTER WITH 1000),
Name STRING(MAX),
Rank INT64
) PRIMARY KEY (SingerId);
PostgreSQL
以下範例說明如何使用 IDENTITY 資料欄,在透過 CREATE
TABLE 指令建立新資料表時,為 SingerId 建立自動產生的整數資料欄:
CREATE TABLE Singers (
SingerId bigint GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE),
Name text,
PRIMARY KEY (SingerId)
);
您也可以使用 START COUNTER WITH 選項,指定資料欄的計數器起點。在下列範例中,系統會為 SingerId 建立自動產生的整數資料欄,產生位元反轉的正值,且位元反轉前的內部計數器會從 1,000 開始。
CREATE TABLE Singers (
SingerId bigint GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE START COUNTER WITH 1000),
Name text,
PRIMARY KEY (SingerId)
);
SERIAL 和 AUTO_INCREMENT
Spanner 支援 PostgreSQL 中的 SERIAL 和 GoogleSQL 中的 AUTO_INCREMENT,這些都是 IDENTITY 資料欄的 DDL 別名,用於建立不重複的整數資料欄。使用 SERIAL 或 AUTO_INCREMENT 前,請先設定資料庫 default_sequence_kind 選項。
您可以使用下列 SQL 陳述式設定資料庫 default_squence_kind 選項:
GoogleSQL
ALTER DATABASE db SET OPTIONS (default_sequence_kind = 'bit_reversed_positive');
CREATE TABLE Singers (
id INT64 AUTO_INCREMENT PRIMARY KEY,
name STRING(MAX),
)
PostgreSQL
ALTER DATABASE db SET spanner.default_sequence_kind = 'bit_reversed_positive';
CREATE TABLE Singers (
id serial PRIMARY KEY,
name text
);
請注意,由於 SERIAL 和 AUTO_INCREMENT 會對應至 IDENTITY 資料欄,因此序列化結構定義時,您不會看到這些資料欄。對於這個結構定義,GetDatabaseDDL 的輸出內容會是:
GoogleSQL
ALTER DATABASE db SET OPTIONS (default_sequence_kind = 'bit_reversed_positive');
CREATE TABLE Singers (
id INT64 GENERATED BY DEFAULT AS IDENTITY,
name STRING(MAX),
) PRIMARY KEY (id);
PostgreSQL
ALTER DATABASE db SET spanner.default_sequence_kind = 'bit_reversed_positive';
CREATE TABLE Singers (
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
name character varying,
PRIMARY KEY(id)
);
位元反轉序列
位元反轉序列是產生整數序列並反轉位元的結構定義物件。這個物件會對私有內部 Spanner 計數器執行位元反轉,確保唯一性。產生的位元反轉值用於主鍵時,有助於避免大規模的熱點。
在 Spanner 中,您可以使用 SEQUENCE DDL 陳述式和 bit_reversed_positive 屬性,建立、變更或刪除產生位元反轉正值的序列 (GoogleSQL 或 PostgreSQL)。
每個序列都會維護一組內部計數器,並使用這些計數器產生值。序列計數器會提供位元反轉演算法的輸入內容。
使用以 GoogleSQL GET-NEXT-SEQUENCE-VALUE 或 PostgreSQL nextval 函式做為預設值的 DEFAULT 運算式定義資料欄時,Spanner 會自動呼叫函式,並將位元反轉的輸出值放入資料欄。位元反轉序列特別適合用於主鍵,因為位元反轉值會平均分布在鍵空間中,因此不會造成熱點。
以下範例說明如何建立位元反轉序列和資料表,其中索引鍵資料欄會將序列做為預設值:
GoogleSQL
CREATE SEQUENCE SingerIdSequence OPTIONS (
sequence_kind="bit_reversed_positive"
);
CREATE TABLE Singers (
SingerId INT64 DEFAULT (GET_NEXT_SEQUENCE_VALUE(SEQUENCE SingerIdSequence)),
Name STRING(MAX),
Rank INT64,
) PRIMARY KEY (SingerId);
PostgreSQL
CREATE SEQUENCE SingerIdSequence bit_reversed_positive;
CREATE TABLE Singers (
SingerId bigint DEFAULT nextval('SingerIdSequence'),
Name text,
PRIMARY KEY (SingerId)
);
然後,您可以使用下列 SQL 陳述式插入並傳回主鍵值:
GoogleSQL
INSERT INTO Singers (Name) VALUES ('Melissa Garcia')
THEN RETURN SingerId;
PostgreSQL
INSERT INTO Singers (name) VALUES ('Melissa Garcia')
RETURNING (SingerId);
這項陳述式會傳回類似下列內容的結果:
| SingerId |
|---|
| 3458764513820540928 |
將 UUID 和序列當做主鍵預設值的使用情境
UUID 和序列的適用情境包括:
- 新應用程式
- 遷移
以下各節說明各個情境。
新應用程式
如果現有應用程式需要 GoogleSQL 中的 INT64 鍵,或 PostgreSQL 中的 bigint 鍵,Spanner 提供位元反轉正序結構定義物件 (PostgreSQL 或
GoogleSQL)。否則,對於新應用程式,我們建議您使用通用唯一識別碼 (UUID)。
詳情請參閱「使用通用唯一識別碼 (UUID)」。
遷移
如要將資料表遷移至 Spanner,有幾種做法可供選擇:
- 如果您在來源資料庫中使用 UUID,則可以在 Spanner 中使用
STRING類型的鍵值資料欄和GENERATE_UUID()函式 (GoogleSQL 或 PostgreSQL) 做為預設值。 - 如果您使用整數主鍵,且應用程式只需要主鍵是唯一的,則可以在
INT64中使用主鍵資料欄,並使用位元反轉的正序做為主鍵的預設值。請參閱「遷移位元反轉鍵資料欄」。 Spanner 不支援產生單調值的方法。
如果您使用單調遞增鍵 (例如 PostgreSQL
SERIAL型別或 MySQLAUTO_INCREMENT屬性),且需要在 Spanner 上使用新的單調遞增鍵,則可使用複合鍵。詳情請參閱「交換鍵的順序」和「雜湊唯一鍵並將寫入資料分散到邏輯資料分割」。如果應用程式會手動反轉 GoogleSQL 中的
INT64鍵或 PostgreSQL 中的bigint鍵,您可以使用反轉位元的正序 (GoogleSQL 或 PostgreSQL),讓系統為您產生新的鍵值。詳情請參閱「遷移位元反轉鍵欄」。
後續步驟
- 進一步瞭解如何搭配精細存取權控管機制使用序列。
- 瞭解 GoogleSQL 或 PostgreSQL 的 DDL
SEQUENCE陳述式。 - 瞭解 GoogleSQL 或 PostgreSQL 中的序列函式。
- 瞭解 GoogleSQL 或 PostgreSQL 中 INFORMATION_SCHEMA 的序列。
- 瞭解 GoogleSQL 的 INFORMATION_SCHEMA 序號選項。