SQL Server 重置Identity标识列的值(INT爆了)(转载)

一、背景

  SQL Server数据库中表A中Id字段的定义是:[Id] [int] IDENTITY(1,1),随着数据的不断增长,Id值已经接近2147483647(int的取值范围为:-2 147 483 648 到 2 147 483 647)了,虽然已经对旧数据进行归档,但是这个表需要保留最近的1亿数据,有什么方法解决Id值就快爆的问题呢?

  解决上面的问题有两个办法:一个是修改表结构,把Id的int数据类型修改为bigint;第二个是重置Id(Identity标识列)的值,使它重新增长。

  当前标识值:current identity value,用于记录和保存最后一次系统分配的Id值;下次分配Id就是:当前标识值+标识增量(通常为+1,也可以自行设置);

  当前列值:current column value,这Id值到目前为止的最大值;

二、重置过程

(一) 下面就测试重置Identity标识列,首先使用下面的SQL创建测试表:

--创建测试表
CREATE TABLE [dbo].[Test_Identity](
    [IdentityId] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nchar](10) NULL,
 CONSTRAINT [PK_testid] PRIMARY KEY CLUSTERED
(
    [IdentityId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

(二) 显示插入Id值,插入后表[Test_Identity]的记录如Figure1所示,接着再隐式插入Id值,插入后表[Test_Identity]的记录如Figure2所示。

--显示插入Id值
SET IDENTITY_INSERT [Test_Identity] ON
INSERT INTO [Test_Identity](IdentityId,Name)
SELECT 1000,‘name1‘
SET IDENTITY_INSERT [Test_Identity] OFF

--隐式插入Id值
INSERT INTO [Test_Identity](Name)
SELECT ‘name2‘

(Figure1:数据记录)

(Figure2:数据记录)

(三) DBCC CHECKIDENT(‘table_name‘, NORESEED)不重置当前标识值。DBCC CHECKIDENT 返回一个报表,它指明当前标识值和应有的标识值。执行下面的SQL语句,返回的信息表示:当前标识值‘1001‘,当前列值‘1001‘,如 Figure2所示。

--查询标识值
DBCC CHECKIDENT(‘Test_Identity‘, NORESEED)
/*
检查标识信息: 当前标识值‘1001‘,当前列值‘1001‘。
DBCC 执行完毕。如果DBCC 输出了错误信息,请与系统管理员联系。
*/

(四) 再隐式插入Id值,插入后表[Test_Identity]的记录如Figure3所示。所以执行上面的SQL语句是不会重置当前标识值的,可以放心执行。

--隐式插入Id值
INSERT INTO [Test_Identity](Name)
SELECT ‘name3‘

(Figure3:数据记录)

--查询标识值
DBCC CHECKIDENT(‘Test_Identity‘, NORESEED)
/*
检查标识信息: 当前标识值‘1002‘,当前列值‘1002‘。
DBCC 执行完毕。如果DBCC 输出了错误信息,请与系统管理员联系。
*/

(五) DBCC CHECKIDENT (‘table_name‘) 或DBCC CHECKIDENT (‘table_name‘, RESEED) 如果表的当前标识值小于列中存储的最大标识值,则使用标识列中的最大值对其进行重置。

因为上面返回结果是:当前标识值‘1002‘,当前列值‘1002‘,所以执行下面的SQL语句是没有影响的,什么时候才有影响呢?参考:(当在Figure4状态下执行下面的SQL命令,结果就会如Figure7所示

--重置标识值
DBCC CHECKIDENT(‘Test_Identity‘, RESEED)
/*
检查标识信息: 当前标识值‘1002‘,当前列值‘1002‘。
DBCC 执行完毕。如果DBCC 输出了错误信息,请与系统管理员联系。
*/

(六) DBCC CHECKIDENT(‘table_name‘, RESEED, new_reseed_value)当前值设置为 new_reseed_value。如果自创建表后没有将行插入该表,则在执行 DBCC CHECKIDENT 后插入的第一行将使用 new_reseed_value 作为标识。否则,下一个插入的行将使用 new_reseed_value + 1。如果 new_reseed_value 的值小于标识列中的最大值,以后引用该表时将产生 2627 号错误信息。

要理解上面的描述,可以进行下面的测试:

1) 重新设置当前值设置为new_reseed_value = 995,执行下面的SQL语句返回的信息如下所示;

--重置标识值
DBCC CHECKIDENT(‘Test_Identity‘, RESEED, 995)
/*
检查标识信息: 当前标识值‘1002‘,当前列值‘995‘。
DBCC 执行完毕。如果DBCC 输出了错误信息,请与系统管理员联系。
*/

2) 继续往[Test_Identity]表插入数据,执行下面的SQL语句插入后的结果如Figure4所示;插入的Id值为new_reseed_value + 1 = 996;

--隐式插入Id值
INSERT INTO [Test_Identity](Name)
SELECT ‘name4‘

(Figure4:数据记录)

3) 查看现在的标识值,与上面的进行对比,你就可以理解【当前标识值】与【当前列值】的意义了;

