【问题标题】:In what sequence will the Delete SQL execute?Delete SQL 将按什么顺序执行?
【发布时间】:2017-04-19 16:16:40
【问题描述】:

参考我之前的帖子。

Sql Cleanup script, delete from one table that's not in the other1

使用 DB2 for IBM i(As400、Db2)。

我在凌晨 3 点执行以下 sql 作为清理脚本。

DELETE FROM p6prodpf A WHERE (0 = (SELECT COUNT(*) FROM P6OPIPF B WHERE   B.OPIID = A.OPIID))

我有一个不同的过程,在这条sql运行的同时插入两条记录,第一条记录是P6OPIPF记录,然后将详细记录插入P6PRODPF

问题。 在 SQL 清理运行后,P6PRODPF 记录丢失。但请记住,存储记录的进程同时运行。

我对 SQL 的理解是它通过 P6PRODPF 并检查记录是否在 P6OPIPF 如果它不在 P6OPIPF 然后删除 P6PRODPF

但随后我在系统导航器中对该 SQL 运行 Visual Explain,并得到以下结果。

现在我很困惑。

Visual explain 之后看起来语句以检查P6OPIPF 开头。

那么它的内容是:如果在P6OPIPF 中的那个时间实例中有一条记录,而P6PRODPF 中没有具有相同键的记录,则删除P6PRODPF

这可以解释我的问题,即当我的插入记录的进程和 sql 脚本同时运行时,P6PRODPF 被删除。

那么我如何看待它。(我的理论)

  1. 插入两条记录的进程启动。

  2. 插入两条记录的进程将第一条记录插入到 P6OPIPF.

  3. SQL 清理同时运行。查询看到的是P6OPIPF 记录并检查它是否有P6PRODPF 记录。在这个阶段 仍然没有插入P6PRODPF,所以 Sql 认为它需要 删除P6PRODPF中的记录。
  4. 同时插入两条记录的进程插入 P6PRODPF 中的第二条记录。
  5. 而且因为 Sql 在那个阶段没有看到P6PRODPF 删除P6PRODPF 中新插入的记录,留下P6OPIPF 没有P6PRODPF 记录的记录。

我说的对吗?

我真正想知道的只是上面列出的删除脚本。我对 SQL 的理解是它通过 P6PRODPF 并检查记录是否在 P6OPIPF 中,如果它不在 P6OPIPF 中,然后删除 P6PRODPF。但是在视觉解释之后,我可以看到它从检查 P6OPIPF 开始。那么 delete 语句首先会检查什么?

插入的代码在 CA PLEX 生成器中生成。 RPGIV 代码。

我的一个函数将首先插入P6OPIPF(OperationsItem.Update.InsertRow),然后在P6PRODPF(ProductDetail.Update.InsertRow) 中插入其详细信息。

Insert Row function

将执行删除脚本的我的计划函数代码。

Scheduled delete script function

希望它有意义。

【问题讨论】:

  • 旁注:进行无行删除的更惯用方法是这样的:DELETE FROM P6ProdPF A WHERE NOT EXISTS (SELECT 1 FROM P6OpiPF B WHERE A.opId = B.opId)。在多对一的情况下,这可能会更快(不需要计算行数,它只检查任何行)。
  • @Clockwork-Muse 感谢您的提示,我将在未来使用它。

标签: sql db2 ibm-midrange db2-400


【解决方案1】:

Visual Explain 是了解数据库在做什么的有用工具,尤其是在尝试提高性能时。

但是 SQL 不是过程语言。你不应该也不能真的试图说当我运行这个语句时,数据库正在这样做,然后它正在这样做。

虽然对于特定的运行可能是正确的,但它高度依赖于可用的数据和资源。您不能围绕您看到的步骤编写流程。

你真的不应该尝试同时运行两个进程,根本没有办法确保你最终会得到什么;至少在使用默认隔离级别时(可能是“无提交”或“读取未提交”,具体取决于接口。)

