优化MySQL中表的批量更新:10,000行的性能问题

问题描述 投票:0回答:1

考虑以下设计为包含最多 10000 行的内容:

CREATE TABLE T(
    id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
    weight MEDIUMINT NOT NULL,
    PRIMARY KEY(id)
);

每 6 小时我需要根据最新数据更新每行的权重。我通过预先比较表和最新数据之间保持相同的值来缩小这个数字,但最坏的情况仍然是 10000 行需要更新。新鲜数据仅由地图 id->value 组成。所以这里我不是在谈论

UPDATE T SET weight = {value};
,因为我需要将每一行的字段设置为特定值。

最初我认为单个查询应该更快,所以我将所有更新重新组合在一个

INSERT INTO T(id, weight) VALUES ({id_1}, {weight_1}), ..., ({id_n}, {weight_n}) ON DUPLICATE KEY UPDATE weight = VALUES(weight);
语句中,这有点快(尽管我不记得到底有多快),但我很快发现我的即使行已更新且未插入,AUTO_INCRMENT id 也会递增,这在我的情况下是非常错误的,因为选择 id 本身的数据类型 (SMALLINT UNSIGNED) 是因为它是具有最低最大值 (32767) 的数据类型表的最大理论行数 (10000)。我可以使用 BIGINT UNSIGNED 但由于我只更新此表,这似乎浪费空间并且是解决问题的一种非常懒惰的方法。

我刚刚尝试对每个 id->value 对进行

UPDATE T SET weight = {value} WHERE id = {id};
查询,但速度非常慢,因为完成所有查询大约需要 600 毫秒。

我也只是尝试将所有 id->value 对重新组合到一个

UPDATE T SET weight = CASE id WHEN {id_1} THEN {weight_1} ... WHEN {id_n} THEN {weight_n} END WHERE id IN ({id_1}, ..., {id_n});
语句中,但仍然需要大约 600 毫秒才能完成。

您可能会告诉我,每 6 小时 600 毫秒并不算多,我同意这个表,但我会更定期地处理类似的情况,这种高延迟肯定会成为一个问题。

mysql query-optimization bulkupdate
1个回答
0
投票

建立一个新表,然后交换表可能是最快的:

CREATE TABLE new LIKE real;
INSERT INTO new 
    SELECT ...   -- including `real.id`
        FROM real
        JOIN updates ON ...
RENAME TABLE real TO old,
             new TO real;

如果传入的数据可能会添加新行(因此,创建新的 id),我建议用两个查询来代替那个 INSERT ——一个用于处理更新的行,另一个用于添加新行(参见

LEFT JOIN
)。

(这个问题太模糊了,我无法说出完整的细节。)

© www.soinside.com 2019 - 2024. All rights reserved.