Oracle - 故障转移 table 或查询操作

Oracle - Failover table or query manipulation

在 DWH 环境中,出于性能原因,我需要将视图具体化为 table 100 列和 50.000.000 条记录。每天插入约 60.000 条新记录,并对现有记录执行约 80.000 条更新。根据决定,我不允许使用物化视图,因为架构师声称这会导致性能问题。我不能再争论这个案子了,这是一个不可撤销的决定,我必须接受。 所以我想在晚上每天满载,例如截断和插入。但如果作业失败,table 可能不为空,但必须包含上次成功填充的数据。 因此,我想到了类似故障转移 table 的方法,如果出现任何问题,将使用它来代替:

如果v_load_job_failed 那么failover_table 其他 regular_table

是否会根据预定义条件使用故障转移 table 之类的东西来代替另一个 table?类似于在执行前重写或操作 select 查询的触发器?

我知道这是一种肮脏的解决方法。

物化视图只是一组具有底层 table 的元数据,您没有理由不能以类似于物化视图内部机制的方式维护 table。

我建议将 MERGE 语句用作单个查询而不是 truncate/insert。它要么完全成功,要么回滚以保持以前的数据完好无损。 60,000条新记录和80,000条修改记录并不多。

我认为,如果您至少从一个简单的单一 SQL 语句开始,然后看看它对您有何作用,您就不会出错。如果您确实决定采用多步骤流程,那么请确保它在任何可能在中途出错的阶段自动恢复自身——这可能会成为一个棘手的问题。

如果您有 space 的(短暂)双重存储时间,我建议

1) 克隆现有 table(所有索引、授权等)但名称带有 _TMP
2) 加载_TMP
3) 将 base table 重命名为 _BKP
4) 重命名 _TMP 以匹配 Base table
5) 将 _BKP 重命名为 _TMP
6) T运行cate _TMP

预计到达时间:#1 将是 "one time"; 2-6 将成为日常脚本的一部分。

这一切都假设 (1) 检测所有新记录和所有更新记录以及 (2) 使用 MERGE (INSERT+UPDATE) 将这些更改的记录整合到基础 table 中的性能是 "on par"满载。

(就我个人而言,无论如何我都倾向于完全加载方法;当有人调整并入视图定义的参考值并更改所有记录的值时,您会发现自己要等待一周更新50,000,000条记录。满载方式完全消除这种顾虑)

综上所述,应该注意的是,如果正确定义了 MV,则 MV 刷新方法在各个方面都与此方法相同,除了: 1)更简单/更少移动的部件 2) 更透明(SQL of view def 附加到 MV,而不是埋在某些 PL/SQL 包或某处的 .sql 脚本中) 3) 没有 "blip" 的时间,在 table 重命名之间,查询/进程可能看不到 table 并失败。

预计到达时间:可以使用 "partition magic" 以多种方式完成此操作,从而避免 "blip" 的时间丢失数据或 table。

例如,您可以有偶数日和奇数日分区。在奇数日,插入数据(不提交),然后 t运行cate 偶数日(同时删除旧日并公开新日)。但这值得复杂吗?您需要添加一列作为分区依据,并处理 re运行s 的复杂性——如果您的逻辑不严密,您最终会 t运行cating 刚刚加载的数据.但是,这确实可以防止出现问题

一种确实避免了任何 "blip" 并且不太容易 "whoops" 的方法: 1) 添加始终具有值 1 的 "DUMMY" 列。 2) 创建 _TMP table(也有 "DUMMY" 列)并按 DUMMY 列分区(因此所有行都进入同一分区)
-- 每日剧本 -- 3) 加载 _TMP table 4) _TMP table 与主库 table 的交换分区 WITHOUT VALIDATION INCLUDING INDEXES

重复一下:如果资源使用和MV-refresh一样,这些方法都是等价的;它们只是更复杂,并且往往会让开发人员感到 "savvy" 需要解决已经解决的问题。

最后的说明 - 解决 David Aldridge - 首先,每日刷新 tables 不应该启用日志记录。在恢复方案中,只需确保在基础 table 恢复后,您有 运行 刷新脚本的步骤。

在性能方面,里程数会有所不同;但根据我的经验,识别和修改 changed/inserted 行的复杂性可能会变得非常棘手(在某些时候,有人会对您的脚本没有考虑到的基础数据做一些事情;要么产生不正确的结果,要么产生性能障碍) . DWH 环境倾向于适应这样的过程,几乎没有问题。 Unless/until 事实证明,完全刷新的开销超出了系统可以容忍的范围,这通常是最简单的 "set-it-and-forget-it" 方法。

关于这一点,如果数据可以在逻辑上分为"live rows which might be updated"和"historic rows that will never be updated",你可以想出一个分区方案和过程,只truncates/reloads "live" 每天的数据。