我有一个像这样的表结构:
ParentObject(ObjectId string,.....)
ChildObject(ObjectId string,ParentId String,Atribute1 String,State Integer ....)
有多个ParentObject记录(接近1000个),每个ParentObject记录表由ChildObject表中的多个记录(接近50个)引用。
我有两个在不同机器上运行的并行进程,它们使用OCI库调用在循环中执行此查询。
UPDATE ChildObject SET Attribute1='<process_name>' WHERE ObjectId = ANY
(SELECT TOP 100 ObjectId FROM ChildObject alias1 WHERE State = 0
AND NOT EXISTS
(SELECT * FROM ChildObject alias2 WHERE alias2.State = 0 AND
alias2.Attribute1 <> ' ' AND alias2.ParentId = alias1.ParentId))
语法可能不完美。逻辑是每个进程在运行中更新100个ChildObject记录,并将Attribute1设置为进程名称(如果尚未设置),休眠一段时间并再次开始更新。
我的要求是,所有引用同一ParentObject记录的ChildObject记录都应该由一个进程更新。例如,如果Process1更新具有相同ParentId的10个ChildObject记录,则具有相同ParentId的其余ChildObject记录应由Process1更新,而不是由Process2更新。
由于进程并行运行,因此一些ChildObject记录在一个进程中更新,一些具有相同ParentId的ChildObject记录在另一个进程中更新。
选择..对于更新在我的情况下不起作用,因为更新发生在ChildObject表中的不同记录上。
锁定整个ChildObject表可能不是一个好的解决方案。
您能否建议我如何实现此同步?
谢谢,
Vanathi
答案 0 :(得分:0)
如何将ProcessName列添加到ParentObject表中。如果ProcessName为null,则首先要更新子进程的进程必须在父进程上设置ProcessName(在更新查询中包含条件,不要先检查它)。即使两个进程都尝试同时设置父ProcessName,也只有一个进程成功。然后,该进程读取父进程的ProcessName,如果它是自己的名称,则继续更新子进程。
如果您无法添加或修改表格,请将查询更改为:
UPDATE ChildObject
SET Attribute1='<process_name>'
WHERE ObjectId = ANY (
SELECT TOP 100 ObjectId
FROM ChildObject alias1
WHERE State = 0 AND NOT EXISTS (
SELECT *
FROM ChildObject alias2
WHERE alias2.Attribute1 <> ' '
AND alias2.Attribute1 <> '<process_name>'
AND alias2.ParentId = alias1.ParentId
)
)
答案 1 :(得分:0)
只需将父行锁定为第一步。这将阻止任何其他会话(具有相同的锁定机制)处理该行
SELECT *
FROM ParentObject
WHERE ObjectID = <<whatever>>
FOR UPDATE;
UPDATE ChildObject ...
根据Oracle版本以及您正在执行的操作,您可能不希望线程阻止等待无限期锁定ParentObject
行。您可能想要执行FOR UPDATE NOWAIT
,如果您无法锁定父行,则会捕获异常,然后转到下一行。或者您可能需要FOR UPDATE SKIP LOCKED
来确定要处理的下一个ObjectID
。