1

我已经搜索了一段时间,找不到这个。我正在使用 Oracle 并且有一个类似于以下的 For 循环:

BEGIN
  FOR YEARIDs IN (SELECT DISTINCT YEARID From MyTable)
  LOOP
    UPDATE (
              SELECT    ......
            )
    SET     MyFlag = 1;
    COMMIT;  -- Added
  END LOOP;
END;

AutoCommit 已打开,但在整个 FOR 循环完成之前似乎不会发生提交。因此,我在上面的代码中添加了 Commit 语句。这会导致任何意外结果,还是违反任何最佳实践?(即,当 AutoCommit 打开时,我不应该明确调用提交吗?)

谢谢,斯科特

编辑:哎呀...我使用 Oracle 11g 和 Oracle SQL Developer 作为客户端。

编辑:谢谢你的回复,到目前为止。在查询运行的时间点,正在生成和调整数据。不应有其他连接尝试访问数据。至于为什么我如此频繁地提交,在开发过程中,我对数据的子集运行查询并且查询运行得很好。该表包含大约 1400 万条记录,我正在测试大约 100k 条记录。该查询相当复杂,针对该子集运行大约 5 分钟。当我开始对整个表运行它时,查询运行了 14 多个小时并且无法更新任何记录。我的理论是持有这么多撤消信息可能会消耗开发服务器上的所有可用资源。如果我经常提交,那么撤消信息可以被释放和重用。是的,它很慢。但是如果查询真的会完成,即使需要一整夜,也可以将其移至测试服务器。(并且性能调整可以在以后进行。)这个截止日期早就过去了。(在错过最后期限后,我被请来帮忙。我的专业领域不是甲骨文。)

4

2 回答 2

7

在循环内提​​交通常是一个坏主意(允许任何工具自动提交也是如此)。

在循环内提​​交会使编写可重新启动的代码变得更加困难。如果在 3 次迭代后遇到错误会发生什么?您现在已经成功提交了 2 个UPDATE语句的结果。据推测,您需要找出更新了哪些行并编写代码来反转更新,或者您必须添加代码以避免尝试更新这两个成功yearid值的数据。这当然是可能的。但这涉及编写一堆代码来跟踪您的进度,并且通常会使您的代码更加复杂。

在循环内提​​交会使您的代码慢得多。提交通常是一项相当昂贵的操作。因此,循环执行它通常是一个坏主意。如果您只有几十个循环迭代,那么问题就不大了。但是,如果您有数百或数千次迭代,您很容易最终将大部分时间都花在提交上。

在循环内提​​交会大大增加导致 ORA-01555 错误的风险。您的查询MyTable需要读取一致的数据视图。但是,如果您在循环内提​​交,您就是在告诉 Oracle 您的会话不再需要旧UNDO数据。如果 Oracle 碰巧清除UNDO了循环后续迭代所需的数据,则会出现错误。然后你又要处理不可重新启动的代码,你已经成功地经历了 N 次迭代,但你不知道哪些年份已经被处理或哪些需要被处理。

在循环内提​​交会产生数据一致性问题。例如,如果某个其他会话正在运行报告,这些报告很容易看到部分更新的数据,这通常意味着数据将不一致。如果 3 年的数据发生了变化,而其他年份没有发生变化,则很难理解报告,并且人员(或流程)很容易做出错误的决定。

在循环内提​​交也会降低代码的可重用性。如果您的代码包含提交(或回滚,而不是您在块内建立的保存点),则它不能被任何其他不希望其事务提交的代码调用。这导致人们试图在没有事务控制的情况下重新实现您的逻辑,或者错误地违反事务完整性,这不可避免地导致他们构建引入数据一致性问题的应用程序。

于 2013-04-02T20:30:16.183 回答
0

DBMS_PARALLEL_EXECUTE 是奇妙的功能之一,我们一直在使用具有 mn 行且没有任何中断的大型表。

这确保了高可用性、可重新启动性并利用了并行处理。

看到这个 https://oracle-base.com/articles/11g/dbms_parallel_execute_11gR2

我认为在定期间隔(比如 1000 - 10000 行,取决于行大小)之后提交数据没有任何问题。事实上,对于大数据迁移/回扫,建议分块并提交以避免'ORA-01555 Snapshot Too Old'。

这也可以防止在基表上锁定更长的时间。

正如其他人所评论的那样,这里不需要“自动提交”......

于 2016-10-16T22:37:28.333 回答