【问题标题】:Is there any way to update the most recent version of row through SQL?有没有办法通过 SQL 更新最新版本的行?
【发布时间】:2011-05-03 13:46:39
【问题描述】:

我读到 Oracle 维护行版本来处理并发性。我想在一个非常大的实时数据库上运行更新查询,但是这个更新作业必须更改该行的最新版本。

这可以通过 PL/SQL 还是简单的 SQL 实现?

在下面编辑**

让我澄清一下场景,即我们在一个非常大的数据库上面临的现实问题。我们的客户是一家知名的手机服务商。

我们的数据库有一个表格,用于管理客户手机帐户上的当前余额记录。在表格的其他列中,一列存储已完成的充值量,另一列管理当前剩余的活动余额。

我们有两个独立的 PL/SQL 脚本。当客户为手机充电并更新余额时,会自动触发一个脚本。

第二个脚本是关于从客户帐户中扣除某些费用。这是一个批处理作业,因为它适用于所有客户。此脚本计划在一天的特定时间间隔运行。运行此脚本时,它会在内存中加载 50,000 条记录,更新某些列并执行批量更新回表。

发生的问题是这样的:

一位 ID 为 101 的客户联系了当地商店为手机充电。他支付金额。但是直到他的手机快要充电的时候,第二个脚本的预定时间才触发了第二个脚本。第二个脚本在内存中加载了 50,000 个客户的记录。在这个内存记录中,也是这个客户的记录之一。

直到第二个脚本批量更新完成,第一个脚本成功为客户账户充值。

现在发生的是实际表,列:“CurrentAccountBalance”更新为 150,但第二个脚本正在处理的内存中记录具有客户的旧余额,即 100。

第二个脚本必须从列中减去 10:“CurrentAccountBalance”。当根据实际工作,客户的“CurrentAccountBalance”应该是140时,这个问题使他的余额为90。

现在如何处理这个问题。

【问题讨论】:

  • 你说的是闪回,Oracle 的临时访问?
  • 没有。纯 SQL 更新语句。
  • 您正在尝试查看来自另一个会话的未提交数据?然后在提交之前更新它!?
  • 更新将始终针对该行的最后提交版本。我不确定你的问题是什么。如果您希望修改大量数据,您是否尝试包含在更新开始后修改和提交的行?
  • 我不寒而栗地想到如果有什么事情会如何运作但是这甚至是可能的......

标签: oracle oracle10g oracle11g oracle9i


【解决方案1】:

正如@Markus 建议的那样,您有一个竞争条件。如果您将记录加载到内存中并在更新表中的行之前对其进行处理,并且在此期间可能会尝试更新它们,那么您需要在处理它们时锁定它们。 (我假设您所做的任何事情都太复杂而无法进行简单的一步更新)。这样的事情会起作用:

DECLARE
    CURSOR c is SELECT * FROM current_balance_table FOR UPDATE;
BEGIN
    FOR r IN c LOOP
        /* Do whatever calculations you need */
        new_value := r.CurrantAccountBalance - 10;
        UPDATE current_balance_table SET CurrentAccountBalance = new_value
        WHERE CURRENT OF c;
    END LOOP:
END;

现在的问题是,所有记录在循环期间都被锁定,因此您在商店中的客户将无法更新他们的余额,或者在更新生效之前等待日志 - 尽管当它它是否适用于您存储的更新值。因此,您必须将光标分成小块,平衡脚本的性能和对尝试更新同一个表的其他人的影响。

一种选择是让外部光标选择您所定位的所有客户而不锁定,然后在计算和更新该行时锁定该客户的余额记录的内部光标。您必须在每个内部循环之后提交才能释放该行的锁定。这涉及到更多的锁定/解锁和提交,每次更新后都会大大减慢速度。但它最大限度地减少了对商店中个别客户的影响,因为一次只锁定一行,并且锁定的时间长度被最小化。所以,你需要找到合适的平衡点。

【讨论】:

  • 目前我们正在锁定,但我想知道任何有效的替代方案。
【解决方案2】:

我认为你想要的是如果你 UPDATE 会发生什么。

Oracle 确实会保留旧数据一段时间,但只是为了支持一致性读取。也就是说,读取操作只能看到事务开始时的状态——即使同时数据被覆盖。称为多版本并发控制,可以通过Transaction Isolation Level进行控制。

您可以通过选择`FOR UPDATE 明确请求最新的;这会为记录添加一个锁,这样其他人就不能同时更新它(直到您的事务结束)。

但是,如果您需要编写任何内容(例如,UPDATE),Oracle总是在最新版本上工作。

【讨论】:

  • 请查看OP中的实际场景。
  • 我已经在逃跑了,只是浏览了你的更新。这可能是一个竞争条件?所以我在上面添加了一些关于 FOR UPDATE 的内容。
猜你喜欢
  • 1970-01-01
  • 2016-08-16
  • 1970-01-01
  • 1970-01-01
  • 2021-12-11
  • 1970-01-01
  • 2018-08-06
  • 2016-11-11
  • 1970-01-01
相关资源
最近更新 更多