编辑:请回答我问的两个答案之一。我知道还有其他的选择,在另一种情况下会更好。这些其他潜在的选项(分区表,作为一个大批量删除语句不分批提交等)是不是选项在我的情况下,由于我的控制之外的事情。SQL优化问题(oracle)
我有几个非常大的表格要删除。所有的索引都有相同的外键。我需要删除所有表中的某些记录。
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
通常做了删除这样的时候,我把一个循环来通过所有的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;
然而,在一些代码,我看到了其他地方,它被放在一起单独的循环,每个删除一个。
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
所以我需要以下回答之一:
1)哪一个是更好?
2)如何找出哪个更适合我的特殊情况? (也就是说,如果这取决于我有多少表,他们是多么大等)
编辑:
我必须这样做在一个循环中,由于这些表的大小。我将从具有数亿条记录的表中删除数千条记录。这发生在一个无法承受这么长时间表锁定的系统上。
编辑:
注:我需要分批提交。数据量太大,无法在一批中完成。回滚表将使我们的数据库崩溃。
如果有一种方法可以批量提交而不是循环,我愿意听到它。否则,不要打扰说我不应该使用循环...
如果您觉得由于表的大尺寸而必须使用循环,那么您(和/或DBA)是否使用数据库引擎的分区功能来查看?这是分区帮助的“用例”之一。例如,如果您拥有10 TB的10 TB行表,那么删除分区(基于ID)比遍历数百万行更容易。 – JasDev 2009-12-03 17:43:01
是的,我们已经考虑过这个。我们已经分割了我们的数据库。但是,t1和t2(etc)表可以通过几种不同的方式访问(基于id以外的字段)。因此,任何对它们的分割都会伤害整体。 我遗漏了很多不影响我的问题的细节,但确实意味着我们无法对t1,t2等进行分区。 – 2009-12-03 18:00:00
您知道无论删除多少行,您都不会锁好桌子吧?如果您正在删除某个其他进程尝试更新的行,则只会出现锁争用,这似乎不太可能。如果有人试图更新您尝试删除的行,那么阻止该行显得非常合理。 – 2009-12-04 06:01:23