如何在Oracle中的记录中创建序列号?

时间:2014-04-24 16:07:41

标签: sql oracle sequence

我有两个表,foobar

foo
,----------------.
|id | name | ... |
|---+------+-----|
| 1 | abc  | ... |
| 2 | xyz  | ... |
| ...            |
`----------------'

bar
,-------------------------.
| id | foo_id | num | ... |
|----+--------+-----+-----|
| 1  | 1      | 1   | ... |
| 2  | 1      | 2   | ... |
| 3  | 1      | 3   | ... |
| 4  | 2      | 1   | ... |
| 5  | 2      | 2   | ... |
| ...                     |
`-------------------------'

对于每个foo记录,有许多bar条记录,每条记录都有一个插槽号(num),每个foo_id的值应为1 - N }。因此,(foo_idnum)上有一个唯一键。这些插槽号是有意义的,必须是顺序的。

由于最后一个约束条件,我不能使用Oracle的原生序列(因为它们不能保证是连续的,并且似乎不是用于值的有意义的)。 foo记录的数量也 extermely 大,并且每个foo_id都有一个序列似乎非常不切实际。

所以,我的问题是 - 在插入时创建这些数字有哪些方法可以在高并发性下保留?我唯一的选择是锁定并选择MAX(num) + 1,并在提交时释放锁定吗?

2 个答案:

答案 0 :(得分:2)

你可以使用两步法:

  1. 您可以使用序列
  2. 将记录统一存储到数据库中
  3. 运行一个脚本,该序列将填充序列号中的num:

    --q1
    insert into bar (id, foo_id, seq_num) values (:id, :foo, someseq.next_val)
    
    --q2
    update bar b1 set
    num = (select 1+count(*) from bar b2 
    where b2.foo_id = b1._foo_id 
    and b2.seq_num < b1.seq_num)
    where num is null
    
  4. 或者你可以让条形有间隙,但是有一个视图bar_vw可以在飞行中纠正它:

         create view bar_vw as
            select id, foo_id, 
            row_number() over (partition by foo_id, order by seq_num) as num 
         from bar
    

答案 1 :(得分:0)

如果有一种方法来构建系统,使得一次只有一个会话为任何特定的bar行插入foo行,那将是理想的,因为这将消除实际争用(I假设您仍然希望代码处理它以防万一)。

要管理并发性,您几乎肯定需要锁定父foo行(select for update),然后使用max(num) + 1行执行bar { {1}}。我想你可能会省略锁定foo_id记录的步骤,并创建一个物化视图,在提交时快速刷新以验证foo值是顺序的,但这似乎不大可能是更快,似乎很可能它会使代码更复杂,因为你现在正在提交时捕获异常,而不是简单地阻塞,直到你可以继续前进。