【问题标题】:Oracle Atomic Stored ProcedureOracle 原子存储过程
【发布时间】:2013-04-16 00:56:14
【问题描述】:

我正致力于在 Oracle 中编写一个存储过程,该过程将刷新包含非规范化数据的表。程序的概要是:

CREATE OR REPLACE PROCEDURE loadDenormalizedTable IS
BEGIN

DELETE FROM denormalizedTable;

INSERT INTO
    denormalizedTable
    (
        data
    )
SELECT DISTINCT
    data
FROM
    normalizedTables;

END;
/

我希望所有这些都发生在事务中,以便表中始终存在数据。现在删除运行并且表是空的几分钟,直到插入完成。在不停机的情况下处理这种类型的表刷新的最佳方法是什么?

【问题讨论】:

  • 在您提交之前,其他会话不会看到删除,您不应该在过程中执行此操作。所以你会看到空桌子,但没有其他人会。这是您真实程序的显着缩减版本吗?还有……你在重新发明materialized views吗?
  • 谢谢!会话问题使我绊倒了。我现在看到在刷新表时数据仍然对应用程序可见。它被削减了,因为我删除了所有实际的表和列,只是放入了占位符。不过结构是一样的。是的,这是对物化视图的重新发明,数据架构师不喜欢 MV。
  • 垫子视图有什么问题?它可以以原子方式或非原子方式刷新。并且一旦创建,所有这些工作都可以简化为单个刷新语句。我不会说我对你的数据“架构师”的看法
  • 我应该说他们不喜欢“这个项目”的 MV。我们确实有 MV,所以这不是全面反对。我不太了解决定以何种方式评论这个特定问题的决定的原因,但我会说,总的来说,这些人在他们所做的事情上都很出色。

标签: oracle stored-procedures


【解决方案1】:

默认情况下,过程将作为会话拥有的更大事务的一部分执行。正如documentation 提到的那样:

注意:一个交易可以跨越多个区块,一个区块可以包含多个交易。

按照概述的代码,在调用过程后提交之前,没有其他会话会看到您的删除插入。例如,如果您只是从 SQL*Plus 提示符执行它:

SQL> exec loadDenormalizedTable;

PL/SQL procedure successfully completed.

SQL>

...那么任何其他查看表的人仍然会看到旧数据,即使删除和插入都完成了。 (任何其他试图执行该过程,或在denormalizedTable 中插入或删除数据的人都会阻塞,但大概您只是希望其他人查询它)。一旦您发出commit,那么每个人都会看到相同的内容。

获得您描述的行为的唯一方法是在过程中手动结束事务:

CREATE OR REPLACE PROCEDURE loadDenormalizedTable IS
BEGIN

DELETE FROM denormalizedTable;

COMMIT WORK; -- makes the delete visible elsewhere

INSERT INTO
    denormalizedTable
    (
        data
    )
SELECT DISTINCT
    data
FROM
    normalizedTables;    
END;
/

您不需要在过程中间使用commit,而且您很少会或应该想要这样做,因为它会破坏原子性。

有可能你正在做的事情在你没有意识到的情况下进行了隐式提交;可能会调用另一个执行自己提交的过程或函数(不这样做的原因之一 - 它可能会产生意想不到的副作用!),或者可能是一个 DDL 语句 - 它总是会在幕后进行隐式提交,但是你无论如何都必须使用动态 SQL 来做到这一点。

另一种可能性是您实际上并未执行delete,而是您正在执行truncate。正如in the documentation 所暗示的,这将立即对其他所有人可见,而无需明确提交。不过,这也将与您提供的大纲大相径庭。

【讨论】:

  • 我仍然习惯于 Oracle 中会话的工作方式。它完全按照您的描述工作。谢谢。
【解决方案2】:

如果 Oracle 分区选项可用,那么最好、最有效的方法是使用分区交换操作。这是很多海量数据仓库中非常常见的操作。

在以下位置查看一些示例:

http://www.akadia.com/services/ora_exchange_partition.html http://gerardnico.com/wiki/database/oracle/partition_exchange_loading

例如,您可以想象拥有与 denormalizedTable 具有相同结构的第二个表。实现你的加载操作:

  • 截断 denormalizedTable2
  • 将数据插入 denormalizeTable2
  • 交换表 denormalizedTable 和 denormalizedTable2 的分区

它通常保证对正在运行的应用程序的影响最小。

【讨论】:

  • 谢谢。如果 DBA 更喜欢截断而不是删除,我会记住这一点。
猜你喜欢
  • 1970-01-01
  • 2011-01-03
  • 2011-12-29
  • 2018-12-08
  • 2020-10-13
  • 1970-01-01
  • 2014-05-26
相关资源
最近更新 更多