oracle 对不同记录的更新查询的数据库同步执行

unguejic  于 2023-10-16  发布在  Oracle
关注(0)|答案(3)|浏览(91)

我有一个这样的表结构:
ParentObject(ObjectId字符串,.....)
ChildObject(ObjectId字符串,ParentId字符串,Attribute1字符串,State字符串.)
有多个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更新了10条具有相同ParentId的ChildObject记录,则ChildObject中具有相同ParentId的其余记录应由Process1而不是Process2更新。
由于进程并行运行,因此在一个进程中更新某些ChildObject记录,而在另一个进程中更新具有相同ParentId的某些ChildObject记录。
Select.. For Update在我的情况下不起作用,因为更新发生在ChildObject表中的不同记录上。
锁定整个ChildObject表可能不是一个好的解决方案。
你能告诉我如何实现这种同步吗?
谢谢你,
瓦纳蒂

p5cysglq

p5cysglq1#

如何将ProcessName列添加到ParentObject表中。如果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
    )
)
scyqe7ek

scyqe7ek2#

第一步只需锁定父行。这将阻止任何其他会话(具有相同的锁定机制)处理该行

SELECT *
  FROM ParentObject
 WHERE ObjectID = <<whatever>>
   FOR UPDATE;

UPDATE ChildObject ...

根据Oracle版本和您正在做的事情,您可能不希望线程阻塞等待无限期地锁定ParentObject行。您可能希望执行FOR UPDATE NOWAIT,如果无法锁定父行,则捕获异常,然后继续下一行。或者您可能希望执行FOR UPDATE SKIP LOCKED以确定要处理的下一个ObjectID

hrysbysz

hrysbysz3#

我们遇到了类似的问题,多个k8s pod在update query下并行执行,并陷入死锁
因此,我们需要锁定会话1将要更新的行集,这将阻止其他会话更新相同的行。

SELECT * FROM 
(select group_slice_id,slice_id FROM queue_master
WHERE batch_run_id = 'STP_1693389464930_2015-04-03_1696424282917_1' AND COMPONENT_ID = '1_5'
AND Control_plane_pod_id is null AND status is null AND pod_id is null) WHERE rownum <= 10 
FOR UPDATE SKIP LOCKED;

update queue_master set status = 'CP-IN-PROGRESS', 
START_TIME = CURRENT_TIMESTAMP, control_plane_pod_id = 'cp-pod-1', CP_POD_IP='192.11.11.0'
where batch_run_id = 'STP_1693389464930_2015-04-03_1696424282917_1' and status is null and Control_plane_pod_id is null
and COMPONENT_ID = '1_5' and 
(group_slice_id,slice_id) in (select * from 
(select group_slice_id,slice_id from queue_master
where batch_run_id = 'STP_1693389464930_2015-04-03_1696424282917_1' and COMPONENT_ID = '1_5'
and Control_plane_pod_id is null and status is null and pod_id is null) where rownum <= 10 );

带有FOR UPDATE的选择查询将锁定这些行集,并且只有在提交或回滚后才释放锁定
并且FOR UPDATE SKIP LOCKED将锁定下一组行,而不是等待第一个会话释放锁定

相关问题