这始终是一项棘手的任务。事务的大小(例如为了安全回滚)受到事务日志大小的限制。事务日志不仅由您的 sql 命令填充,还由同一时刻使用 db 的其他用户的命令填充。
我建议使用以下方法之一/或组合
1. 承诺
经常提交 - 在你的情况下,我会在每个删除命令后进行一次提交
2. 增加事务日志的大小
我记得默认的 db2 事务日志不是很大。应单独计算/调整每个数据库的事务日志的大小。参考here以及更多细节here
3.存储过程
编写并调用存储过程,该过程会按块进行删除,例如:
-- USAGE - create: db2 -td@ -vf del_blocks.sql
-- USAGE - call: db2 "call DEL_BLOCKS(4, ?)"
drop PROCEDURE DEL_BLOCKS@
CREATE PROCEDURE DEL_BLOCKS(IN PK_FROM INTEGER, IN PK_TO INTEGER)
LANGUAGE SQL
BEGIN
declare v_CNT_BLOCK bigint;
set v_CNT_BLOCK = 0;
FOR r_cur as c_cur cursor with hold for
select tableky from tablename
where tableky between pk_from and pk_to
for read only
DO
delete from tablename where tableky=r_cur.tableky;
set v_CNT_BLOCK=v_CNT_BLOCK+1;
if v_CNT_BLOCK >= 5000 then
set v_CNT_BLOCK = 0;
commit;
end if;
END FOR;
commit;
END@
4. 使用替换选项导出+导入
在某些情况下,当我需要清除非常大的表或只保留少量记录(并且没有 FK 约束)时,我会使用导出 + 导入(替换)。替换导入选项具有很强的破坏性 - 它会在开始导入新记录之前清除整个表(参考db2 导入命令),所以请先确定您在做什么并进行备份。对于此类敏感操作,我创建了 3 个脚本并单独运行每个脚本:备份、导出、导入。这是导出的脚本:
echo '===================== export started ';
values current time;
export to tablename.del of del
select * from tablename where (tableky between 1 and 1000
or tableky between 2000 and 3000
or tableky between 5000 and 7000
) ;
echo '===================== export finished ';
values current time;
这是导入脚本:
echo '===================== import started ';
values current time;
import from tablename.del of del allow write access commitcount 2000
-- !!!! this is IMPORTANT and VERY VERY destructive option
replace
into tablename ;
echo '===================== import finished ';
5. 截断命令
Db2 在版本 9.7 中引入了 TRUNCATE 语句,其中:
删除表中的所有行。
基本上:
TRUNCATE TABLE <tablename> IMMEDIATE
我没有在 db2 中使用 TRUNCATE 的经验,但在其他一些引擎中,该命令非常快并且不使用事务日志(至少不以通常的方式)。请检查所有详细信息here or in 官方文档。作为解决方案4,这个方法也是具有很强的破坏性 - 它会清除整个表所以在发出命令之前要非常小心。首先执行表/数据库备份,确保之前的状态。
请注意何时执行此操作
当数据库上没有其他用户时,或者通过锁定表来确保这一点。
关于回滚的注意事项
在事务数据库(如db2)中,回滚可以将数据库状态恢复到事务开始时的状态。在方法1,3和4中这是无法实现的,所以如果您需要“恢复到原始状态”功能,确保这一点的唯一选择是方法nr。 2-增加事务日志.