使用oracle上的大量数据优化删除查询

时间:2012-03-20 07:46:24

标签: sql optimization plsql oracle9i

我正在研究oracle 9i。我有一个包含135,000,000条记录的表,分区每个分区大约有。 10,000,000行。所有索引和一切。

我需要从中删除大约70,000,000行作为新业务要求。

所以我创建了要删除的行的备份作为单独的表。

Table1 <col1, col2........> -- main table (135,000,000 rows)

Table2 <col1, col2........> -- backup table (70,000,000 rows)

尝试了以下删除查询。

Delete from table1 t1 where exists (select 1 from table2 t2 where t2.col1 = t1.col1)

但需要无限时间。

然后尝试了

declare
cursor c1 is 
select col1 from table2;
c2 c1%rowtype;
cnt number;
begin
cnt :=0;
open c1;
loop
    fetch c1 into c2;
    exit when c1%notfound;

    delete from table1 t1 where t1.col1 = c2.col1;
    if cnt >= 100000 then
        commit;
    end if;
    cnt:=cnt+1;
end loop;
close c1;
end;

即使它已经运行了超过12个小时。但仍未完成。

请注意,table1上有多个索引,table2上有col1索引。分析所有表和索引。

请告知是否有任何优化方案。

谢谢你们。

4 个答案:

答案 0 :(得分:4)

删除所有索引(备份create语句) 使用用于构建备份表的select语句,从中创建DELETE命令 重新创建所有索引

答案 1 :(得分:4)

我记得早些时候面对这个问题。在这种情况下,我们采取这样做,因为它比任何其他删除操作更快地运行:

1)创建另一个结构相同的表

2)将要保留的记录插入新表中(使用直接路径插入来加快速度)

3)放下旧桌子

4)重命名新表

答案 2 :(得分:1)

你说表是分区的。您是否打算删除某些分区中的所有数据?如果是这样,您应该能够简单地删除具有您想要删除的7000万行的7个分区。不过,我假设您的问题并非如此简单。

如果您可以进行临时提交,这意味着您并不关心事务一致性,那么最有效的方法可能就像

一样。
CREATE TABLE rows_to_save
    AS SELECT *
         FROM table1
        WHERE <<criteria to select the 65 million rows you want to keep>>

TRUNCATE TABLE table1;

INSERT /*+ append */
  INTO table1
SELECT *
  FROM rows_to_save;

除非创建备份表,否则简单发布DELETE语句

会更有效率
DELETE FROM table1
 WHERE <<criteria to select the 70 million rows you want to keep>>

在运行DELETE之前,您还可以从删除或禁用索引和约束中受益。

答案 3 :(得分:0)

我会回答这个问题,假设过滤掉备份表的成本更低,但是使用你用来填充备份表的标准的否定可能会更便宜。

1)创建一个具有相同结构的新表。没有索引,约束或触发器。

2)

    select 'insert /*+ append nologging */ into new_table partition (' || n.partition_name || ') select * from old_table partition (' || o.partition_name || ') minus select * from bak_table partition (' || b.partition_name || ');'
    from all_tab_partitions o, all_tab_partitions n, all_tab_partitions b
    where o.partition_no = all( n.partition_no, b.partition_no)
      and o.table_name = 'OLD_TABLE' and o.table_owner = 'OWNER'
      and n.table_name = 'NEW_TABLE' and n.table_owner = 'OWNER'
      and b.table_name = 'BAK_TABLE' and b.table_owner = 'OWNER';
    -- note, I haven't run this it may need minor corrections in addition to the obvious substitutions

3)验证并运行上一个查询的结果

4)根据需要构建索引,约束和触发器

与删除相比,这避免了大量的重做和撤消。 附加提示直接路径插入 没有记录进一步减少重做 - 请确保您之后备份 利用您的分区将工作分解为可以在较少的传递中排序的块

使用并行插入+并行选择可能会更快,但可能没有必要。如果没有插入和“alter session enable parallel dml”

,请不要进行并行选择