在 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
这将相当快,并且对其他查询几乎没有影响。然而,如果有人在几天内查看该代码,价格可能不会持续更新。 (如果这与您有关;我们可以进一步讨论。)
我试图了解 table 中的大量更新如何影响用户的数据可用性。我浏览了各种帖子 (fastest-way-to-update-120-million-records,
我正在尝试了解这些大型更新如何影响 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
这将相当快,并且对其他查询几乎没有影响。然而,如果有人在几天内查看该代码,价格可能不会持续更新。 (如果这与您有关;我们可以进一步讨论。)