无间隙序列,其中涉及多个表的多个事务
本文关键字:事务 间隙 | 更新日期: 2023-09-27 17:51:16
我有一个要求(根据法律),在不同的表上没有差距的数字。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_Sequence
和Document_Sequence
的序列都有间隙。
注意,这是非常简化的,并且每个事务中包含更多的表。
我该如何处理?
我看到有人建议在事务提交或回滚之前"锁定"序列,但是当涉及这么多表和这么复杂的长事务时,这将是一个巨大的停顿。
正如您似乎已经得出的结论,无间隙序列根本无法缩放。当回滚发生时,您可能会冒丢失值的风险,或者您的序列化点会阻止多用户并发事务系统的扩展。你不能两者兼得。
我的想法是,后处理操作怎么样?每天,您都有一个流程在营业结束时运行,检查差距,并重新编号任何需要重新编号的东西?
最后一个想法:我不知道你的要求,但是,我知道你说这是"法律要求"。那么,问问你自己,在电脑出现之前,人们在做什么?如何满足这个"需求"?假设你有一堆空白的表格,在右上角预先打印了一个"序列"号码?如果有人把咖啡洒在表格上怎么办?那是怎么处理的?看来你需要一个类似的方法来处理你的系统。
希望对你有帮助。
这个问题原则上是不可能解决的,因为任何事务都可以回滚(bug、超时、死锁、网络错误等)。
您将有一个串行争点。尽量减少争用:使分配数字的事务尽可能小。此外,在事务中尽可能晚地分配数字,因为只有在分配数字时才会出现争用。如果你正在做1000ms的无争用工作,然后分配一个数字(占用10ms),你仍然有100的并行度,这就足够了。
所以也许你可以用虚拟序列号插入所有行(你说有很多),只有在事务结束时,你才能快速分配所有真实序列号并更新已经写入的行。如果插入比更新多,或者更新比插入快(它们将会是这样),或者插入之间有其他处理或等待,这将工作得很好。
无间隙序列很难得到。我建议使用普通的serial
列代替。使用窗口函数row_number()
创建一个视图,以生成无间隙序列:
CREATE VIEW foo AS
SELECT *, row_number() OVER (ORDER BY serial_col) AS gapless_id
FROM tbl;
这是一个既支持高性能又支持高并发性的想法:
-
使用一个高度并发的,缓存的Oracle序列为无间隙的表行生成一个哑唯一标识符。将这个实体命名为MASTER_TABLE
-
为从MASTER_TABLE到其他依赖的详细表的所有内部引用完整性使用哑唯一标识符
-
现在,您的无间隙MASTER_TABLE序列号可以作为MASTER_TABLE上的附加属性实现,并且将由与MASTER_TABLE行创建分离的进程填充。实际上,应该在MASTER_TABLE的第4个标准形式属性表中维护无间隙附加属性,这样单个后台线程就可以轻松地填充它,而不必担心MASTER_TABLE上的任何行锁。
-
所有需要在屏幕或报告上显示无间隙序列号的查询,将与无间隙附加属性第4 normal form表连接MASTER_TABLE。注意,只有在后台线程填充了无间隙附加属性第4个范式表之后,这些连接才会被满足。