【问题标题】:DB2: Purge large number of records from tableDB2:从表中清除大量记录
【发布时间】:2019-12-18 17:04:00
【问题描述】:

我正在为 LUW 使用 DB2 9.7 FP5。我有一个有 250 万行的表,我想删除大约 100 万行,这个删除操作分布在整个表中。我正在使用 5 个删除语句删除数据。

delete from tablename where tableky between range1 and range2
delete from tablename where tableky between range3 and range4
delete from tablename where tableky between range5 and range5
delete from tablename where tableky between range7 and range8
delete from tablename where tableky between range9 and range10

在执行此操作时,前 3 次删除工作正常,但第 4 次删除失败,DB2 挂起,什么也不做。以下是我遵循的过程,请帮助我:

1. Set following profile registry parameters: DB2_SKIPINSERTED,DB2_USE_ALTERNATE_PAGE_CLEANING,DB2_EVALUNCOMMITTED,DB2_SKIPDELETED,DB2_PARALLEL_IO

2.Alter bufferpools for automatic storage.

3. Turn off logging for tables (alter table tabname activate not logged initially) and delete records

4. Execute the script with +c to make sure logging is off

删除如此大量数据的最佳做法是什么?为什么从同一个表中删除相同性质的数据时会失败?

【问题讨论】:

  • 我在博客上分享了我的经验。请参考这个link

标签: database performance db2 db2-luw


【解决方案1】:

这总是一项棘手的任务。事务的大小(例如为了安全回滚)受事务日志大小的限制。事务日志不仅是你的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 约束)时,我使用了导出 + 导入(替换)。替换导入选项非常具有破坏性 - 它会在开始导入新记录之前清除整个表(参考 of db2 import command),因此请确保您在做什么并在之前进行备份。对于此类敏感操作,我创建了 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 的经验,但在其他一些引擎中,该命令非常快并且不使用事务日志(至少不是以通常的方式)。请查看hereofficial documentation 中的所有详细信息。作为解决方案 4,此方法也非常具有破坏性 - 它会清除整个表,因此在发出命令之前要非常小心。确保先执行表/数据库备份的先前状态。

注意何时执行此操作

当 db 上没有其他用户时,或通过锁定表来确保这一点。

关于回滚的注意事项

在事务db(如db2)中回滚可以将db状态恢复到事务开始时的状态。在方法 1,3 和 4 中这是无法实现的,所以 如果您需要“恢复到原始状态”的功能,唯一可以确保这一点的选项是方法 nr. 2 - 增加事务日志

【讨论】:

    【解决方案2】:
    delete from ordpos where orderid in ((select orderid from ordpos where orderid not in (select id from ordhdr) fetch first 40000 rows only));
    

    希望这能解决您的问题 :)

    【讨论】:

      【解决方案3】:

      DB2 不太可能“挂起”——更可能是在 DELETE 操作填满事务日志后进行回滚。

      确保您在每个 DELETE 语句之后提交。如果您使用 DB2 CLP 的 +c 选项执行脚本,请确保在每个 DELETE 之间包含显式的 COMMIT 语句。

      【讨论】:

        【解决方案4】:

        删除具有数百万行的数据的最佳做法是在删除之间使用提交。在您的情况下,您可以在每个删除语句之后使用 commit。

        commit 的作用是清除事务日志并腾出空间供其他 delte 操作执行。

        或者在 5 个删除语句中使用循环并将删除语句传递给删除,在循环的一次迭代执行一次提交之后,数据库将永远不会挂起,同时您的数据将被删除。

        使用类似的东西。

        while(count<no of records)
        delete from (select * from table fetch fist 50000 records only)
        commit;
        count= total records- no of records.
        

        【讨论】:

          【解决方案5】:

          如果 SELECT WHERE FETCH FIRST 10 ROWS ONLY 可以提取少量记录,例如以 10 为一组,那么您可以将其作为输入提供给另一个脚本,然后删除这些记录。冲洗并重复...

          【讨论】:

            【解决方案6】:

            为了大家的利益,here 是我关于同一问题的 developerWorks 文章的链接。我尝试了不同的方法,而我在本文中分享的方法对我来说效果很好。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-07-22
              • 1970-01-01
              • 1970-01-01
              • 2015-11-28
              • 2022-01-01
              • 1970-01-01
              相关资源
              最近更新 更多