在 oracle 中更新大 table 而不会降低基数 table
Updating a big table in oracle without drooping the base table
我正在尝试更新 sql 查询中的 table。我的 table 包含半百万条记录,大约需要 10 分钟的时间。这是我的开发环境。
当我使用 UAT 或 prod 时,table 那里将包含比开发环境更多的数据。更新整个 table 然后提交将消耗大量内存。谁能建议我一个批量更新 table 的好方法。
我已经通过网络,我找到的最常见的解决方案是通过 "create new_table as select (update ) from old_table." 创建一个新的 table 但在我的情况下我不能使用它,因为在我的产品环境中我不能删除并创建 table.
谢谢
Ankit。
如果 "Create Table as Select" 不是一个选项,那么最好的办法是编写一个 PL/SQL 存储过程来利用 BULK COLLECT
和 FORALL
语句。这是一个很好的起点http://www.oracle.com/technetwork/issue-archive/2012/12-sep/o52plsql-1709862.html
CTAS 仍然是最快的选择。请记住,您不需要删除原始 table;您可以重命名并保留它以使您的管理满意。
否则,您可以根据自己的情况选择一些选项。
如果:
- 关注的只是经过的时间;和
- 您拥有企业版许可证;和
- 生产还有 CPU 秒
那你可以考虑Parallel DML来解决问题
alter session enable parallel dml;
update /*+ parallel (your_table) */ your_table
set ..
如果您只有标准版但使用的是 11gR2 或更高版本,您可以使用 DBMS_PARALLEL_EXECUTE 包来并行 运行 一个 PL/SQL 作业。关于 CPU 的注意事项仍然适用。
除此之外,你应该看看 WHERE 子句的效率。 UPDATE 也是一种扫描,可以像任何其他查询一样进行调整。
将更新分成批次会使总耗时更长。当然会,你正在做更多的工作。对单个更新语句进行批处理的主要优点是,通过提交记录块,如果任务中途失败,我们不会丢失工作。如果存在区分更新记录的机制(由此任务更新的状态或日期列 而不是其他 ),这只是一个优势。如果你没有这样的标志,你 运行 绝对有损坏 table 的风险。
最简单的批处理方法是简单的 PL/SQL 循环。假设您有一百万行要更新:
begin
for idx in 1..100 loop
update your_table
set whatever = whatever * 1.1
, status = 'touched'
where status != 'touched'
and rownum <= 10000;
commit;
end loop;
end;
显然你需要一些错误处理,也许是日志记录等。但是要抵制 bulk collect
、forall
等的诱惑,除非你的更新规则足够复杂以至于它们需要程序逻辑。
我正在尝试更新 sql 查询中的 table。我的 table 包含半百万条记录,大约需要 10 分钟的时间。这是我的开发环境。
当我使用 UAT 或 prod 时,table 那里将包含比开发环境更多的数据。更新整个 table 然后提交将消耗大量内存。谁能建议我一个批量更新 table 的好方法。
我已经通过网络,我找到的最常见的解决方案是通过 "create new_table as select (update ) from old_table." 创建一个新的 table 但在我的情况下我不能使用它,因为在我的产品环境中我不能删除并创建 table.
谢谢 Ankit。
如果 "Create Table as Select" 不是一个选项,那么最好的办法是编写一个 PL/SQL 存储过程来利用 BULK COLLECT
和 FORALL
语句。这是一个很好的起点http://www.oracle.com/technetwork/issue-archive/2012/12-sep/o52plsql-1709862.html
CTAS 仍然是最快的选择。请记住,您不需要删除原始 table;您可以重命名并保留它以使您的管理满意。
否则,您可以根据自己的情况选择一些选项。
如果:
- 关注的只是经过的时间;和
- 您拥有企业版许可证;和
- 生产还有 CPU 秒
那你可以考虑Parallel DML来解决问题
alter session enable parallel dml;
update /*+ parallel (your_table) */ your_table
set ..
如果您只有标准版但使用的是 11gR2 或更高版本,您可以使用 DBMS_PARALLEL_EXECUTE 包来并行 运行 一个 PL/SQL 作业。关于 CPU 的注意事项仍然适用。
除此之外,你应该看看 WHERE 子句的效率。 UPDATE 也是一种扫描,可以像任何其他查询一样进行调整。
将更新分成批次会使总耗时更长。当然会,你正在做更多的工作。对单个更新语句进行批处理的主要优点是,通过提交记录块,如果任务中途失败,我们不会丢失工作。如果存在区分更新记录的机制(由此任务更新的状态或日期列 而不是其他 ),这只是一个优势。如果你没有这样的标志,你 运行 绝对有损坏 table 的风险。
最简单的批处理方法是简单的 PL/SQL 循环。假设您有一百万行要更新:
begin
for idx in 1..100 loop
update your_table
set whatever = whatever * 1.1
, status = 'touched'
where status != 'touched'
and rownum <= 10000;
commit;
end loop;
end;
显然你需要一些错误处理,也许是日志记录等。但是要抵制 bulk collect
、forall
等的诱惑,除非你的更新规则足够复杂以至于它们需要程序逻辑。