【问题标题】:Identity column not generating correct IDs [duplicate]身份列未生成正确的 ID [重复]
【发布时间】:2014-02-01 19:45:29
【问题描述】:

我有一张桌子:

CREATE TABLE [dorkOrder] ( 
    [doId] int identity(1,1)  NOT NULL,
    [shId] int NOT NULL,
    [mopId] int NOT NULL,
    [dorkOrderNo] varchar(20) NULL,
    [doDate] date NULL
);

现在,当我将数据插入其中而不是以这种方式生成 doId 1,2,3,4,5,6,7 时,它会以以下奇怪的方式生成它:

1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
2002
2003
2004
2005
2006
2007
2008
2013

请帮我解决这个问题。

【问题讨论】:

  • 除了这个是重复的之外,使用IDENTITY 列的大部分价值是您不必(也不应该)担心它生成的值。你为什么?
  • @Yuck 你认为这是正确的做法吗?重新播种表格 1 并输入 1000 条记录后,下一个再次变为 1002 会发生什么?或许?我的问题是这些是我输入的第一条记录,所以为什么它不是从 1 开始。
  • @AaronBertrand 很好的发现和有趣的阅读。这无疑是罪魁祸首。随着人们进入 2012 年,可能会有更多这样的事情......
  • @Aaron Bertrand 现在回答了这个问题。

标签: sql sql-server sql-server-2012


【解决方案1】:

这是known issue in SQL Server 2012。但即使没有该错误(可能有一天会修复,但可能不会),您应该期望您的 IDENTITY 列可能有间隙。发生这种情况的原因有很多,包括删除和回滚。

如果您想实现一个没有间隙的顺序列,那么请停止使用 IDENTITY,围绕插入新行构建强大的可序列化流程,并拒绝对地球上的所有人删除/截断该表。

否则,既然微软已经表示他们有absolutely no intention of offering a "gapless sequential" feature,请学会忍受差距。

【讨论】:

  • 解释了这个问题,但我认为 ouwld 只是让 identity 无用,因为有了这个跳远,你很快就会达到最大 int 栏。
  • @Maven 你会达到 20 亿,因为你偶尔跳过 1000?我对此表示怀疑。无论如何,如果是这种情况,请使用 BIGINT。祝你好运,在你的一生中用尽所有这些价值观。
  • 一次?在每条第 19 条记录之后,我将超过 1000 次。
  • 发生这种情况时您没有重新启动 SQL Server?你的系统肯定有一些不同,因为我肯定无法重现它...你能展示一下你是如何插入这 19 行的吗?
  • 请注意,无缝身份会产生重大的性能问题。顺便说一句,您是否更改了连接池的默认大小?
【解决方案2】:

这是一个小测试脚本,向您展示关于身份列的一些有趣的事情

1 - 大多数人使用 (1, 1)。

但是,您可以使用 (1, 5) 增加 5,这会留下间隙。
如果您愿意,也可以从 (2000, 1) 两千开始。

2 - 从表中删除所有记录不会重置计数器。

3 - 截断表格会将计数器重置为基数。

4 - 间隙可能是由于删除或阻止插入的条件。

最后有一个示例触发器,显示如果不玩大钱,就会出现缺口。

5 - 最后但同样重要的是,您可以从类型的负数范围开始。

对于 INT,从 -2147483648 开始,然后向 2147483647 递增,得到两倍的数字。 但是,如果用户看到 id,您可能不想要这个。然后使用 BIGINT。

-- Just playing
use tempdb;
go

-- drop existing
if object_id('superbowl_pool') > 0
drop table superbowl_pool
go


-- create new
create table superbowl_pool
(
id int identity (1,1) primary key,
cash smallmoney
);

-- add data
declare @a int = 0;
while (@a < 100)
begin
  insert into superbowl_pool (cash) values (rand(checksum(newid())) * 50);
  set @a += 1;
end
go

-- show the data
select * from superbowl_pool;

显示用户删除不重置计数器。

-- delete does not reset the counter
delete from superbowl_pool;
go

-- Two records
insert into superbowl_pool (cash) values (rand(checksum(newid())) * 50);
insert into superbowl_pool (cash) values (rand(checksum(newid())) * 50);
go

-- Gaps in id column
delete from superbowl_pool where id = 102;
insert into superbowl_pool (cash) values (rand(checksum(newid())) * 50);

-- show the data
select * from superbowl_pool;

向用户显示截断会重置计数器。

-- truncate table
truncate table superbowl_pool;

-- Two records
insert into superbowl_pool (cash) values (rand(checksum(newid())) * 50);
insert into superbowl_pool (cash) values (rand(checksum(newid())) * 50);
go

-- show the data
select * from superbowl_pool;

用户必须玩 $20 或更多

-- create ins trigger
create trigger dbo.trg_big_money on dbo.superbowl_pool
FOR INSERT
AS
BEGIN

  IF EXISTS (SELECT * FROM inserted where cash < 20)
      ROLLBACK;
END

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-23
    • 1970-01-01
    • 1970-01-01
    • 2017-05-14
    • 2011-08-19
    • 2023-03-09
    • 2017-09-06
    • 2021-05-07
    相关资源
    最近更新 更多