自动提交打开时显式提交是否正常?

时间:2013-04-02 20:15:28

标签: sql oracle

我一直在寻找一段时间,却找不到这个。我正在使用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万条记录,我正在测试大约10万条记录。该查询相当复杂,并且针对该子集在大约5分钟内运行。当我针对整个表运行它时,查询运行超过14小时并且无法更新任何记录。我的理论是,保留那么多撤消信息可能会消耗开发服务器上的所有可用资源。如果我经常提交,则可以释放和重用该撤消信息。是的,它很慢。但是如果查询实际上已经完成,即使它需要整晚,那么它也可以移动到测试服务器。 (并且可以在以后完成性能调整。)这个问题的截止日期早已过去。 (在错过截止日期之后,我被带到了帮助中。而且我的专业领域不在于Oracle。)

2 个答案:

答案 0 :(得分:7)

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

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

在循环内部提交会使代码更慢。承诺通常是相当昂贵的操作。因此,在循环中执行它通常是一个坏主意。如果你只有几十个循环迭代,这不是一个问题。但是如果你有数百或数千次迭代,你很容易就会花费大部分时间来提交。

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

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

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

答案 1 :(得分:0)

DBMS_PARALLEL_EXECUTE是一个非常棒的功能,我们一直在使用具有mn行而没有任何中断的大型表。

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

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

我认为在定期间隔(例如1000 - 10000行,取决于行大小)之后提交数据没有错。事实上,对于大数据迁移/反向扫描,它建议使用chunk并承诺避免ORA-01555快照太旧了。

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

正如其他人评论的那样,' AutoCommit'这里没必要......