--查询标识值
DBCC CHECKIDENT(‘Test_Identity‘, NORESEED)
/*
检查标识信息: 当前标识值‘996‘,当前列值‘1002‘。
DBCC 执行完毕。如果DBCC 输出了错误信息,请与系统管理员联系。
*/

4) 继续往[Test_Identity]表插入数据,执行3次后表的数据如Figure5所示;

--隐式插入Id值
INSERT INTO [Test_Identity](Name)
SELECT ‘name5‘

(Figure5:数据记录)

5) 如果现在继续往[Test_Identity]表插入数据会发生什么事情呢?将产生 2627 号错误信息,如下面的错误信息;

消息2627,级别14,状态1,第2 行

违反了PRIMARY KEY 约束‘PK_testid‘。不能在对象‘dbo.Test_Identity‘ 中插入重复键。

语句已终止。

6) 下面来测试创建表后没有插入行,如果这个时候执行重置标识值会发生什么事情?清空[Test_Identity]表,再重新设置标识值,返回的信息如下面所示;

--清空表
truncate table [Test_Identity]
--重置标识值
DBCC CHECKIDENT(‘Test_Identity‘, RESEED, 995)
/*
检查标识信息: 当前标识值‘NULL‘,当前列值‘995‘。
DBCC 执行完毕。如果DBCC 输出了错误信息,请与系统管理员联系。
*/

7) 这个时候往[Test_Identity]表插入数据,数据就如Figure6所示,这说明了:“如果自创建表后没有将行插入该表,则在执行 DBCC CHECKIDENT 后插入的第一行将使用 new_reseed_value 作为标识。

--隐式插入Id值
INSERT INTO [Test_Identity](Name)
SELECT ‘name5‘

(Figure6:数据记录)

(Figure7:数据记录)

8) 假如我们删除了IdentityId为1000和1001的记录,这个时候继续插入数据,会重新生成1000和10001值吗?效果如Figure10所示(重新覆盖了);

--删除和
delete from [Test_Identity] where IdentityId=1000
delete from [Test_Identity] where IdentityId=1001

(Figure8:数据记录)

--重置标识值
DBCC CHECKIDENT(‘Test_Identity‘, RESEED, 996)
--隐式插入Id值
INSERT INTO [Test_Identity](Name)
SELECT ‘name6‘

(Figure9:数据记录)

(Figure10:数据记录)

(七) 总结:到这里,我们已经可以解决Id值就快爆的问题了,因为我们旧的数据会定时归档,所以不会出现2627错误信息;而另外一个场景是当出现 Figure5的时候,可以执行DBCC CHECKIDENT(‘Test_Identity‘, RESEED),设置为当前列最大值为标识值,防止出现2627错误信息。

三、补充说明

在MySQL中,也有类似Identity的功能:

`IDs` int(11) unsigned NOT NULL AUTO_INCREMENT

在创建表的时候,会有一个选项AUTO_INCREMENT=17422061,直接可以设置起始值,还可以设置步长:

SHOW VARIABLES LIKE ‘auto_inc%‘;

起始值:auto_increment_offset

步长:auto_increment_increment

SET @auto_increment_increment=10;

SELECT LAST_INSERT_ID();

四、参考文献

重置MSSQL的Identity标识列的值

DBCC CHECKIDENT (Transact-SQL)

SQLServer中的@@IDENTITY,SCOPE_IDENTITY和IDENT_CURRENT

SCOPE_IDENTITY (Transact-SQL)

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------

1、newid长度长,像4楼说的,每个页面存放的数量就会少,查询时要访问的数据页就多,通俗点说,就是I/O会更高。性能不见得好。
2、3楼说的newid无序,不适合做聚集索引,是正确的。
3、对于数据库底层操作而言。由于数值型变成16进制时是明确的。而字符型或者其他类型到了底层会存在一些不可预知性。这样需要额外的信息来确定数据。所
以一般建议使用数值型来做主键及索引,补充一下,最快的运算操作是2进制,其实也就是SQLServer的bit类型。但是由于索引需要考虑选择性,所以
不建议使用bit类型来做索引。选择性不高。
4、newid号称3000年内不会重复,但是几乎没有项目需要这么旧。int类型足够存放2亿数据。对于大部分项目来说绰绰有余。
5、你的文章仅仅突出不重复,而不是高效。
6、由于newid的不确定性,在匹配时,比如表关联,会有一定的内耗。
综上所述,不建议在非常特殊的情况下使用newid来做主键或者索引

