没有 RESEED 的 MSSQL 身份插入

Posted

技术标签:

【中文标题】没有 RESEED 的 MSSQL 身份插入【英文标题】:MSSQL Identity Insert without RESEED 【发布时间】:2021-09-14 06:36:47 【问题描述】:

我在 4 个不同的位置有 4 个数据库。我写了一个程序来互相同步。该程序最多可在 2 个位置正常工作。我会解释原因。

每个数据库都有每个表的身份主键。如果我只配置了两个数据库。我可以将第一个数据库的身份设置为 IDENTITY(1,1),将另一个数据库设置为 IDENTITY(-1,-1)。但是如果有多个位置,那么我将不得不为每个数据库遵循一些模式。喜欢,

1st - Identity(1,5)
2nd - Identity(2,5)
3rd - Identity(3,5)
........
........

现在我的问题是,当我在每个数据库之间同步数据时。我使用 IDENTITY_INSERT ON 关键字。在 INSERTING 行到另一个数据库后,SEED 值将变为 MAX,它将打破这种模式。

例如,数据库 A 有这样的值,

1
6
11
16

数据库 B 有值,

2
7
12
17

如果我将数据从数据库 B 同步到 A。它(A)将 SEED 为 17,下一个值为 22。此时模式将中断。

有人在其他论坛上问过同样的问题。链接在这里。 https://www.sqlservercentral.com/forums/topic/identity-insert-without-reseed/page/2 但是解决方案对我不起作用。他们建议使用“REPLICATION=TRUE;”在连接字符串中以避免 RESEED 但这对我不起作用。

如何解决这个问题?我想我可以通过为每个数据库分配范围来做到这一点,但我更愿意使用序列号。

谢谢。

【问题讨论】:

这就是微软创建复制服务的原因。它会为您处理所有这些。 使用 GUID 或使用包含系统 ID 的复合键。无论您想出什么编号系统,都会发生冲突或编号用完 【参考方案1】:

如果您有多个带有标识列的服务器,并且您希望将数据合并到一个地方,那么 SQL Server 提供了多种复制和分发的可能性。

如果我理解您的问题,那么您可以将服务器设置为使用不同的值范围。一种方法是在每台服务器上将标识列启动为不同的值:

identity(1, 1)
identity(1000000, 1)

这假设您在每台服务器上的行数永远不会超过 1000000。

一种稍微不同的方法是将偶数放在一台服务器上,将奇数放在另一台服务器上:

identity(1, 2)
identity(2, 2)

这两者都保证了“合并”后身份值不会冲突。

【讨论】:

感谢您的回复。您已经很好地理解了我的问题。我想参考您提到的第二种方法,但存在一些问题。当我使用 SET IDENTITY_INSERT ON 插入任何行时。然后模式将打破。 SEED 值将重置为最高值。 我再次检查了这个。当它从一个同步到另一个时。奇数和偶数将不再起作用。【参考方案2】:

...将标识列标记为“不用于复制”

ssms tab_1(正常连接):

use tempdb
go
drop table if exists dbo.x;
drop table if exists dbo.y;
go

create table dbo.x(id int identity(1,5), a char(1) default('a'));
create table dbo.y(id int identity(1,5) not for replication, a char(1) default('a'));
go

insert into dbo.x(a)
values ('a'), ('a'), ('a');
insert into dbo.y(a)
values ('a'), ('a'), ('a');
go

select 'x' as tbl, * from dbo.x;
select 'y' as tbl, * from dbo.y;
go

ssms tab_2 (..Options-->附加连接参数--> add Replication=true;) :

set identity_insert dbo.x on;
insert into dbo.x(id, a)
output inserted.*
values (12, 'b');
set identity_insert dbo.x off;
select 'x' as tbl, * from dbo.x;
go

set identity_insert dbo.y on;  --..not actually needed
insert into dbo.y(id, a)
output inserted.*
values (12, 'b');
set identity_insert dbo.y off;  --.. 
select 'y' as tbl, * from dbo.y;
go

/*
--error for a "typical" insertion when in "Replication"
--:Explicit value must be specified for identity column in table 'y' either when IDENTITY_INSERT is set to ON 
-- or when a replication user is inserting into a NOT FOR REPLICATION identity column.

insert into dbo.y(a)
values ('a')
*/

ssms tab_3(正常连接):

insert into dbo.x(a)
values('z'), ('z');
go

insert into dbo.y(a)
values('z'), ('z');
go

select 'x' as tbl, * from dbo.x;
select 'y' as tbl, * from dbo.y;
go

【讨论】:

以上是关于没有 RESEED 的 MSSQL 身份插入的主要内容,如果未能解决你的问题,请参考以下文章

mssql 2000,以用户身份执行sql语句。

使用 Promise 从数据库中获取身份值

远程连接到 MSSQL,使用 Windows 身份验证,JAVA

node mssql 无法连接sql server

使用 Windows 身份验证时要填写 mssql_connect 的哪些登录数据?

身份插入是不是有任何问题。没有它的其他并发操作会正常运行还是会产生缓慢或死锁?