本頁面討論如何使用預設值運算式,在資料表中產生主鍵值的策略。本頁面的資訊適用於 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。
如要為需要預設值的資料欄產生預設值,可以使用 GoogleSQL 函式 NEW_UUID 或 PostgreSQL 函式 gen_random_uuid()。以下範例說明如何建立資料表,其中 FanId 鍵值資料欄在值資料欄中會以產生的 UUID 做為預設值。
GoogleSQL
CREATE TABLE Fans (
FanId UUID DEFAULT (NEW_UUID()),
Name STRING(MAX),
) PRIMARY KEY (FanId);
PostgreSQL
CREATE TABLE Fans (
FanId uuid DEFAULT gen_random_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 |
如要進一步瞭解產生的 UUID 函式,請參閱 GoogleSQL 或 PostgreSQL 參考頁面。
IDENTITY 個資料欄
使用 IDENTITY 欄,即可自動為索引鍵和非索引鍵欄產生整數值。IDENTITY 欄不需要使用者手動維護基礎序列,也不需要管理欄與基礎序列之間的關係。如果捨棄自動產生的身分欄,系統也會自動刪除基礎序列。
如要使用 IDENTITY 資料欄,您可以在產生序列時提供起始整數值,也可以讓 Spanner 為您產生整數序列。如要提供起始整數值,請使用 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 別名,用於建立不重複的整數資料欄。您必須先設定資料庫 default_sequence_kind 選項,才能使用 SERIAL 或 AUTO_INCREMENT。您可以使用下列 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 和序列的適用情境包括:
- 新應用程式
- 遷移
以下各節說明各個情境。
新應用程式
如果是新版應用程式,Spanner 建議使用通用唯一識別碼 (UUID) 做為主鍵。詳情請參閱「使用通用唯一識別碼 (UUID)」。
如果現有應用程式需要 GoogleSQL 中的 INT64 鍵,或 PostgreSQL 中的 bigint 鍵,Spanner 提供位元反轉正序結構定義物件 (PostgreSQL 或 GoogleSQL)。
遷移
如要將資料表遷移至 Spanner,您可以選擇下列方式:
- 如果您在來源資料庫中使用 UUID,則可以在 Spanner 上使用 UUID 型別資料欄和產生的 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 序號選項。