2

我有一张表,它有大约 1.8 亿条记录和 40 个索引。一个夜间程序,将数据加载到此表中,但由于某些业务条件,我们只能删除并将数据加载到此表中。nightly 程序将从源系统中带来新记录或对表中现有记录的更新。我们有有限的窗口,即大约 6 小时来完成从源系统中提取,执行业务转换并最终将数据加载到此目标表中,并准备好让用户在早上消费数据。我们面临的问题是从该表中删除需要很长时间,主要是由于表上有 40 个索引(平均每小时 70000 次删除)。我在互联网上进行了一些挖掘,并查看了以下选项

a)在删除前删除或禁用索引,然后重建索引:删除和加载数据后将数据加载到目标表的程序需要执行相当多的索引更新。由于表中数据量巨大,重建 1 个索引需要将近 1.5 小时。所以这种方法是不可行的,因为重建索引需要时间,而且我们必须为用户准备好数据的时间有限

b)使用批量删除:目前程序是根据rowid删除,一条一条删除记录如下

DELETE FROM <table> WHERE rowid = g_wpk_tab(ln_i);

g_wpk_tab 是包含要删除的 rowids 的集合,该集合通过 FOR ALL 循环读取,我每删除 50000 行进行一次中间提交。

AskTom 的汤姆在这里的讨论中说批量删除和逐行删除将花费几乎相同的时间

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:5033906925164

所以这也不是一个可行的选择

c)定期删除: AskTom 的 Tom 建议使用定期删除,甚至可能由于该表上的索引数量而需要很长时间

d) CTAS:这种方法是没有问题的,因为程序需要重新创建表,创建 40 个索引,然后继续更新,我上面提到的索引将至少需要 1.5 小时才能创建

如果您能给我提供任何其他建议,我将不胜感激。

更新:截至目前,我们决定采用https://stackoverflow.com/users/409172/jonearles建议的方法来存档而不是删除。方法是在表中添加一个标志,将要删除的记录标记为 DELETE,然后在白天运行一个 post delete 程序来删除记录。这将确保数据在正确的时间可供用户使用。由于用户通过 OBIEE 进行消费,我们计划在表格上设置内容级别过滤器以不查看存档列,这样用户就无需知道选择什么和忽略什么。

4

1 回答 1

1

并行 DML alter session enable parallel dml; , delete /*+ parallel */ ...;, commit;. 有时就是这么容易。

并行 DDL alter index your_index rebuild nologging compress parallel;。NOLOGGING 以减少在索引重建期间生成的重做量。COMPRESS 可以显着减小非唯一索引的大小,从而显着减少重建时间。如果您有多个 CPU 或多个磁盘,则 PARALLEL 还可以在重建时间上产生巨大差异。如果您还没有使用这些选项,如果将它们一起使用可以将索引重建提高一个数量级,我不会感到惊讶。然后 1.5 * 40 / 10 = 6 小时。

重新评估您的索引真的需要 40 个索引吗?这完全有可能,但创建许多索引只是因为“索引很神奇”。确保每个索引背后都有正当理由。这可能很难做到,很少有人记录索引的原因。在你四处打听之前,你可能想收集一些信息。打开索引监视以查看真正使用了哪些索引。并且即使使用了索引,也可以通过 v$sql_plan 来查看它是如何使用的。索引可能用于特定语句,但另一个索引也可以正常工作。

归档而不是删除 而不是删除,只需设置一个标志来将行标记为已归档、无效、已删除等。这将避免索引维护的直接开销。暂时忽略这些行,稍后让其他工作删除它们。这样做的最大缺点是它会影响表上的任何查询。

升级可能是不可能的,但 12c 有一个有趣的新功能,称为数据库内归档。这是一种更透明的方式来完成同样的事情。

于 2013-08-01T06:25:37.437 回答