【问题标题】:Oracle: do Truncates maintain Atomicity within a transaction?Oracle:截断是否在事务中保持原子性?
【发布时间】:2025-12-20 12:10:12
【问题描述】:

Oracle 10g -- 由于与 9i 数据库的兼容性问题,我正在使用 INSERT INTO...SELECT 语句通过 10g 数据库(供 11g 数据库使用)通过运行每个15分钟。我注意到 TRUNCATE 语句比 DELETE 语句快得多,并且已经读到 DELETE 语句的“缺点”是它们永远不会降低表的高水位线。我对这些数据的使用纯粹是只读的——永远不会针对有问题的表发出 UPDATE 和 INSERT。

鉴于上述情况,我想避免我的“工作”数据库 (Oracle 11g) 尝试从我的暂存数据库 (10g) 上的表中读取数据的情况,该表在一段时间内为空,因为 TRUNCATE 直接发生9i 数据库中的 INSERT INTO...SELECT 需要几分钟才能完成。

所以,我想知道这是否是 Oracle 在事务中处理 TRUNCATE 的方式,或者是否执行并提交了整个操作,尽管 TRUNCATE 无法回滚?或者,换一种说法,从外部 SELECT 的角度来看,如果我在事务中的表上包装 TRUNCANTE 和 INSERT INTO...SELECT,那么从表中读取的外部 SELECT 表会不会显示为空?

【问题讨论】:

  • TRUNCATE 语句会导致隐式提交。因此,紧跟在TRUNCATE 之后,启动查询表的事务的其他会话将看到它为空,直到使用INSERTCOMMIT 将行添加到表中。
  • 不,他们没有。截断是 DDL 语句并且 DDL 总是提交。截断只是删除整个表的段并创建一个新段。此操作还会使库缓存中针对此表的所有执行计划无效。

标签: database oracle oracle11g transactions oracle10g


【解决方案1】:

一旦一个表在事务中被截断,您就不能在同一个事务中对该表执行任何其他操作;您必须先提交(或回滚)事务,然后才能再次使用该表。或者,截断表可能会有效地终止当前事务。无论哪种方式,如果您使用 TRUNCATE,当表被截断(空)但 INSERT 操作尚未完成时,您将有一个窗口。这不是您想要的,但它是 Oracle 提供的。

【讨论】:

  • 我想知道如何成为中间数据库(10g 数据库)的优秀“客户”。从您上面的回答来看,我不能在每 15 分钟的工作中使用 TRUNCATE,因为我不能在未知的时间段内(或根本没有)让表为空。但是,如果我有一份每天在午夜运行一次的工作,那么中间数据库的“健康”是否会有一些整体优势,当时不太可能有人会使用最终应用程序来执行 TRUNCATE + INSERT INTO ...在桌子上选择?这会有效地至少每天重置一次表高水位线吗?还有其他好处吗?
  • 你能做一个三桌洗牌吗?创建要加载的表New_TableA,然后加载它。然后,您可以进行随机播放,将当前 TableA 重命名为 Old_TableA,将 New_TableA 重命名为 TableA。然后您可以删除 Old_TableA。至少,这将没有完全填充的 TableA 的时间缩短到两个重命名操作之间的时间(我假设 Oracle 有)。 --如果表上有主键或外键等,这可能会出现问题;你可能需要做一些花哨的步法来保持正确。如果这仅用于在系统之间传输数据,您可能没问题。
【解决方案2】:

您可以进行分区交换。在临时表中有 2 个分区; p_OLD 和 p_NEW。

  1. 在插入之前进行分区交换“新”->“旧”并截断“新”分区。 (此时如果您从表格中选择,您会看到旧数据)
  2. 将数据插入“新”分区,截断“旧”分区。 (此时您会看到新数据)。

通过这种方法,您的桌子对旁观者来说永远不会是空的。

为什么需要 3 个 Oracle 环境?

【讨论】: