【发布时间】:2016-12-19 04:32:42
【问题描述】:
背景
我有很多不同的“事物”(特定领域的项目/实体/主题),这些“事物”所有者(人类)是可见的。业主将用数字标识他们的“东西”。而不是显示一个大的“随机”数字,我想向他们显示一个对人类来说更容易的小数字(最好是从 1 开始的序列)。业主很乐意谈论“my foo 37”和“her bar 128”。 “序列”可能有间隙,但附加的数字在“事物”实例的生命周期内必须保持不变。所以我需要一种方法来生成“事物”+所有者特定的 id(目前称为“可见 id”)。
“事物”+所有者组合的数量为 10k+。目前新的“事物”不能动态生成,但所有者可以。
每个所有者一个“事物”实例的数量相对较少,每个所有者大约几十个,但是没有可以从业务规则中得出的硬性上限。经常创建和删除新的“事物”实例。
考虑的选项
我在 SO question Oracle Partitioned Sequence 中找到了一个很好的讨论,它解决了我遇到的几乎相同的问题。
到目前为止,我已经考虑了以下选项:
- 我认为标准数据库序列会非常好,但这需要我动态创建大量“事物”+ 所有者特定序列,并在插入过程中解析序列名称。 (并在所有者离开时删除序列。)我不确定创建大量序列是否是一种好习惯(对我来说,10k+ 数据库对象是一个巨大的数字)。
- 我也认为是臭名昭著的
max(visible_id) + 1,但我们会遇到正常的并发问题,所以这是不行的。 - 根本不将所有者特定的 ID 保存到数据库中,而是在 suggested by Adam Musch 的选择中生成它。这是一个绝妙的主意,但不幸的是,在“事物”实例的生命周期内,id 必须是相同的。
- 通过让所有者命名“事物”来避免整个问题。但他们根本不喜欢这个主意 - “我为什么要打扰,说 foo 16 就是这么容易。”!
问题
是否有其他方法可以解决此问题,或者我应该开始动态创建序列?如果序列是答案,请详细说明可能存在哪些陷阱(例如 DDL 中的隐式提交)。
我对 Oracle 11gR2 和 12c 解决方案都感兴趣(如果它们不同的话)。
说明问题的伪代码
create table foo (
id number primary key -- the key for computers
,owner_id number
,visible_id number -- the key for humans
,data_ varchar2(20)
);
create constraint foo_u1 unique foo(owner_id, visible_id);
-- primary key sequence
create sequence foo_id_seq;
insert into foo values(
foo_id_seq.nextval
,1
,1 -- what to put here ?
,'lorem ipsum'
);
insert into foo values(
foo_id_seq.nextval
,2
,1 -- what to put here ?
,'dolor sit amet'
);
select visible_id, data_ from foo where owner = 2 order by visible_id;
【问题讨论】:
-
为什么选项 3 不适用?事物实例可能会被删除?如果将它们标记为已删除(例如通过附加列)怎么办?
-
我不明白为什么当 MAX(visible_id) 被限制为特定的 ownerid 时 #2 会产生并发问题(你绝对不希望整个表的最大值)。所有者是否可能会同时从多个应用程序实例更新他们的项目?听起来您需要表上的主键,ownerid,thingid。 Thingid 必须由您生成,因此我建议您使用存储过程进行更新/插入/删除,以便您可以根据需要管理序列,而不是直接调用 dml 操作
-
@KonstantinSorokin 嗯......因为,错误......我可能只是因为我对那个选项视而不见。是的,我知道soft delete,是的,我的第一个想法是这可能非常适合这里。我需要更多地思考这个想法以及利弊。
-
@Matt 你是对的,所有访问都将在 PL/SQL 接口之后(我的问题中没有明确表示)。此外,
owner_id和visible_id将是由约束强制执行的唯一组合。然而,即使我们对所有者有一个明确的概念,不幸的是它也不排除来自不同来源的多个同时插入 - 所有者并不总是可以生成新“事物”实例的唯一来源。如果可能的话,我不想故意引入序列化点(即使它是由 PL/SQL API 控制的,并且冲突可能只会“很少”发生)。感谢您挑战我的想法! -
创建和删除 10k+ 个 oracle 序列需要几秒钟。但我认为选项 1 可能会在某种程度上减慢插入速度,因为为每个所有者的序列动态创建了硬解析语句。从这个角度来看,通过带有包 API 的表(以提供自治事务和缓存)维护自助序列看起来还不错。但我还是更喜欢选项 3。