Dam*_*ods 4 database-design sql-server auto-increment identity sql-server-2012
我需要在 2 个单独的数据中心运行一个带有 2 个主表的 sql server 日志数据库,同时写入两个数据中心。
我的想法是将数据库恢复到新的数据中心,然后将身份列重新设定为 -1 并将增量设置为 -1,这样在需要合并数据时就不会出现重复的 ID。DATACENTRE1 为正整数,DATACENTRE2 为负整数
-1 的增量会导致任何问题吗?
倒退对我来说是错误的。
仅使用两个数据中心,您还可以实施身份范围。除非您以惊人的速度循环使用标识值,否则您没有理由不能拥有:
-- Data center 1
CREATE TABLE dbo.Table
(
ID INT IDENTITY(1,1) PRIMARY KEY
-- , ...
);
-- Data center 2
CREATE TABLE dbo.Table
(
ID INT IDENTITY(1000000000,1) PRIMARY KEY
-- , ...
);
Run Code Online (Sandbox Code Playgroud)
这将允许在与数据中心 2 发生碰撞之前在数据中心 1 中生成 10 亿(好吧,999,999,999)个值。您可以在数据中心 1 中添加 CHECK 约束以防止值重叠,具体取决于您如何确定优先级错误与重复。如果您担心在应用程序的生命周期中您真的会在任一数据中心生成超过 10 亿的值,您还可以实施一个循环作业,定期检查您与另一个数据中心的下限的接近程度(没关系你的)。
如果约 10 亿还不够,还有其他两种选择可以提供更多的喘息空间:
-- Data center 1
ID INT IDENTITY(-2147483648,1)
-- Data center 2
ID INT IDENTITY(1,1)
Run Code Online (Sandbox Code Playgroud)
这将为每个数据中心提供超过 20 亿个非重叠值,在数据中心 1 接近 0 之前不会发生碰撞危险。 如果这还不够:
-- Data center 1
ID BIGINT IDENTITY(-9223372036854775808,1)
-- Data center 2
ID BIGINT IDENTITY(1,1)
Run Code Online (Sandbox Code Playgroud)
或者,如果您想保持所有值 > 0,您可以将正范围大致分成两半(如果您比我更迂腐,您可以比这更精确一点)。
-- Data center 1
ID BIGINT IDENTITY(1,1)
-- Data center 2
ID BIGINT IDENTITY(4611600000000000000,1)
Run Code Online (Sandbox Code Playgroud)
我什至不知道怎么说这个数字,但它是巨大的。在现实中,您必须非常努力地在一台非常快的计算机上工作,以在您的曾曾曾曾孙从大学毕业时用完所有这些值。如果您使用的是企业版,您可以使用数据压缩,这样您就不必为所有 8 个字节付费,至少在数据中心 1 中,直到那里超过 20 亿个字节。
在我管理的系统中,我采用了稍微不同的方式——我们有多个带有 Express 实例的 Web 服务器,这些服务器负责生成企业中需要唯一的 ID 号。所以我们只是使用 BIGINT IDENTITY 列在每台机器上设置一个序列生成器(它们不需要实际存储值)。我们有 < 9 台服务器,所以它们都是这样播种的:
-- WEBAPP0001
ID BIGINT IDENTITY(10000000000,1)
-- WEBAPP0002
ID BIGINT IDENTITY(20000000000,1)
-- WEBAPP0003
ID BIGINT IDENTITY(30000000000,1)
...
Run Code Online (Sandbox Code Playgroud)
当这些值被使用然后在中央系统中合并时,我们不仅保证没有任何重复,而且还很容易立即识别它们来自哪个 Web 服务器(这有时在调试中很有用),而无需引入任何复合关键要求。我们不担心任何一台 Web 服务器会产生超过 100 亿的值。
在这种情况下,很多人会使用 GUID,但我认为有几个强有力的论据反对这种方法。
它不会导致问题,因为 SQL Server 允许您这样做:
create table decrement(
id integer identity(0,-1),
test int
)
insert into decrement (test) select number from numbers
select top 10 id, test from decrement order by id asc
go
id test
------------
-5103 5110
-5102 5109
-5101 5108
-5100 5107
-5099 5106
-5098 5105
-5097 5104
-5096 5103
-5095 5102
-5094 5101
Run Code Online (Sandbox Code Playgroud)
但从长远来看,一个好主意可能是一个不同的问题。其他人最终可能会感到困惑(即;我不得不考虑上面查询的顺序,因为它与正常情况相反)。或者当其他人恢复数据库并IDENTITY
以“正常”方式重新设定种子并且您有重叠的 ID 时会发生什么?
是否可以修改您的架构,以便您拥有一个“站点”列?然后使用站点和ID作为复合键?
使用此设置可能会出现的一些问题:
按照@Martin Smith评论中的链接,标识列中的负值可能会导致某些应用程序出现问题:为什么数据库设计者不让 IDENTITY 列从最小值而不是 1 开始?
另一个问题与值为负但正在减少的值无关,并且身份是否也是表的聚集键。B 树结构在从左到右(从低到高的值)遍历时以及在右侧(高)侧完成插入时(例如,当键不断增加时)更有效。这个属性对于表的聚集键来说更加重要。请参阅Kimberly Tripp 的这篇博文,了解集群键的最佳属性,尤其是关于不断增加的。
使用递减键,您将始终在索引的错误(左侧)侧插入数据,从而导致索引碎片化。效果可能对您的情况并不重要,但我认为如果身份也被选为集群键,您应该牢记这一点。
或者正如@Martin 建议的那样,将聚集索引也定义为DESC
(-1) 数据中心。这将避免任何上述碎片问题。
实现相同功能并保持增加 ID 的其他选项是在一个数据中心具有偶数值而在另一个数据中心具有奇数值(因此两者都具有 +2 增量)或siteID
添加到@Stuart 建议的主键。
归档时间: |
|
查看次数: |
10549 次 |
最近记录: |