如何更新 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,DROP
和 ADD
都会很慢,但不会像索引的增量构建那样慢。
您真的应该转向 InnoDB,它以完全不同的方式进行数据更新和索引更新,并且更高效。一个警告:table+索引将占用 MyISAM 的 2-3 倍磁盘space。
你真的需要全部 4 个索引吗?
对于MyISAM,key_buffer_size
的值很重要。对于 InnoDB,innodb_buffer_pool_size
.
如何更新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,DROP
和 ADD
都会很慢,但不会像索引的增量构建那样慢。
您真的应该转向 InnoDB,它以完全不同的方式进行数据更新和索引更新,并且更高效。一个警告:table+索引将占用 MyISAM 的 2-3 倍磁盘space。
你真的需要全部 4 个索引吗?
对于MyISAM,key_buffer_size
的值很重要。对于 InnoDB,innodb_buffer_pool_size
.