您必须以某种方式“锁定”您要处理的行。这种“锁定”当然应该与最小的冲突/错误同时发生。
一种方法如下:
Create table change
(
id int not null generated always as identity
, v varchar(10)
) in userspace1;
insert into change (v) values '1', '2', '3';
Create table change_process_rel
(
id int not null
, pid int not null
, status int not null
) in userspace1;
create unique index change_process_rel1 on change_process_rel(id);
现在您应该能够从多个并发会话中运行相同的语句:
SELECT ID
FROM NEW TABLE
(
insert into change_process_rel (id, pid, status)
select c.id, mon_get_application_handle(), 1
from change c
where not exists (select 1 from change_process_rel r where r.id = c.id)
fetch first 1 row only
with ur
);
每个这样的语句都会在表中插入 1 或 0 行change_process_rel
,这里用作“锁定”表。返回对应ID
的from change
,您可以在同一个事务中继续处理对应的事件。
如果事务成功完成,则保存插入到change_process_rel
表中的行,因此可以认为对应id
的 from已处理。change
如果事务失败,则相应的“锁定”行从change_process_rel
消失,并且此行可能稍后由该应用程序或另一个应用程序处理。
这种方法的问题是,当两个表都变得足够大时,这样的子选择可能不会像以前那样快速工作。
它需要将status
列放入change
表中。不幸的是,Db2 for LUW 没有SKIP LOCKED
功能,这可能有助于这种算法。
如果,比方说,status=0
是“未处理”,并且status<>0
是一些处理/处理状态,那么在设置这些DB2_EVALUNCOMMITTED
和DB2_SKIP*
注册表变量并重新启动实例之后,您可以使用以下语句“捕获”下一个ID
进行处理。
SELECT ID
FROM NEW TABLE
(
update
(
select id, status
from change
where status=0
fetch first 1 row only
)
set status=1
);
ID
一旦你得到它,你就可以像以前一样在同一个事务中做进一步的处理。
为性能创建索引很好:create index change1 on change(status); 并且可以将此表设置为 volatile 或收集此列的分布统计信息,以及定期对表及其索引进行定期统计。
请注意,这样的注册表变量设置具有全局效果,您应该牢记...