【问题标题】:Does a general InnoDB UPDATE lock the entire table and block incoming specific UPDATEs?一般 InnoDB UPDATE 是否会锁定整个表并阻止传入的特定 UPDATE?
【发布时间】:2020-11-14 13:31:36
【问题描述】:

假设我运行了这个语句:

UPDATE Employees set country='AU'

在 InnoDB 表中,Employees,大约有 1000 万行。

其他用户也通过如下 SQL 查询积极更新此表:

例如一个用户,ID = 20,将他们的国家更改为新西兰:

UPDATE Employees set country='NZ' where id = 20
  1. 在这种情况下,是否会对该表块进行任何进一步的更新,直到 一般更新完成了吗?
  2. 如果是这样,有没有办法允许特定的 更新和一般更新同时运行(如果不是) 更新同一行? (为了澄清我在这里的意思:假设 一般更新完成更新 ID 为 1 - 50 的员工,并且是 现在更新员工 51 - 约 1000 万,单次更新 id 为 20 的员工无需等待 一般更新完成)

【问题讨论】:

  • 用一个UPDATE改变一个表的所有行是很不正常的。如果该表仅用于澳大利亚,为什么还要有 country 列?
  • 对不起,国家可能不是一个很好的例子。在生产中,我们每天都会为所有用户将某些计数器重置为零。
  • 50M 行?计数器是否每天更新一次以上? (如果没有,有一个简单的解决方法。)

标签: mysql sql-update mariadb innodb table-locking


【解决方案1】:
  1. 是的,第一次更新将对表中的所有记录设置排他锁,阻止其他查询对其进行更新。锁会一直持有,直到事务提交。

  2. 没有。锁在事务运行时被持有,在事务提交时被释放。您可能希望以块的形式更新表,而不是一次大爆炸,避免第一次更新锁定整个表。如果可能,或者在工作时间之外执行更新。

【讨论】:

  • 假设营业时间是 24/7,那么块方法是最优的吗?没有其他方法可以解决这个锁定问题吗?
  • 正如我所写,锁是独占的。一次只能有一笔交易保存在记录中。
  • 我会批准你的回答,但我可以知道你的消息来源说锁是表锁吗?
  • @lbj99 - DML 只做 row 锁; DDL 可能会执行 table 锁。
  • @lbj99 表中的所有行都将被锁定,因为您的更新中没有 where 子句可以过滤掉任何记录。
【解决方案2】:

让我们“跳出框框思考”...

有 2 列。一个是counter;一个(dy)与计数器最后一个增量的DATE。然后使计数器的碰撞更复杂一些——即如果日期在今天之前,将其重置为 1。另外(总是)将日期更新为CURDATE()

类似

UPDATE t
    SET counter = IF (dy = CURDATE(), counter + 1, 1),
        dy = CURDATE()
    WHERE id = 123

消除了每晚的大更新。

要获取当天的计数器

SELECT  IF (dy = CURDATE(), counter, 0) AS counter
    WHERE id = 123;

这种技术还避免了必须在午夜运行大更新。如果机器恰好在午夜停机(并且当天无法运行更新),则会出现二阶“错误”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-05
    • 1970-01-01
    • 2012-08-03
    • 2011-10-05
    • 2017-02-01
    • 1970-01-01
    • 2013-12-22
    • 1970-01-01
    相关资源
    最近更新 更多