我正在使用没有SEQUENCE
功能的SQL Server 2008 Standard 。
外部系统从主数据库的几个专用表中读取数据。外部系统保留数据副本,并定期检查数据更改并刷新其副本。
为了使同步高效,我只想传输自上次同步以来已更新或插入的行。(行永远不会删除)。要知道自上次同步以来已更新或插入了哪些行,每个表中都有一bigint
列RowUpdateCounter
。
这个想法是,每当插入或更新一行时,其RowUpdateCounter
列中的数字就会改变。列中的值RowUpdateCounter
应取自不断增加的数字序列。RowUpdateCounter
列中的值应唯一,并且表中存储的每个新值都应大于任何先前值。
请查看显示所需行为的脚本。
架构图
CREATE TABLE [dbo].[Test](
[ID] [int] NOT NULL,
[Value] [varchar](50) NOT NULL,
[RowUpdateCounter] [bigint] NOT NULL,
CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED
(
[ID] ASC
))
GO
CREATE UNIQUE NONCLUSTERED INDEX [IX_RowUpdateCounter] ON [dbo].[Test]
(
[RowUpdateCounter] ASC
)
GO
插入一些行
INSERT INTO [dbo].[Test]
([ID]
,[Value]
,[RowUpdateCounter])
VALUES
(1, 'A', ???),
(2, 'B', ???),
(3, 'C', ???),
(4, 'D', ???);
预期结果
+----+-------+------------------+
| ID | Value | RowUpdateCounter |
+----+-------+------------------+
| 1 | A | 1 |
| 2 | B | 2 |
| 3 | C | 3 |
| 4 | D | 4 |
+----+-------+------------------+
中生成的值RowUpdateCounter
可以不同,例如5, 3, 7, 9
。因为我们从空表开始,所以它们应该是唯一的并且应该大于0。
插入和更新一些行
DECLARE @NewValues TABLE (ID int NOT NULL, Value varchar(50));
INSERT INTO @NewValues (ID, Value) VALUES
(3, 'E'),
(4, 'F'),
(5, 'G'),
(6, 'H');
MERGE INTO dbo.Test WITH (HOLDLOCK) AS Dst
USING
(
SELECT ID, Value
FROM @NewValues
)
AS Src ON Dst.ID = Src.ID
WHEN MATCHED THEN
UPDATE SET
Dst.Value = Src.Value
,Dst.RowUpdateCounter = ???
WHEN NOT MATCHED BY TARGET THEN
INSERT
(ID
,Value
,RowUpdateCounter)
VALUES
(Src.ID
,Src.Value
,???)
;
预期结果
+----+-------+------------------+
| ID | Value | RowUpdateCounter |
+----+-------+------------------+
| 1 | A | 1 |
| 2 | B | 2 |
| 3 | E | 5 |
| 4 | F | 6 |
| 5 | G | 7 |
| 6 | H | 8 |
+----+-------+------------------+
RowUpdateCounter
ID为ID的行1,2
应保持不变,因为这些行未更改。RowUpdateCounter
具有ID的行3,4
应更改,因为它们已更新。RowUpdateCounter
ID为ID的行5,6
应更改,因为已将其插入。RowUpdateCounter
所有更改的行都应大于4(RowUpdateCounter
序列中的最后一个)。
新值(5,6,7,8
)分配给更改后的行的顺序并不重要。新值可以有空白,例如15,26,47,58
,但绝不能减少。
数据库中有几个带有此类计数器的表。它们是否都使用单个全局序列作为其编号,还是每个表都有其自己的序列都没关系。
我不想使用带有日期时间戳的列而不是整数计数器,因为:
服务器上的时钟可以向前和向后跳跃。尤其是当它在虚拟机上时。
SYSDATETIME
对于所有受影响的行,像这样的系统函数返回的值都相同。同步过程应该能够批量读取更改。例如,如果批处理大小为3行,则在MERGE
同步过程以上的步骤之后,将仅读取row行E,F,G
。下次运行同步过程时,它将从row继续H
。
我现在的做法相当丑陋。
由于SEQUENCE
SQL Server 2008中没有,因此我SEQUENCE
用专用表模拟IDENTITY
,如此答案所示。我本身不需要一次生成一个数字,而是一次生成一批数字,这一点本身就很丑陋,而且更加恶化。
然后,我INSTEAD OF UPDATE, INSERT
在每个表上使用触发,并在RowUpdateCounter
那里生成所需的数字集。
在INSERT
,UPDATE
并MERGE
查询我设置RowUpdateCounter
为0,这是通过在触发正确的值替换。在???
查询中的以上都是0
。
它有效,但是有更简单的解决方案吗?
rowversion
不会给我这个可能性,如果我理解正确的是什么?它是保证将不断增加?
rowversion
。看起来很诱人。我唯一关心的是,到目前为止,我所见过的所有使用示例都围绕着检测单行是否发生更改。我需要知道什么是一个有效的方式设置,因为某一个时刻更改的行。此外,是否有可能错过更新?
A
更新一行,其rowversion更改为123,A
尚未提交。time = 2:事务B
更新另一行,其rowversion更改为124。time = 3:B
提交。time = 4:同步过程运行并获取rowversion> 122的所有行,这意味着行仅由更新B
。时间= 5:A
提交。结果:更改A
将永远不会被同步过程接收。我错了吗?也许聪明地使用MIN_ACTIVE_ROWVERSION
会有所帮助吗?