【发布时间】:2018-01-27 16:38:42
【问题描述】:
我会尽量简化我的问题。
假设我们在 Oracle 11g 中有 3 个表。
Persons (person_id, name, surname, status, etc )
Actions (action_id, person_id, action_value, action_date, calculated_flag)
Calculations (calculation_id, person_id,computed_value,computed_date)
我想要的是每个人符合特定标准(比如说status=3)
我应该从Actions 表中获得action_values 的sum,其中calculated_flag=0。 (类似select sum(action_value) from Actions where calculated_flag=0 and person_id=current_id)。
然后我将在某种公式中使用 sum 并为特定的 person_id 更新 Calculations 表。
update Calculations set computed_value=newvalue, computed_date=sysdate
where person_id=current_id
之后,参与行的calculated_flag 将设置为1。
update Actions set calculated_flag=1
where calculated_flag=0 and person_id=current_id
现在这可以很容易地按顺序完成,方法是创建一个游标,该游标将遍历 Persons 表,然后执行特定人员所需的每个操作。
(我不提供顺序解决方案的代码,因为上面只是一个类似于我的实际设置的示例。)
问题是我们正在谈论大量的数据,而顺序方法似乎浪费了计算时间。
在我看来,这个任务可以针对多个 person_id 并行执行。
所以问题是:
这种任务可以在 PL/SQL 中使用并行化来执行吗?
解决方案会是什么样子?也就是说,应该使用哪些特殊的包(例如DBMS_PARALLEL_EXECUTE)、关键字(例如bulk collect)、方法以及以什么方式使用?
另外,我应该担心并行更新的部分失败吗?
请注意,我不太熟悉使用 PL/SQL 进行并行编程。 谢谢。
编辑 1. 这是我的顺序解决方案的伪代码
procedure sequential_solution is
cursor persons_of_interest is
select person_id from persons
where status = 3;
tempvalue number;
newvalue number;
begin
for person in persons_of_interest
loop
begin
savepoint personsp;
--step 1
select sum(action_value) into tempvalue
from actions
where calculated_flag = 0
and person_id = person.person_id;
newvalue := dosomemorecalculations(tempvalue);
--step 2
update calculations set computed_value = newvalue, computed_date = sysdate
where person_id = person.person_id;
--step 3
update actions set calculated_flag = 1;
where calculated_flag = 0 and person_id = person.person_id;
--step 4 (didn't mention this step before - sorry)
insert into actions
( person_id, action_value, action_date, calculated_flag )
values
( person.person_id, 100, sysdate, 0 );
exception
when others then
rollback to personsp;
-- this call is defined with pragma AUTONOMOUS_TRANSACTION:
log_failure(person_id);
end;
end loop;
end;
现在,我将如何使用forall 和bulk colletct 或并行编程来加快上述速度在以下约束下:
- 适当的内存管理(考虑到大量数据)
- 对于一个人,如果步骤序列的一部分失败 - 所有步骤都应该回滚并记录失败。
【问题讨论】:
-
并行处理是一种极端的解决方案。您是否考虑过基于集合的解决方案而不是游标循环?还是
bulk collect和forall? -
@TonyAndrews 这是一个想法......虽然我不太确定如何解决 1. 可能存在巨大的内存消耗(可能使用
limit会解决这个问题)2.通过顺序方法,我可以按人提交。在这种情况下,如果一个人的操作失败 - 其他人不受影响 - 不太确定如何使用bulk updates实现这一目标,因为每个人更新了多个表格。您提到的“基于集合的解决方案”是否与bulk collect和for all的使用相同,还是其他?您能否以伪代码提供您提出的解决方案?谢谢。 -
@TonyAndrews 为什么要避免并行解决方案?我对特定问题思考得越多,我就越相信使用
forall和基于集合的解决方案进行类似事务的操作(每人)可能会非常麻烦。我在这里错过了什么吗? -
在 25 年的 Oracle 开发中,我很少使用任何并行处理。它通常只在巨大的,可能是数据仓库,数据库中完成,并且有问题的工作是唯一在具有多个 CPU 的服务器上运行的东西(系统上没有其他用户同时)。这是你的情况吗? “相当大量的数据”是多少? 数十亿行?
-
@TonyAndrews 好的,所以行数肯定比数十亿少得多......可能有一百万(我稍后会给出一个估计)......但是你的其他标准提都种遇见。也就是说 - 此过程将单独运行(仅形成一个用户)并且每年仅运行两次或 4-5 次,而没有其他用户登录数据库。现在我倾向于并行解决方案,因为它看起来直观更干净的解决方案。此外,我仍然无法想象如何使用
bulk collect进行事务管理。for all和其他基于集合的解决方案。
标签: oracle plsql parallel-processing