您现在的位置: 365建站网 > 365文章 > SQLIDENTITY 与 AUTO_INCREMENT 有何不同?ALWAYS、BY DEFAULT 与序列校准

SQLIDENTITY 与 AUTO_INCREMENT 有何不同?ALWAYS、BY DEFAULT 与序列校准

文章来源:365jz.com 点击数:10 更新时间:2024-08-09 09:15

自增主键有三种写法:老式 SERIAL、MySQL 的 AUTO_INCREMENT,以及标准的 IDENTITY 列。它们行为相近但约束强度不同,尤其在"能不能手工插入指定 id"这一点上差别很大,直接决定数据迁移会不会踩主键冲突。本文依据 PostgreSQL 官方恒等列文档原文整理。

SQLIDENTITY

一、官方定义:它背后是一个隐式序列

PostgreSQL 恒等列文档(实测 200)的第一句原文是:"An identity column is a special column that is generated automatically from an implicit sequence. It can be used to generate key values." 语法形式为 GENERATED ... AS IDENTITY,官方给出两种变体:GENERATED ALWAYS AS IDENTITY 与 GENERATED BY DEFAULT AS IDENTITY。

同一页还明确指出:"in many ways, an identity column behaves like a column with a default value" —— 它在很多方面表现得像带默认值的列,但语义上是"这张表的键由序列生成",属于约束而非默认值。另外官方限制条件值得记住:"The data type of an identity column must be one of the data types supported by sequences",序列属性可在建列时指定。

二、ALWAYS 与 BY DEFAULT 的真实差别

这是选型的分水岭。官方原文说明:BY DEFAULT 的结果是"a behavior more similar to default values, where the default value can be overridden by an explicit value",即显式给值时以显式值为准;而 ALWAYS 禁止显式插入值,直接写 id 会报错。

取舍建议:应用层永远不该关心主键数值、又希望杜绝人为指定时,用 ALWAYS(严格,防止业务代码塞 id);需要兼容旧写法或迁移时要插原值,用 BY DEFAULT。迁移场景最常见的就是 ALWAYS 卡住导入。

三、DEFAULT 关键字与 OVERRIDING 子句

官方说明可以在值的位置显式写 DEFAULT 来"request the sequence-generated value",这在列很多、又不想重排列顺序时很实用。插入时若列是 ALWAYS 而你必须塞入原值,标准出路是 OVERRIDING SYSTEM VALUE;反过来想强制忽略用户提供的值、仍用序列生成,则用 OVERRIDING USER VALUE。这两个子句的存在本身就说明 ALWAYS 是"约束"而不是"提示"。

四、与其他数据库的对应关系

  • MySQL:只有 AUTO_INCREMENT,没有 ALWAYS/BY DEFAULT 之分,且允许显式插值(插一个大值后序列会从该值继续)。一个列只能是主键的一部分,且一张表通常只设一个。
  • SQL Server:IDENTITY(种子,增量),一个表只允许一列,需手工插值时先 SET IDENTITY_INSERT 表名 ON——这与标准 SQL 的 OVERRIDING 思路完全不同。
  • Oracle 12c 及以上:支持标准 GENERATED [ALWAYS|BY DEFAULT] AS IDENTITY,还提供 DEFAULT ON NULL,语义与 PG 最接近。

写跨库 DDL 时不要假定 IDENTITY 关键字通用;SQL Server 的 IDENTITY 是列属性写法,不能照搬 GENERATED ... AS IDENTITY。

五、最容易出事的点:序列落后于数据

用 BY DEFAULT 或 OVERRIDING 手工插入过 id 之后,隐式序列并不知道,下一次自增可能撞上已存在的主键,报 duplicate key。这是导入历史数据后的典型故障。处理办法是把序列推进到当前最大值之后(PG 可用 setval 配合 max(id),MySQL 则通过 AUTO_INCREMENT = n 调整表选项)。迁移脚本必须包含这一步,否则第一次线上插入就会失败。

六、常见问题 FAQ

问:SERIAL 和 IDENTITY 选哪个?
答:新库用 IDENTITY。SERIAL 只是建序列加默认值的语法糖,序列与列没有归属关系,删列会留孤儿序列。

问:ALWAYS 能改成 BY DEFAULT 吗?
答:可以,用 ALTER TABLE ... ALTER COLUMN ... SET GENERATED BY DEFAULT,无需重建表。

问:自增列能做外键吗?
答:可以,但生成值只保证唯一不保证连续,回滚会跳号,别用 id 推算记录数量。

七、总结

关于 SQLIDENTITY 的结论是:它由隐式序列自动生成键值、数据类型必须是序列支持类型;ALWAYS 禁止显式插值、BY DEFAULT 允许覆盖,需要塞原值时用 OVERRIDING SYSTEM VALUE;MySQL 的 AUTO_INCREMENT 与 SQL Server 的 IDENTITY(种子,增量) 语义与语法都不同,不可照搬;手工插值后必须推进序列,否则主键冲突。新项目优先用标准 IDENTITY 而非 SERIAL,迁移脚本务必带上序列校准这一步。

生产内容,同时打通搜索引擎(SEO)与AI搜索引擎(GEO)流量入口的软件! 点击进入365建站器 »