如何更新 MyISAM 的 25 GB,超过 3.5 亿条记录的大 table?

How to update a large table of 25 GB, more than 350 million records of MyISAM?

如何更新table 25GB,超过3.5亿条记录的MyISAM? 我需要在 time 字段中为所有记录设置一个随机日期。在没有负载的服务器上,执行了命令:

UPDATE table SET time = FROM_UNIXTIME(1451595600 + FLOOR((RAND() * 31536000)))

mysqld 加载了处理器并占用了大量内存,早上服务器上的负载很小,但是查询都执行了,已经过去了 55 多个小时。

我不明白这是怎么回事!

CREATE TABLE `table` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `job_id` int(10) unsigned NOT NULL,
    `lock` mediumint(6) unsigned DEFAULT '0',
    `time` timestamp NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    KEY `job_id` (`job_id`),
    KEY `lock` (`lock`),
    KEY `time` (`time`)
) ENGINE=MyISAM;

添加:

root@lw4:~ # iostat -p md1 60 5

已解决:

我中断了更新过程。

删除了主索引以外的索引:

MariaDB [base]> ALTER TABLE `table` DROP INDEX `job_id`, DROP INDEX `lock`, DROP INDEX `time`;
Query OK, 339468609 rows affected (1 hour 3 min 28.89 sec)
Records: 339468609  Duplicates: 0  Warnings: 0

更新“时间”字段:

MariaDB [base]> UPDATE `table` SET `time` = FROM_UNIXTIME(1451595600 + FLOOR((RAND() * 31539599)));
Query OK, 339468609 rows affected (16 min 8.09 sec)
Rows matched: 339468609  Changed: 339468609  Warnings: 0

添加索引:

MariaDB [base]> ALTER TABLE `table` ADD INDEX (`job_id`), ADD INDEX (`lock`), ADD INDEX (`time`);
Query OK, 339468609 rows affected (2 hours 18 min 58.32 sec)
Records: 339468609  Duplicates: 0  Warnings: 0

总更新时间:3 小时 38 分 35.3 秒

首先,删除 table 的所有索引。此外,删除外键约束(如果有的话)。然后启动更新查询。更新完成后再次创建所有索引和约束

创建所有索引和约束将花费时间,但与直接更新 table 相比会少很多。

这是正在发生的事情...

每条记录最初为 13 个字节。更新一行后,它将是 17 字节(旧版本 MySQL)或 18 字节(新版本)。

这意味着更新的行不能简单地替换旧行,而必须放在其他地方然后释放旧行space。第一次这样的更新将进行到 table 的末尾。或者它可能使用旧 space 中的 13-6 个字节,然后将 link 放到它放置新行的其余部分的位置。

然后第二行做了类似的乱七八糟的事情。

因此,操作在 table 中徘徊,使数据非常零散。

此外,正在重建 time 的索引(使用 key_buffer)。因为是"random",索引BTree的更新是随机的。如果 key_buffer 不够大,那么会有很多 I/O。这个特殊方面可以通过 DROPping 预先索引并在之后重新添加它来加速。 las,DROPADD 都会很慢,但不会像索引的增量构建那样慢。

您真的应该转向 InnoDB,它以完全不同的方式进行数据更新和索引更新,并且更高效。一个警告:table+索引将占用 MyISAM 的 2-3 倍磁盘space。

你真的需要全部 4 个索引吗?

对于MyISAM,key_buffer_size的值很重要。对于 InnoDB,innodb_buffer_pool_size.