编程SQL工程师 / 数据架构师

如何在SQL中自动生成唯一键时生成和处理序列(SEQUENCE/IDENTITY)是如何工作的,有什么根本性的区别?可能会遇到什么潜在问题?

用 Hintsage AI 助手通过面试

答案

SEQUENCE(例如,在PostgreSQL和Oracle中)是数据库中特殊的对象,存储当前值,允许获取唯一数字以进行插入(通常是键)。 IDENTITY是字段的属性,在插入时自动分配下一个顺序值(SQL Server、MySQL、PostgreSQL中的表自动增量)。

主要区别:

  • SEQUENCE — 是一个表外的对象,可以从不同地方访问,允许在不插入的情况下获取下一个值(nextval / currval)。可以用于多个表,可能有多个SEQUENCE对应一个表。
  • IDENTITY — 是列定义的一部分,仅在插入行时自动增加。

示例:

-- PostgreSQL SEQUENCE CREATE SEQUENCE order_seq; INSERT INTO orders(id, name) VALUES (nextval('order_seq'), '第一订单'); -- PostgreSQL IDENTITY CREATE TABLE users ( id BIGSERIAL PRIMARY KEY, username TEXT ); INSERT INTO users(username) VALUES ('ivan'); -- id将自动分配

问题和细节:

  • 如果手动插入id,可能会出现“空洞”或重复。
  • 在删除行时,值不会被重新使用,可能会导致键范围的断裂。
  • 在某些数据库(如MySQL)中,事务回滚时,autoincrement可能会“跳过”,留下未更改的值。
  • SEQUENCE可以在多个表中使用,但这使得维护唯一性变得更加复杂。

设问

如果同时有两个请求从同一个SEQUENCE请求nextval(),会发生什么?可能会得到非唯一的值吗?

答案: 不会,SEQUENCE保证唯一性。即使在同时访问的情况下,每个请求也会获得唯一值。然而,由于并发,顺序可能与插入顺序不符。

示例:

-- 第一个线程获得nextval=100,第二个线程片刻后获得nextval=101。 -- 即使之后第一个线程回滚,值100已被使用。

事件#1

从MySQL迁移到PostgreSQL后,忘记了SEQUENCE和IDENTITY的区别:试图手动插入id,导致自动生成时出现“重复键”错误。最终修正,完全将键的管理转移到SEQUENCE上。


事件#2

在部分删除了带有autoincrement的表中的行后,需要“紧密”填充id范围。由于控制不当重新创建新行,导致了歧义——键与业务逻辑不一致,不得不转向单独的SEQUENCE进行控制。


事件#3

在大型OLTP系统中,由于缺乏对SEQUENCE的控制,订单号超过2,147,483,647,导致集成API发生故障,因为它未准备好处理bigint值。请求被重新实现,以控制SEQUENCE的上限值。