冒着过多解释我的问题的风险,我会在过多信息方面犯错。
我正在创建一个批量上传过程,该过程将数据插入两个表中。这两个表大致如下。 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
。)
在Description
中,Description
和Language
的组合将是唯一的,但是实际的“ DescriptionID”将始终至少具有两个实例。
现在,对于批量上传过程,我创建了两个登台表,它们看起来很像Parts
和Description
,但没有任何PK,索引等。它们是{{1} }和Parts_Staging
。
在Description_Staging
中有一个额外的列,它包含一个层次结构节点字符串,它是这种格式的HierarchyNode:Parts_Staging
等。然后,当数据从_Staging表复制到实际的表格中,我使用了/1/2/3/
。
由于两个表之间共享ID的复杂性,CAST(Source.Column AS hierarchyid)
中的自引用ID和hierarchyid以及要插入的行数(可能是100,000个)决定了首先100%编译C#模型中的所有数据,包括PK ID。因此,该过程在C#中如下所示:
Parts
发生的位置)。 我们正在导入很多零件书,并且单个零件可以在多本书中复制。我们需要删除重复项。在步骤4中,通过检查CAST(Source.Column AS hierarchyid)
表中的SourcePartId
和Parts
表中Description
的{{1}}清除重复项。
整个过程效果很好!最重要的是,它确实非常快。但是,如果您仔细阅读(感谢您),那么您已经注意到一个明显的明显问题。
如果同时发生多个进程(并且绝对会发生!),那么就很有可能会混淆ID并造成数据真正损坏。 Process1可以执行DescriptionText
查询,在设法完成之前,Process2也可以执行Description
查询,并且因为Process1尚未实际写入表中,所以它会获得相同的ID。 / p>
我最初的想法是使用SEQUENCE对象。一开始,该计划似乎很出色。但是它在测试中失败了,因为完全有可能对同一数据进行不止一次处理,并且在从_Staging表到最终表的复制发生时最终将其忽略。在那种情况下,SEQUENCE号将已经被声明和使用,从而导致ID的巨大缺口。这并不是致命的缺陷,而是我们宁愿避免的问题。
所以...这是很多背景信息,可以问这个实际问题。我想做的是这样的:
该锁必须是READ锁(我认为这是互斥锁?),以便如果另一个进程尝试执行GET MAX ID
查询,则必须等待。
我的问题是:1)这是最好的方法吗?并且2)如何在表上放置排他锁?
谢谢!
答案 0 :(得分:3)
我不确定哪种方法最好,但是就在表上放置“排他”锁而言,仅在查询中与(TABLOCKX)一起使用会在表上放置一个。
如果您想了解它;