时间: 2024-07-29 02:18:10

SQL Server 重置Identity标识列的值(INT爆了)(转载)的相关文章

Sql Server中的标识列(自增长字段)

一.标识列的定义以及特点 SQL Server中的标识列又称标识符列,习惯上又叫自增列.该种列具有以下三种特点: 1.列的数据类型为不带小数的数值类型2.在进行插入(Insert)操作时,该列的值是由系统按一定规律生成,不允许空值3.列值不重复,具有标识表中每一行的作用,每个表只能有一个标识列. 由于以上特点,使得标识列在数据库的设计中得到广泛的使用. 二.标识列的组成创建一个标识列,通常要指定三个内容:1.类型(type)在SQL Server 2000中,标识列类型必须是数值类型,如下:de

SQL Server中的标识列

一.标识列的定义以及特点 SQL Server中的标识列又称标识符列,习惯上又叫自增列. 该种列具有以下三种特点: 1.列的数据类型为不带小数的数值类型 2.在进行插入(Insert)操作时,该列的值是由系统按一定规律生成,不允许空值 3.列值不重复,具有标识表中每一行的作用,每个表只能有一个标识列. 由于以上特点,使得标识列在数据库的设计中得到广泛的使用. 二.标识列的组成 创建一个标识列,通常要指定三个内容: 1.类型(type) 在SQL Server 2000中,标识列类型必须是数值类型

SQL Server 2012 自动增长列,值跳跃问题

介绍 从 SQL Server 2012 版本开始, 当SQL Server 实例重启之后,表格的自动增长列的值会发生跳跃,而具体的跳跃值的大小是根据增长列的数据类型而定的.如果数据类型是 整型(int),那么跳跃值为 1000:如果数据类型为 长整型(bigint),那么跳跃值为 10000.从我们的项目来看,这种跳跃问题是不能被接受的,尤其是展示在客户端的时候.这个奇怪的问题只在 SQL Server 2012 及更高的版本中存在,SQL Server 2012之前版本不存在此问题. 背景

SQL SERVER 自增长标识列(Auto Increment Identity)的标识种子复位

DBCC CHECKIDENT('TableName', RESEED, 0) http://stackoverflow.com/questions/16971/how-do-i-reset-an-increment-identitys-starting-value-in-sql-server

SQL Server 将某一列的值拼接成字符串

名称 海鲜水产 水果蔬菜 海参 肉禽蛋 牛排 腊味 生鲜食品 将以上一列变成: 生鲜食品,海鲜水产,水果蔬菜,海参,牛排,肉禽蛋,腊味 sql select CAST(列 as varchar)+',' from 表 as gt where gt.Code=1 for xml path('')

sql Server 使某一列的值等于行号

declare @i INT set @i=0 update 表名 SET [列名][email protected],@[email protected]+1 WHERE 条件

Identity标识列

SQL Server中,经常会用到Identity标识列,这种自增长的字段操作起来的确是比较方便.但它有时还会带来一些麻烦. 示例一 :当表中被删除了某些数据的时候,自增长列的编号就不再是一个连线的数列.这种时候我们可以用以下方案来解决. SET IDENTITY_INSERT [TABLE] [ON|OFF] http://www.cnblogs.com/roucheng/p/GUID.html 允许将显式值插入表的标识列中,当设置为ON时,这时可能在INSERT操作时手工指定插入到标识列中的

SQL Server 动态行转列(参数化表名、分组列、行转列字段、字段

一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 实现代码(SQL Codes) 方法一:使用拼接SQL,静态列字段: 方法二:使用拼接SQL,动态列字段: 方法三:使用PIVOT关系运算符,静态列字段: 方法四:使用PIVOT关系运算符,动态列字段: 扩展阅读一:参数化表名.分组列.行转列字段.字段值: 扩展阅读二:在前面的基础上加入条件过滤: 参考文献(References) 二.背景(Contexts) 其实行转列并不是一个什么新鲜的

解读SQL Server 2014可更新列存储索引——存储机制

概述 SQL Server 2014被号称是微软数据库的一个革命性版本,其性能的提升的幅度是有史以来之最. 可更新的列存储索引作为SQL Server 2014的一个关键功能之一,在提升数据库的查询性能方面贡献非常突出.据微软统计,在面向OLAP查询统计类系统中,相比其他SQL传统版本的数据库,报表查询的性能最大可提升上十倍. 下面我们从存储的角度来了解下SQL Server 2014的可更新列存储索引. 什么是列存储 微软为了提升SQL Server的查询性能,更好的支持大数据分析,早在SQL