冒着过度解释我的问题的风险,我会错误地提供太多信息。
我正在创建一个批量上传过程,将数据插入两个表中。这两个表大致如下所示。TableA
是一个自引用表,允许 N 级引用。
Parts (self-referencing table)
--------
PartId (PK Int Non-Auto-Incrementing)
DescriptionId (Fk)
ParentPartId
HierarchyNode (HierarchyId)
SourcePartId (VARCHAR(500) a unique Part Id from the source)
(other columns)
Description
--------
DescriptionId (PK Int Non-Auto-Incrementing)
Language (PK either 'EN' or 'JA')
DescriptionText (varchar(max))
(我还应该指出,还有其他表格将引用我们的PartID
我暂时不谈这个。)
In Description
, 的组合Description
and Language
将是唯一的,但实际的“DescriptionID”将始终具有至少两个实例。
现在,对于批量上传过程,我创建了两个临时表,它们看起来很像Parts
and Description
但没有任何 PK、索引等。它们是Parts_Staging
and Description_Staging
.
In Parts_Staging
还有一个额外的列,其中包含一个 Hierarchy Node String,它是这种格式的 HierarchyNode:/1/2/3/
等等。然后,当数据从 _Staging 表复制到实际表时,我使用CAST(Source.Column AS hierarchyid)
.
由于两个表之间共享的 ID 很复杂,因此自引用 id 和 hierarchyidParts
,以及要插入的行数(可能是 100,000 行)我决定首先 100% 编译 C# 模型中的所有数据,包括 PK ID。所以这个过程在 C# 中看起来像这样:
- 查询两个表的 MAX ID
- 使用这些最大ID,编译两个表的所有数据的完整模型(包括hierarchyid /1/2/3/)
- 对两个 _Staging 表进行批量插入
- 触发一个 SP,将两个 _Staging 表中的非重复数据复制到实际表中。 (这就是
CAST(Source.Column AS hierarchyid)
发生)。
我们正在导入大量零件书,并且单个零件可能会在多本书中复制。我们需要删除重复项。在步骤 4 中,通过检查来清除重复项SourcePartId
in the Parts
表和Description
in the DescriptionText
in the Description
table.
整个过程非常顺利!最重要的是,它非常快。但是,如果您仔细阅读本文(如果您仔细阅读,我会表示感谢),那么您已经注意到一个明显的问题。
如果多个进程同时发生(这绝对会发生!),那么就存在 ID 混淆和数据真正损坏的风险。 Process1 可以执行以下操作GET MAX ID
查询并在完成之前,Process2 还可以执行GET MAX ID
查询,并且由于 Process1 尚未实际写入表,因此它将获得相同的 ID。
我最初的想法是使用 SEQUENCE 对象。起初,这个计划似乎很出色。但它在测试中失败了,因为当从 _Staging 表复制到最终表时,相同的数据完全有可能被多次处理并最终被忽略。在这种情况下,SEQUENCE 编号将已被声明和使用,从而导致 ID 中存在巨大间隙。这并不是一个致命的缺陷,但这是一个我们宁愿避免的问题。
所以...有很多背景信息来提出这个实际问题。我想做的是这样的:
- 锁定两个有问题的表
- 如上所述的步骤 1-4
- 解锁两个表。
该锁需要是读锁(我认为是排它锁?),这样如果另一个进程尝试执行GET MAX ID
查询,则需要等待。
我的问题是:1)这是最好的方法吗? 2)如何在表上放置排他锁?
Thanks!