如果您必须同时运行两个进程,您可能希望在“可重复读取”或“可序列化”下运行删除;这应该具有锁定正在引用的表的效果,以便其他进程无法更改它们。

或者,您可以在读取稳定性或更高的隔离级别下同时运行删除和插入。

【讨论】:

    【解决方案2】:

    为了解释 Visual Explain,DB2 将在执行 DELETE 子句之前检查内部表达式 - 它必须这样做,否则它将不知道哪些行受到影响。

    您的存档行未存档的原因是删除脚本在插入脚本之前运行。

    【讨论】:

    • 我同意你的观点,我也认为删除在插入之前运行,但似乎不可能......有一个程序调用 2 插入第一个插入在 P6OPIPF 中,之后同一程序调用另一个插入 P6PRODPF。在这个程序运行的同时删除 SQL 运行。删除运行后,我检查了记录,我可以看到它删除了 P6PRODPF。为什么即使有 P6OPIPF 记录,Delete SQL 脚本也会删除 P6PRODPF?
    • 我认为“同时”这个词有些混淆。你真的是说程序按这个顺序运行了 3 个单独的 SQL 语句:1)插入 a 2)插入 b 3)删除
    • 抱歉让我澄清一下:有两个 RPGIV 函数 1. 一个插入 P6OPIPF,在同一函数中的 P6OPIPF 之后将其细节插入 P6PRODPF。 2. 是一个预定函数,将在预定时间执行 That Delete SQL。现在在我的实例中,函数一开始了,当我查看函数 2 执行的时间时,它看起来好像是同一时间。我把这两个函数的代码贴出来了,请你看看。
    • 如果有两个单独的操作(插入和删除)并且它们在两个不同的作业中运行,并且看起来它们同时运行,则无法保证哪个先运行。要解决此问题,请将删除操作与插入操作放在同一程序中,以便删除操作始终在插入操作之后运行。
    【解决方案3】:

    您听说过“交易”和“隔离”这两个概念吗?通常,针对同一数据库运行的不同进程相互屏蔽(隔离),因此它们在运行时不会看到同时运行的任何其他事务的直接影响。逻辑上同时执行的两个事务(一个进程或一系列 SQL 语句)以串行方式执行。

    在您的情况下,第一个过程是“第一个”或“第二个”。如果您重复测试,您可能会看到不同的结果,具体取决于谁是“第一”(逻辑上)。

    【讨论】:

    • 感谢您的回复。你说的很有道理。我真正想知道的只是上面列出的删除脚本。我对 SQL 的理解是它通过 P6PRODPF 并检查记录是否在 P6OPIPF 中,如果它不在 P6OPIPF 中,然后删除 P6PRODPF。但是在视觉解释之后,我可以看到它从检查 P6OPIPF 开始。那么 delete 语句首先会检查什么?
    • 访问表的顺序可以根据索引的存在和表中的数据量而改变。您不应依赖访问顺序。
    • 因此,您认为 Sql 删除脚本的行为会根据索引的存在和表中的数据量而有所不同。例如在实时系统上。表 A 通过程序插入,然后删除 Sql 脚本运行开始根据索引检查表 A 或 B,然后表 B 通过程序插入。这可能是一个潜在的问题吗?
    • @Renier - 比这更糟糕的是:您无法控制处理哪些行的顺序或进程的时间。即使您首先启动INSERT,它也不一定会首先插入行。最好考虑将来自单独进程的语句总是交错,因为它们会。您需要开始交易。
    • @Renier - 这两个都不是很有帮助,因为它们都不包含实际的语句。 “删除”的人正在从其他地方获得一份声明。我不会费心完全跟踪插入程序(特别是考虑到它看起来像那样)。 You have a lot to read - 交易是一个有点复杂的话题。您的 DBA 应该能够帮助您;一方面,他们通常是无论如何都要担心锁定的人。
    猜你喜欢
    • 1970-01-01
    • 2021-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-16
    • 1970-01-01
    • 2014-10-28
    • 2019-07-05
    相关资源
    最近更新 更多