用于更新超过 1 000 000 行的 Pl/Sql 脚本
Posted
技术标签:
【中文标题】用于更新超过 1 000 000 行的 Pl/Sql 脚本【英文标题】:Pl/Sql Script for update more than 1 000 000 rows 【发布时间】:2021-06-26 12:51:03 【问题描述】:我有一张桌子:
id| name | organisation_name|flag |priority|salary
1 | Mark | organisation 1 |null |1 |100.00
2 | Inna | organisation 1 |null |2 |400.00
3 | Marry| organisation 1 |null |3 |500.00
4 | null | organisation 1 |250.00|null |null
5 | Grey | organisation 2 |null |1 |600.00
6 | Holly| organisation 2 |null |2 |400.00
8 | null | organisation 2 |150.00|null
该程序应按优先级从特定组织的工资中扣除该标志。上面的结果如下。 结果:
id| name | organisation_name|flag |priority|salary
1 | Mark | organisation 1 |null |1 |0.00
2 | Inna | organisation 1 |null |2 |250.00
3 | Marry| organisation 1 |null |3 |500.00
4 | null | organisation 1 |250.00|null |null
5 | Grey | organisation 2 |null |1 |450.00
6 | Holly| organisation 2 |null |2 |400.00
8 | null | organisation 2 |150.00|null
我为此创建了 Pl/sql 块,但是在一百万条记录上速度太慢了。 最快的方法是什么?
【问题讨论】:
【参考方案1】:这里不需要 PL/SQL。 SQL 有足够的能力来做到这一点,并且应该足够快:
MERGE INTO orgs o
USING (SELECT o.id,
greatest(o.salary - greatest(0, f.flag - nvl(sum(o.salary) over (partition by o.organisation_name order by o.priority rows between unbounded preceding and 1 preceding), 0)), 0) as salary
FROM orgs o
LEFT JOIN (SELECT organisation_name, flag FROM orgs WHERE flag IS NOT NULL) f
ON (f.organisation_name = o.organisation_name)
WHERE o.priority IS NOT NULL) f
ON (f.id = o.id)
WHEN MATCHED THEN UPDATE SET o.salary = f.salary;
澄清:USING子句中的查询是通过使用窗口函数计算组织名称内的移动总数来获取更新的工资。然后我们将其合并到原始表中。
【讨论】:
【参考方案2】:要加快速度,请尝试在 PL/SQL 代码中使用 BULK COLLECT 和 FORALL 选项,或者如上所述,在 SQL 中执行。
【讨论】:
以上是关于用于更新超过 1 000 000 行的 Pl/Sql 脚本的主要内容,如果未能解决你的问题,请参考以下文章
Laravel 无法显示超过 10,000 条的 mysql 记录
尝试使用 VB 自动填充大于 300,000 行的非常大的电子表格