oracle如何优化海量更新
Posted
技术标签:
【中文标题】oracle如何优化海量更新【英文标题】:How to optimise massive updates in oracle 【发布时间】:2019-03-02 17:19:12 【问题描述】:我需要在 oracle 中更新一个包含 ~40*10^6 记录的巨大表。 将被修改的行数大约为 10^7。 确定将要更新的行的查询很复杂并且涉及连接。仅识别将要更新的行的 id 就需要 30 分钟。
Select p.some_id from
(select some_id, col2,col3 from t1 where col2='someVulue' and col3 ='someValue') p
inner join (select some_id from t2 where t2.col3='someValue') q
on p.some_id=q.some_id
现在为了进行更新,我需要添加另一个 join 或使用 IN 语句,这会使事情变得更糟。
有没有办法并行化这个? 还是进行批量更新(每次更新 25*10^4 行)?有没有办法告诉 oracle 只更新前 n 行?然后是 n->2n,然后是 2n->3n ... ?
该脚本将在 生产 环境中运行,因此无法进行表重建。
更新包括将布尔列设置为 true。(如果这有帮助)
【问题讨论】:
这是否会在服务窗口期间完成,以便您需要不惜一切代价快速运行?或者当有活跃用户时查询会运行吗?在一个事务中更新所有行的并行方法将非常昂贵,因此在使用数据库时不推荐。在这种情况下,我宁愿在一次选择中找到 ID 并将它们复制到临时表中。然后我会分批处理它们,每批之间都有一个提交。这意味着获得 ID 的选择成本很高,然后进行一些相当便宜的更新。 有关更新的更多详细信息可能会有所帮助。您只发布了select
查询。我想我理解 in
子查询和 Jon Heller 的 merge
建议可能会有所帮助,或者 update (select...join...) set...
,然后是 dbms_parallel_execute
或普通 /*+ parallel */
用于并行方面。
【参考方案1】:
执行大规模更新的最快方法是使用并行 DML,如下所示:
alter session enable parallel dml;
update /*+ parallel(16) */ some_table set some_column = 1;
commit;
有很多小问题需要注意。您需要有企业版。 UPDATE
将在表上获得排他锁,因此其他人将无法同时写入表。您的系统必须有足够的资源来支持大型 UPDATE
,例如足够的重做、撤消、CPU、I/O 和配置合理的系统。
(您可能希望将我示例中的数字 16 更改为适合您的系统的数字。如果您想最大化性能,但可能以牺牲其他进程为代价,请将数字设置为等于该数字核心。)
Oracle 并行性很棒,但并没有真正优化。它使系统更努力地工作,而不是更智能。在尝试并行之前,您可能需要查看UPDATE
中使用的 SQL 语句。您可能还想尝试改用MERGE
。 MERGE
语法一开始有点棘手,但它可以帮助避免重复连接,并允许哈希连接运行更快,以更改大部分行。
【讨论】:
【参考方案2】:有几种方法。 1)将您的查询分成小块。 例如:按主键拆分表或添加子句 2)如果你需要经常运行这个,你可以考虑分区表,然后运行更新并行 3)检查您的索引是否正确构建 顺便说一句,如果 30 分钟不会导致您的应用程序出现性能问题或阻止其他查询,我认为这不是很长的时间,这是很正常的。
【讨论】:
【参考方案3】:进行批量更新(每次更新 25*10^4 行)?有没有办法告诉 oracle 只更新前 n 行?然后是 n->2n,然后是 2n->3n,这里 n 为 10
for loop i in 1..10
loop
update table1
set column_val=x
where rowid in (select rowid from table1
where rownum >= (((i-1) * (25*10^4))+1) and rownum <= i*(25*10^4)
);
end loop;
【讨论】:
以上是关于oracle如何优化海量更新的主要内容,如果未能解决你的问题,请参考以下文章