我的查询如下:
delete from tableA
where tableA.fk in (select id
from tableB
where tableB.column1='somevalue'
and tableB.date between date1 and date2)
;
表tableB包含近100,000,000条记录。所以
select id
from tableB
where tableB.column1='somevalue'
and tableB.date between date1 and date2
返回1,000,000条记录。结果 - 删除根本不起作用 - 回滚段的大小问题。我无法增加细分市场的规模。
如何执行?
答案 0 :(得分:6)
删除是回滚(撤消)空间使用方面最昂贵的操作,因为我们必须存储整个已删除的行(而撤消插入语句只需要数据库存储rowid)。解决问题的最简单方法是向UNDO表空间添加更多文件。
但你说
“我无法增加细分受众群的规模”
这有点令人惊讶,毕竟,这些天磁盘很便宜。也许你有一个愤怒的DBA,你害怕接近?但是你的DBA没有义务提供数据库,因此可以维护它;坦率地说,拥有一个VLDB(即使在数PB和zettabytes这样的日子里,仍然有一个数十亿行表计数),撤销空间不足也是愚蠢的。
但是,如果您不会在数据中心留下胡说八道,那么您所能做的就是更改您的代码。这是一个选择。鉴于此......
select id
from tableB
where tableB.column1='somevalue'
and tableB.date between date1 and date2
...返回100万行,因此尝试从tableA
删除太多行,您可以尝试返回较少行的子查询。出于练习的目的,我假设date1
到date2
指定的范围是30天:您需要相应地调整以下代码。
for i in 1..10 loop
delete from tableA
where tableA.fk in (select id
from tableB
where tableB.column1='somevalue'
and tableB.date between date1 + (3 * (i-1)) and date1 + (3 * i)
;
commit;
end loop
这将简单地将选择分成十个三天的块。这样做会花费更长的时间,但它不应该破坏Undo表空间。
答案 1 :(得分:3)
你想要做的是:
create table foo_bar
as select *
from tableA
where tableA.fk not in (select id from tableB where
tableB.column1='somevalue' and tableB.date between date1 and date2);
后跟原始表的截断+删除
truncate tableA
drop tableA
然后将foo_bar
重命名为tableA
alter table foo_bar rename to tableA
请注意,请务必禁用所有索引。
评论
我不能放桌子。它一直在使用。
你当然可以。您需要隐藏view
后面的表格,这只是一个虚拟功能和/或留出一些维护时间,因为您在插入时无法将数据吹走。现在,更典型的方法是将此数据推送到materialized view
,作为fact table
运行。这允许您随时修改基表(tableA),而不必担心会损害用户对物化视图的查询。
使用nologging
参数将减少正在使用的回滚量。您无法恢复使用nologging
答案 2 :(得分:2)
如果您要填写回滚段,可能是因为您的交易涉及的数据量。
我会分成几个块并提交它们,例如:
delete from tableA where tableA.fk in (
select id from (
select id from tableB where
tableB.column1='somevalue' and tableB.date between date1 and date2 and id in (select distinct fk from tableA.fk)
)
where rownum < XXXX
)
给XXXX你想要的值(10000)或其他什么,然后循环执行这个语句,不要忘记在每次迭代中提交。
您必须循环,直到delete语句返回0(受影响的行数)。
更新查询 注意,这不会提供最佳性能,但会解决回滚段问题
希望有所帮助