在一个拥有550万行的MySQL表中,更新/更改列的数据类型(TINYINT到SMALLINT)的最佳和最安全的方法是什么?

ct3nt3jp  于 2023-04-19  发布在  Mysql
关注(0)|答案(5)|浏览(117)

类似的问题也被问到过,但我过去使用
ALTER TABLE tablename MODIFY columnname SMALLINT
上次运行此命令时,我的服务器崩溃,不得不恢复我的表。当表中有那么多数据时,使用此命令安全吗?如果有其他查询可能并行运行在表上,该怎么办?我应该复制表并在新表上运行查询吗?我应该复制列并将数据移动到新列吗?
请让我知道在这样做时是否有任何最佳或“最安全”的做法。
另外,我知道这取决于很多因素,但是有人知道查询一个大约550万行的InnoDB表需要多长时间吗(粗略估计)?有问题的列是TINYINT,其中有数据。我想升级到SMALLINT来处理更大的值。
谢谢!

yyyllmsg

yyyllmsg1#

在速度较慢的磁盘上,并且表中有很多列,可能需要几个小时才能完成。
ALTER是“安全的”,因为它过去可以执行以下操作:
1.锁上table
1.创建一个类似的表,但使用SMALLINT而不是TINYINT
1.将所有行复制到新表中。
1.重命名表并删除旧表。
1.解锁
第3步是缓慢的部分,唯一的漏洞在第4步,非常快。
在步骤1-3期间发生的服务器崩溃应该会使旧表保持原样,但可能会留下一个名为#sql...的部分创建的tmp表。
Percona的pt-online-schema-change具有几乎无锁的优势。

d7v8vwbk

d7v8vwbk2#

这个问题不容易回答。
这取决于

  • 该表是否有自己的文件,还是与其他人共享?
  • 这个表以字节为单位有多大?

等等
它可能持续几分钟甚至几个小时,并且可能涉及到复制表的整个内容,因此您需要相当大的磁盘空间。

0yycz8jy

0yycz8jy3#

可以向表中添加新的SMALLINT列:

ALTER TABLE tablename ADD columnname_new SMALLINT AFTER columnname;

然后将数据从旧列复制到新列:

UPDATE tablename SET columnname_new = columnname WHERE columnname_new IS NULL LIMIT 100000

重复上述步骤,直至完成所有记录
然后你可以删除旧的列:

ALTER TABLE tablename DROP COLUMN columnname

最后重命名新列:

ALTER TABLE tablename CHANGE columnname_new columnname SMALLINT

你可以在一批100000行中将值从旧列复制到新列,只是为了确保没有任何问题

tvmytwxo

tvmytwxo4#

我将添加一个新列,更改代码以检查新列中是否存在值,如果存在,则读取/写入它。还更改代码以从旧列读取并写入新列。此时,您可以随意迁移数据,将旧列中的值复制到新列中,其中新列中不存在值。
迁移完所有数据后,您可以删除旧列。

zte4gxcn

zte4gxcn5#

我修改了表中的1列,在18分钟内从intdouble有大约6百万个
我的服务器有8核,16GB内存,使用SSD。

6,192,515 rows affected in 17 m 50 s 81 ms

相关问题