本页面讨论了使用默认值表达式在表中生成主键值的策略。本页面中的信息适用于 GoogleSQL 方言数据库和 PostgreSQL 方言数据库。这些策略具有以下优势:
- 防止出现热点
- 简化从其他数据库的迁移
- 将关键逻辑封装在数据库中,以便您不必担心在应用中对该逻辑的管理
- 在大多数情况下,无需自行创建和管理序列
自动生成主键的方法
如需自动生成主键值,您可以在包含 DEFAULT
表达式的列中使用以下策略:
- 生成 UUID 版本 4 值的 UUID 函数。
- 具有
bit_reversed_positive
选项的架构对象SEQUENCE
。SEQUENCE
同时适用于 GoogleSQL 和 PostgreSQL。
自动生成主键的方法
本部分介绍了如何自动生成 UUID 和位反转序列,以用作主键值。
通用唯一标识符 (UUID)
Spanner 可以自动生成一个 UUID 版本 4 字符串以用作主键。UUID 非常适合新应用和包含许多行的表。它们大致均匀地分布在整个键空间中,这可防止大规模热点。UUID 生成可以创建大量值 (2122),并且每个值实际上具有唯一性。例如,对于 50% 的碰撞概率,您需要 2.71×1018 个值,或者每秒生成 10 亿个值,持续 86 年。这样可确保在大型表中使用时获得唯一值。无论是在数据库中还是在客户端中生成 UUID,它们都是唯一的。我们建议您尽可能使用 UUID。如果客户端生成的 UUID 按照 RFC 4122 序列化为小写,则可以在同一表中安全地混合使用客户端生成的 UUID 和 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
以下示例展示了如何在使用 CREATE TABLE
命令创建新表时,使用 IDENTITY
列为 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
以下示例展示了如何在使用 CREATE
TABLE
命令创建新表时,使用 IDENTITY
列为 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 和序列的场景包括:
- 新应用
- 迁移
以下部分将分别介绍每种场景。
新应用
如果您的现有应用需要 GoogleSQL 中的 INT64
键或 PostgreSQL 中的 bigint
键,Spanner 提供了位反转正值序列架构对象(PostgreSQL 或 GoogleSQL)。否则,对于新应用,我们建议您使用通用唯一标识符 (UUID)。如需了解详情,请参阅使用通用唯一标识符 (UUID)。
迁移
对于将表迁移到 Spanner,您有以下几种选择:
- 如果您在源数据库中使用 UUID,则在 Spanner 上,您可以使用
STRING
类型的键列并将GENERATE_UUID()
函数(GoogleSQL 或 PostgreSQL)作为其默认值。 - 如果您使用的是整数主键,并且您的应用只需要键是唯一的,那么您可以在
INT64
中使用键列,并使用位反转正值序列作为主键的默认值。请参阅迁移位反转键列。 Spanner 不支持生成单调值。
如果您使用的是单调键(例如 PostgreSQL
SERIAL
类型或 MySQLAUTO_INCREMENT
属性),并且需要在 Spanner 上使用新的单调键,则可以使用复合键。如需了解详情,请参阅交换键的顺序和对唯一键进行哈希处理并将写入分布到逻辑分片中。如果您的应用手动对
INT64
键(GoogleSQL 中)或bigint
键(PostgreSQL 中)进行位反转,您可以使用位反转正值序列(GoogleSQL 或 PostgreSQL),让它为您生成新的键值。如需了解详情,请参阅迁移位反转键列。
后续步骤
- 详细了解如何将序列与精细访问权限控制搭配使用。
- 了解 GoogleSQL 或 PostgreSQL 的 DDL
SEQUENCE
语句。 - 了解 GoogleSQL 或 PostgreSQL 中的序列函数。
- 了解 GoogleSQL 或 PostgreSQL 的 INFORMATION_SCHEMA 中的序列。
- 了解 GoogleSQL 的 INFORMATION_SCHEMA 中的序列选项。