SQL优化问题(oracle)

Dav*_*ill 1 sql oracle optimization

编辑:请回答我问的两个答案中的一个.我知道在不同情况下还有其他选择会更好.这些其他可能的选项(对表进行分区,作为一个大型删除语句运行,无需批量提交等)在我的情况下不是选项,因为我无法控制.

我有几个非常大的表要删除.所有都具有索引的相同外键.我需要从所有表中删除某些记录.

table source
  id --primary_key
  import_source --used for choosing the ids to delete

table t1
  id --foreign key
  --other fields

table t2
  id --foreign key
  --different other fields
Run Code Online (Sandbox Code Playgroud)

通常在执行这样的删除时,我会组合一个循环来逐步执行所有ID:

declare
my_counter integer := 0;
begin
for cur in (
select id from source where import_source = 'bad.txt'
) loop
  begin
    delete from source where id = cur.id;
    delete from t1 where id = cur.id;
    delete from t2 where id = cur.id;
    my_counter := my_counter + 1;
    if my_counter > 500 then
      my_counter := 0;
      commit;
    end if;
    end;
  end loop;
  commit;
end;
Run Code Online (Sandbox Code Playgroud)

但是,在我在别处看到的一些代码中,它被放在一个单独的循环中,每次删除一个.

declare
type import_ids is table of integer index by pls_integer;
my_count integer := 0;
begin
select id bulk collect into my_import_ids from source where import_source = 'bad.txt'

for h in 1..my_import_ids.count
  delete from t1 where id = my_import_ids(h);
    --do commit check
end loop;
for h in 1..my_import_ids.count
  delete from t2 where id = my_import_ids(h);
    --do commit check
end loop;

--do commit check will be replaced with the same chunk to commit every 500 rows as the above query
Run Code Online (Sandbox Code Playgroud)

所以我需要以下回答之一:

1)哪个更好?

2)我怎样才能找出哪个更适合我的具体案例?(IE,如果它取决于我有多少桌子,它们有多大,等等)

编辑:

由于这些表的大小,我必须在循环中执行此操作.我将从具有数亿条记录的表中删除数千条记录.这种情况发生在一个不能长时间锁定表的系统上.

编辑:

注意:我需要批量提交.数据量太大,无法在一批中执行.回滚表将使我们的数据库崩溃.

如果有一种方法可以批量提交而不是循环,我愿意听.否则,不要说我不应该使用循环......

Lar*_*tig 7

为什么要循环?

delete from t1 where id IN (select id from source where import_source = 'bad.txt';
delete from t2 where id IN (select id from source where import_source = 'bad.txt';
delete from source where import_source = 'bad.txt'
Run Code Online (Sandbox Code Playgroud)

那是使用标准SQL.我并不特别了解Oracle,但是许多DBMS还具有基于JOIN的多表DELETE,它可以让你在一个语句中完成整个事务.


Ego*_*gov 6

大卫,如果你坚持提交,你可以使用以下代码:

declare
  type import_ids is table of integer index by pls_integer;
  my_import_ids import_ids;
  cursor c is select id from source where import_source = 'bad.txt';
begin
  open c;
  loop
    fetch c bulk collect into my_import_ids limit 500;
    forall h in 1..my_import_ids.count
      delete from t1 where id = my_import_ids(h);
    forall h in 1..my_import_ids.count
      delete from t2 where id = my_import_ids(h);
    commit;
    exit when c%notfound;
  end loop;
  close c;
end;
Run Code Online (Sandbox Code Playgroud)

该程序以500行的形式获取ID,删除并提交每个部分.它应该比逐行处理快得多,因为bulk collectforall可以作为单个操作(在数据库的单次往返中),从而最大限度地减少上下文切换的次数.有关详细信息,请参阅批量绑定,Forall,批量收集.