无间隙序列,其中涉及具有多个表的多个事务

我(根据法律)要求在不同的表格上使用无间隙数字。 ID可以包含空洞但不包含序列。

这是我必须在C#代码或数据库(Postgres,MS SQL和Oracle)中解决的问题。

这是我的问题:

Start transaction 1 Start transaction 2 Insert row on table "Portfolio" in transaction 1 Get next number in sequence for column Portfolio_Sequence (1) Insert row on table "Document" in transaction 1 Get next number in sequence for column Document_Sequence (1) Insert row on table "Portfolio" in transaction 2 Get next number in sequence for column Portfolio_Sequence (2) Insert row on table "Document" in transaction 2 Get next number in sequence for column Document_Sequence (2) Problem occurred in transaction 1 Rollback transaction 1 Commit transaction 2 

问题: Portfolio_SequenceDocument_Sequence顺序缺口。

请注意,这是非常简化的,并且每个事务中都包含更多表。

我怎么处理这个?

我已经看到建议你“锁定”序列,直到事务被提交或回滚,但是当涉及这么多的表和这个复杂的长事务时,这将是系统的一个巨大停顿。

正如您已经看到的那样,无间隙序列根本无法扩展。 您可能会在发生回滚时冒着丢弃值的风险,或者您的序列化点会阻止多用户并发事务系统进行扩展。 你不能兼得。

我的想法是,后处理行动怎么样,每天,你有一个在业务结束时运行的流程,检查差距,并重新编号需要重新编号的任何东西?

最后一个想法:我不知道你的要求,但是,我知道你说这是“法律规定的”。 那么,问问自己,人们在有电脑之前做了什么? 如何满足这个“要求”? 假设你有一堆空白表格在右上角预先印有“序列”号码? 如果有人在那个表格上洒咖啡会怎么样? 怎么处理? 看来你需要一个类似的方法来处理你的系统。

希望有所帮助。

这个问题原则上无法解决,因为任何事务都可以回滚(错误,超时,死锁,网络错误……)。

拥有一个串行争用点。 尝试尽可能减少争用: 保持分配数字的事务尽可能小 。 此外,在事务中尽可能晚地分配数字,因为只有在您分配数字争用时才会出现。 如果你正在进行1000毫秒的无竞争工作,然后分配一个数字(需要10毫秒),你仍然有100度的并行度就足够了。

因此,您可以使用虚拟序列号插入所有行(您说其中有很多行),并且只有在事务结束时,您才能快速分配所有实际序列号并更新已写入的行。 如果插入多于更新,或者更新比插入(它们将是更快)更快,或者插入之间存在其他处理或等待交错,则这将很好地工作。

无差距序列很难得到。 我建议改用普通的serial列。 使用窗口函数row_number()创建一个视图以生成无间隙序列:

 CREATE VIEW foo AS SELECT *, row_number() OVER (ORDER BY serial_col) AS gapless_id FROM tbl; 

这是一个应该支持高性能和高并发性的想法:

  1. 使用高度并发的缓存Oracle序列为无间隙表行生成一个哑的唯一标识符。 将此实体称为MASTER_TABLE

  2. 对于从MASTER_TABLE到其他相关详细信息表的所有内部参照完整性,请使用哑唯一标识符。

  3. 现在,您的无间隙MASTER_TABLE序列号可以作为MASTER_TABLE上的附加属性实现,并且将由与MASTER_TABLE行创建分开的进程填充。 实际上,应该在MASTER_TABLE的第4个普通表单属性表中维护无间隙附加属性,因此然后单个后台线程可以在闲暇时填充它,而不用担心MASTER_TABLE上的任何行锁。

  4. 所有需要在屏幕或报告或其他任何内容上显示无间隙序列号的查询都会将MASTER_TABLE与无间隙附加属性第4普通表格表连接起来。 注意,只有在后台线程填充了无间隙附加属性4th normal form table之后,才会满足这些连接。