我正在编写Oracle中的存储过程,它将刷新包含非规范化数据的表。该程序的大纲是:
CREATE OR REPLACE PROCEDURE loadDenormalizedTable IS
BEGIN
DELETE FROM denormalizedTable;
INSERT INTO
denormalizedTable
(
data
)
SELECT DISTINCT
data
FROM
normalizedTables;
END;
/
我希望所有这些都发生在一个事务中,以便表中始终有数据。现在,删除运行并且表空为几分钟,直到插入完成。在没有任何停机时间的情况下处理此类表刷新的最佳方法是什么?
答案 0 :(得分:1)
如果Oracle分区选项可用,那么最好也是最有效的方法是使用分区交换操作。这是在许多大型数据仓库中完成的非常常见的操作。
请参阅以下示例:
http://www.akadia.com/services/ora_exchange_partition.html http://gerardnico.com/wiki/database/oracle/partition_exchange_loading
例如,您可以想象第二个表具有与denormalizedTable相同的精确结构。要实现加载操作:
它通常可以保证对正在运行的应用程序产生最小的影响。
答案 1 :(得分: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暗示的那样,如果没有明确的提交,那么其他所有人都可以立即看到这一点。这也与你提供的大纲有很大的不同。