在 table 上进行大量更新时数据可用性对用户的影响

The impact of Availability of data to users while doing large updates on table

我试图了解 table 中的大量更新如何影响用户的数据可用性。我浏览了各种帖子 (fastest-way-to-update-120-million-records, ),这些帖子介绍了进行大型更新的不同机制,例如填充全新 table(如果可以离线完成的话)。如果不能离线就做批量更新。

我正在尝试了解这些大型更新如何影响 Table 对用户的可用性,以及在确保 Table 可供读取的同时进行大型更新的最佳方式是什么。

用例:根据主键更新交易详情(如因股票拆分更新持股量。)

不清楚您需要做什么。

  • 替换整个 table -- 填充新的 table,然后交换
  • 为所有行更改一列 -- 听起来设计草率。请详细说明你在做什么。
  • 为某些行更改一列 -- 同上。
  • 添加新列并对其进行初始化 -- 考虑创建并行 table,等等。这将实现零阻塞,但会增加代码的复杂性。
  • 这些值是根据其他列计算的——考虑一个 "generated" 列。 (您使用的 MySQL 是什么版本?)

这里讨论了如何使用 PRIMARY KEY 遍历 table 并且对其他查询的影响最小:http://mysql.rjweb.org/doc.php/deletebig#deleting_in_chunks(用 DELETE 编写记住了,但该原则也适用于 UPDATE。)

Table可用性

任何操作发生时,涉及的行都是"locked",防止其他查询同时修改。 ("Locking involves multi-version control, etc, etc.) They need to stay locked until the entire "交易”已完成。同时,需要记录任何更改,以防服务器崩溃或用户决定 "roll back" 更改。

因此,如果正在更改数百万行,则将持有数百万个锁。这需要时间。

我的博客建议一次只做 1000 行;这通常是一个足够小的数字,几乎不会干扰其他任务,但又足够大以在合理的时间内完成任务。

股票拆分

假设所需的查询(针对巨大的table)类似于

UPDATE t
    SET price = 2 * price
    WHERE date < '...'
      AND ticker = '...' 

您需要一个索引(或者可能是 PRIMARY KEY)才能成为 (ticker, date)。大多数 写入 都是面向日期的,但大多数读取都是面向代码的?鉴于此,以下可能是最佳的:

PRIMARY KEY(ticker, date),
INDEX(date, ticker)

因此,需要由 UPDATE 修改的行在数据的 BTree 中是 'clustered'(连续的)。因此有一定程度的效率。但是,如果那不是 "good enough",那么编写如下代码应该很容易:

date_a = SELECT MIN(date) FROM t WHERE ticker = ?
SET AUTOCOMMIT=ON
Loop
    date_z = date_a + 1 month
    UPDATE t
        SET price = 2 * price
        WHERE date >= ?    -- put date_a here
          AND date <  ?    -- put date_z here
          AND ticker = '...' 
    check for deadlock; if found, re-run the UPDATE
    set date_a = date_z
    exit loop when finished
End Loop

这将相当快,并且对其他查询几乎没有影响。然而,如果有人在几天内查看该代码,价格可能不会持续更新。 (如果这与您有关;我们可以进一步讨论。)