【问题标题】:MySQL MVCC (InnoDB)MySQL MVCC (InnoDB)
【发布时间】:2016-10-12 09:24:21
【问题描述】:

问题是关于 MySQL InnoDB 表中同时 SELECT 和 UPDATE 的行为:

我们有一个相对较大的表,我们会定期扫描读取几个字段,包括一个名为 LastUpdate 的字段。在扫描期间,我们更新之前扫描的行。更新在后台线程中批量执行 - 使用不同的连接。请务必注意,我们会更新已读取的行

三个问题:

  1. 由于 SELECT 仍在进行中,InnoDB 是否会保存更新行的先前版本?
  2. 是否将 READ-UNCOMMITTED 用于 SELECT 帮助?
  3. 如何确认 InnoDB 在其重做日志中保存或不保存修改行的先前版本。

【问题讨论】:

    标签: mysql transactions innodb isolation-level


    【解决方案1】:

    忽略问题,编写不会出问题的代码:

    BEGIN;
    SELECT id ... LIMIT 20; -- get list of _possible_ candidates for action
    COMMIT;
    **
    foreach $candidate
        BEGIN;
        SELECT ..., is_candidate WHERE id = $candidate FOR UPDATE;
        if still a candidate
            process it
            UPDATE ...;
        COMMIT;
    

    如果有人溜进来,比如**,稍后的检查将防止双重处理。此外,第二个 BEGIN..COMMIT 可以防止任何人溜进来。

    FOR UPDATE“锁定”该行;这很重要。

    以这种方式处理的优点是交易快速,从而最大限度地减少对其他一切的影响。

    【讨论】:

    • 不确定我是否理解答案。在我的例子中,SELECT 语句可能会返回 lot 行(100,000 或更多)。问题是我是否可以以某种方式告诉 MySQL 我已经完成了前 1000 行的处理,并且在更新时不需要保留这些行的旧版本。
    • 可能唯一的办法就是自己把它弄成团。
    • 嗯,使用 LIMIT/OFFSET 非常低效,并且使用服务器获取游标会强制 MySQL 创建一个临时表——这再次意味着复制所有数据。也许按主键分区效果最好。谢谢!
    • OFFSET 效率极低; PARTITIONing 无济于事。 PK穿过桌子是一个很好的方法。 More on chunking.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-14
    • 2011-02-28
    • 2017-11-27
    相关资源
    最近更新 更多