【问题标题】:db2 stored procedure - trouble batching DELETE statementsdb2 存储过程 - 批处理 DELETE 语句时遇到问题
【发布时间】:2014-03-05 11:41:37
【问题描述】:

我只写了几天的 DB2 过程,但试图对给定的表执行“批量删除”。我的预期逻辑是:

  • 打开光标
  • 穿过它直到 EOF
  • 在每次迭代中发出 DELETE

为了简化这个问题,假设我只想在 WHILE 循环完成后(即,一旦光标到达 EOF)发出一个 COMMIT(所有 DELETE)。所以给出下面的代码示例:

CREATE TABLE tableA (colA INTEGER, ...)


CREATE PROCEDURE "SCHEMA"."PURGE_PROC"
(IN batchSize INTEGER)
LANGUAGE SQL
SPECIFIC SQL140207163731500
BEGIN

   DECLARE tempID             INTEGER;
   DECLARE eof_bool           INTEGER DEFAULT 0;
   DECLARE sqlString          VARCHAR(1000);
   DECLARE sqlStmt            STATEMENT;
   DECLARE myCurs             CURSOR WITH HOLD FOR sqlStmt;
   DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET eof_bool = 1;

   SET sqlString = 'select colA from TableA';
   PREPARE sqlStmt FROM sqlString;

   OPEN myCurs;
   FETCH myCurs INTO tempID;
   WHILE (eof_bool = 0) DO
        DELETE FROM TableA where colA = tempID;
        FETCH myCurs INTO tempID;
   END WHILE;

   COMMIT;
   CLOSE myCurs;

END

注意:在我的真实场景中:

  • 我不会从表中删除所有记录,只是根据一些附加条件删除某些记录;和
  • 我计划在 WHILE 循环的每 N# 次迭代(比如 500 或 1000)中执行一次 COMMIT,而不是像上面那样一团糟;和
  • 我计划删除多个表,而不仅仅是这个;

但再次,为了简化,我测试了上面的代码,我看到的是 DELETE 似乎被一一提交。我基于以下测试:

  • 我用(比如 50k)条记录预加载了表格;
  • 然后运行 ​​purge storedProc,运行大约需要 60 秒;
  • 在此期间,从另一个 sql 客户端,我不断地“SELECT COUNT(*) FROM tableA”并看到计数逐渐减少。

如果一次提交所有 DELETE,我希望看到记录计数 (*) 仅在 ~60 秒结束时从 0 下降。这就是我在为 Oracle 或 SQLServer 编写的类似 SP 中看到的。

这是 Win2003 上的 DB2 v9.5。

任何想法我错过了什么?

【问题讨论】:

  • 你的代码一次提交,而不是一个一个提交。你怎么知道代码是一个一个提交? select WITH UR 会告诉你修改的行,但没有提交。
  • 我认为您的问题必须更加准时,因为这似乎是一个意见问题,这里不适合提出这样的问题。你必须说出你的问题,展示你做了什么,并清楚地解释你想要得到什么。
  • 正如我在下面告诉 Mustaccio 的那样,我猜你们是对的,它正在执行一次提交。一些背景知识...我在 Oracle、SQLServer 和 DB2 中具有相同的数据库结构。我有一个基于 jdbc 的清除应用程序,我可以针对所有 3 个运行它。我现在正在为 3 个 dbs 中的每一个编写一个 storedProcedure 替代方案。 Oracle 和 SQLServer SP 的性能比 JDBC 提高了 10 倍。 DB2 SP 只显示了 2 倍的改进。这种令人惊讶的缓慢,加上看到(我现在意识到是未提交的读取)记录数减少了 1 比 1,这让我认为正在发生额外的提交。
  • 嗯...如果可能的话,我仍然建议以基于集合的方式删除(即,不在光标中),因为这应该有助于进一步加快速度。显然,您仍然需要发出多个DELETEs,但有一些方法可以解决这个问题 - 例如将 id 插入临时表或类似的。仅 50k 条记录的 60 秒非常慢 - 您正在直接读取表(或可能是索引),因此您的大部分时间都花在循环逻辑和逐行删除。
  • 我同意@Clockwork-Muse 的观点,在任何 RDBMS 上都会首选一套基础解决方案。 50K 对于单次提交来说应该不是问题。 100K 甚至。 1M 可能是个问题。

标签: sql loops cursor db2 commit


【解决方案1】:

需要指出的是,你删除的是“光标外”

使用光标删除的正确方法是使用“定位删除”

DELETE FROM tableA WHERE CURRENT OF myCurs;

上面删除了刚刚获取的行。

【讨论】:

  • 谢谢,如果我理解正确,您的建议将加快这个单表上的删除速度。但是,如果这个 colA 是跨多个其他表的键,也需要在循环中删除(这是我的终极方案),我需要使用临时变量方法。对吗?
【解决方案2】:

您错过了不同数据库引擎之间的并发控制实现的差异。在 Oracle 数据库中,另一个会话将看到在其事务开始之前已提交的数据,也就是说,在第一个会话提交之前,它不会看到任何删除。

在 DB2 中,根据服务器配置参数(例如 DB2_SKIPDELETED)和/或第二个会话隔离级别(例如未提交的读取),它实际上可以看到(或看不到)受进行中事务影响的数据。

如果您的业务逻辑需要不同的事务隔离,请咨询您的 DBA。

【讨论】:

  • 感谢您的回复。我想我在第二次会议中看到了未提交的行数……我猜它实际上是在进行一次提交。我正在努力使用管理工具(与其他 RDBMS 相比),我想我需要查看服务器端的一些东西来监控 COMMIT。我将与 DBA 合作。
  • 我认为您没有看到已删除的行,尽管它们仍未提交。至少你的描述是这样的。
  • 不,这就是我所看到的...再次,我用 50k 条记录加载表,运行 purge rec 大约需要 60 秒才能完成:
  • (忽略之前的评论..edit 在我身上超时)不,这就是我会看到的...再次,我用 50k 条记录加载表,运行 purge rec 大约需要 60秒完成,这是第二个 SQL 客户端/会话将通过简单的“从 tableA 中选择计数(*)”显示的内容:时间 0s = 50,000 记录时间 20 秒 = 34,517 记录时间 40 秒 = 17,102 记录时间 60 秒 = 0 记录这这意味着我正在看到已删除的行,即使它们尚未提交。
  • 34517 条记录少于 50000 条记录,因此您没有看到 16483 条记录已被删除,但尚未提交。对吗?
猜你喜欢
  • 1970-01-01
  • 2011-02-18
  • 2020-05-27
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 2020-08-03
相关资源
最近更新 更多