在Oracle BIG表上删除缓慢

时间:2013-07-31 19:05:40

标签: oracle oracle10g

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

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

b)使用批量删除:目前程序会根据rowid删除并逐个删除记录,如下所示

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

g_wpk_tab是保存要删除的rowid的集合,通过FOR ALL循环读取,并且每50000行删除一次中间提交。

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

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,然后在白天运行一个删除后的程序来删除记录。这将确保在适当的时间为用户提供数据。由于用户通过OBIEE消费,我们计划在表格上设置内容级别过滤器,而不是查看归档列,以便用户无需知道选择什么和忽略什么。

1 个答案:

答案 0 :(得分: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个索引吗?这完全有可能,但只有因为“索引是魔术”才能创建许多索引。确保每个索引背后都有正当理由。这可能很难做到,很少有人记录索引的原因。在你四处询问之前,你可能想收集一些信息。打开index monitoring以查看实际使用的索引。即使使用索引,也可以通过v $ sql_plan查看它的使用方法。索引可能用于特定语句,但另一个索引也可以起作用。

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

升级可能无从谈起,但12c有一个名为in-database archiving的有趣新功能。这是一种更透明的方式来完成同样的事情。