PC崩溃后SQL Server主键ID异常跳增的问题及处理方案咨询
问题分析与解决方案
一、ID跳变到1004的根源
这是SQL Server IDENTITY(自增列)的默认缓存机制导致的:
- SQL Server为提升性能,会预分配一批自增值(默认缓存大小为1000)存储在内存中,每次插入时直接从缓存取号。
- 断电时,内存中未使用的缓存值会丢失,重启后数据库会从上次缓存的起始值 + 缓存大小开始分配新ID。比如你之前的最后一条ID是4,缓存预分配了1-1004的范围,断电后未使用的5-1003丢失,下次就从1004开始,这就是两次断电都跳到1004的原因。
- SSMS运行与此无关,它只是客户端工具,不会干预数据库引擎的自增缓存逻辑。
二、保障主键ID完整性的方案
这里的「完整性」需要分两种场景讨论:
1. 场景:业务要求ID连续无跳号(如发票号、单据号)
如果必须保证ID连续,可通过以下方式禁用缓存:
- 数据库级关闭IDENTITY缓存:
该设置会让所有表的IDENTITY列每次生成新ID时都写入系统表,断电后不会丢失未使用的ID,但会牺牲一定性能(每次插入都要磁盘IO)。ALTER DATABASE [你的数据库名] SET IDENTITY_CACHE OFF; - 使用无缓存的序列(SEQUENCE):
替代IDENTITY,创建序列时指定NO CACHE:
插入数据时调用序列取号:CREATE SEQUENCE dbo.TableIdSequence AS INT START WITH 1 INCREMENT BY 1 NO CACHE;
序列的INSERT INTO 你的表 (Id, ...) VALUES (NEXT VALUE FOR dbo.TableIdSequence, ...);NO CACHE会让每次取值都持久化到磁盘,避免跳号,同样存在性能损耗。
2. 场景:仅需ID唯一(大多数业务场景)
如果业务只要求主键唯一,不需要连续,完全不需要修改现有方案:
- IDENTITY的跳号是正常设计,不会导致数据冲突,也不影响数据完整性。客户环境中即使出现断电跳号,只会让ID不连续,但每个ID仍然唯一,对业务逻辑无影响。
- 这种情况下,IDENTITY是最优选择,性能远高于GUID或无缓存序列。
三、关于GUID的取舍
GUID适合分布式系统(多实例数据库需要全局唯一ID),但单实例数据库中没必要用:
- 如果必须使用GUID,用
NEWSEQUENTIALID()替代NEWID():CREATE TABLE 你的表 ( Id UNIQUEIDENTIFIER DEFAULT NEWSEQUENTIALID() PRIMARY KEY, ... );NEWSEQUENTIALID()生成的是顺序GUID,能大幅减少索引碎片,性能比随机GUID好很多,但仍不如INT/BIGINT的IDENTITY高效(GUID占用16字节,INT仅4字节,索引维护成本更高)。
四、最佳处理方式
- 先确认业务需求:如果不是必须要求ID连续,保留IDENTITY即可,跳号不影响数据。
- 如果必须连续,优先选择数据库级关闭IDENTITY缓存(比序列更贴合原有IDENTITY使用习惯),同时评估性能影响。
- 除非是分布式场景,否则不推荐使用GUID作为主键,避免不必要的性能损耗。
内容的提问来源于stack exchange,提问作者GoodWorld113
相关产品推荐
相关产品推荐

