是否有可能(以及如何)在不使应用程序脱机的情况下将巨大的MyISAM表转换为InnoDB。它需要每秒在该表中插入几行,但是可以将其挂起大约2分钟。
显然ALTER TABLE ... engine = innodb无法正常工作。因此,我计划使用innodb引擎创建一个新表并将内容复制到其中。最后,挂起应用程序日志线程和RENAME TABLE。
不幸的是,即使以100行的小批量进行复制,在一段时间后也会产生明显的延迟。
编辑:现有行永远不会更改,此表用于记录。
是否有可能(以及如何)在不使应用程序脱机的情况下将巨大的MyISAM表转换为InnoDB。它需要每秒在该表中插入几行,但是可以将其挂起大约2分钟。
显然ALTER TABLE ... engine = innodb无法正常工作。因此,我计划使用innodb引擎创建一个新表并将内容复制到其中。最后,挂起应用程序日志线程和RENAME TABLE。
不幸的是,即使以100行的小批量进行复制,在一段时间后也会产生明显的延迟。
编辑:现有行永远不会更改,此表用于记录。
Answers:
鉴于以下约束:
我不在乎对话是否需要几天或几周的时间。但是它必须在后台运行,而不需要关闭应用程序并且不造成明显的延迟
在进行日志记录时,如果您有一些好的方法来设置标记,以便可以告诉您启动过程的目的,那么您就可以重新应用任何日志,或者将日志写到文本文件中,以便您可以稍后将它们摄入 LOAD DATA INFILE
问题的一部分是较小的批量写入意味着必须一遍又一遍地重新计算索引。您最好一次全部运行它,但这可能会导致系统出现一些“明显的”延迟。.但是您不必在生产服务器上这样做。
LOAD DATA INFILE
)不幸的是,即使以100行的小批量进行复制,在一段时间后也会产生明显的延迟。
您是在每个批处理之间添加任何延迟,还是只是将更新分批处理并在上一个批处理之后直接运行每个批处理?
如果是这样,请尝试使用您喜欢的语言编写转换脚本,如下所示:
repeat
copy oldest 100 rows that haven't been copied yet to new table
sleep for as long as that update took
until there are <100 rows unprocessed
stop logging service
move the last few rows
rename tables
restart logging
delete the old table when you are sure the conversion has worked
这应该确保转换不会占用服务器容量的一半以上,甚至允许随着系统使用时间的变化而造成的负载差异。
或者,如果您想在服务相对空闲时使用尽可能多的时间,但在数据库需要为其用户做一些工作时退后(可能会暂停相当长的时间),请替换sleep for as long as the update took
为if the server's load is above <upper measure>, sleep for some seconds then check again, loop around the sleep/check until the load drops below <lower measure>
。这意味着它可以在安静的时候继续前进,但是在服务器忙于执行正常工作负载时将完全暂停。确定负载将取决于您的操作系统-在Linux和类似操作系统下,1分钟负载平均值/proc/loadavg
或uptime
应该输出的负载。<lower measure>
并<upper measure>
可能是相同的值,尽管在此类控件中通常会有所不同,因此您的过程不会继续启动,而是由于其自身的重启而对负载量度产生影响而立即暂停。
当然,这对于可能会修改旧行的表不起作用,但对于像您所描述的日志表一样会很好。
在这种情况下,您将要忽略在填充新表之后创建索引的通常智慧。当您希望事情尽可能快时(确实对系统其余部分的影响)时,这样做的确确实更有效,但是在这种情况下,您不希望在过程结束时像这样浪费大量的负载。索引是一次性创建的,因为在忙碌的时候您不能暂停索引。
这样的事情行吗?
$auto_increment
日志记录表mytable
上的不变)。$auto_increment
值SHOW TABLE STATUS LIKE 'mytable'
。 CREATE TABLE mytable_new LIKE mytable
ALTER TABLE mytable_new AUTO_INCREMENT=$auto_increment ENGINE=Innodb
RENAME TABLE mytable TO mytable_old, mytable_new TO mytable
INSERT INTO mytable SELECT * FROM mytable_old
。 您可以分批或在一条语句中执行第7步,因为它不会阻塞正常的日志记录。