我有一个MySQL数据库,大小约为17 GB,有3800万条目。目前,我需要增加一列的大小(varchar 40到varchar 80)并添加更多列。
许多字段都已编入索引,包括我需要更改的字段。它是应用程序工作所必需的唯一对的一部分。在昨天尝试进行更改时,查询运行了将近四个小时而没有完成,当我决定停止我们的停机并将服务重新启动时。
对这种尺寸的东西进行更改的最有效方法是什么?
这些条目中的许多条目也很旧,如果有一种很好的方法可以对条目进行分类,但仍然可以通过使表格更容易管理来解决这个问题。
答案 0 :(得分:7)
你有一些选择。
在任何情况下,你都应该先做好备份。
一种可能性是让您的服务离线并按原样执行,就像您尝试过的那样。如果这样做,您应该禁用密钥检查和约束。
ALTER TABLE bigtable DISABLE KEYS;
SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE (whatever);
ALTER TABLE (whatever else);
...
SET FOREIGN_KEY_CHECKS=1;
ALTER TABLE bigtable ENABLE KEYS;
这将允许ALTER TABLE操作更快。当你执行ENABLE KEYS时,它将一次性重新生成索引。
另一种可能性是使用您想要的新架构创建一个新表,然后禁用新表上的键,然后按@Bader建议并插入旧表的内容。
构建新表后,您将重新启用其上的键,然后将旧表重命名为“old_bigtable”之类的名称,然后将新表重命名为“bigtable”。
您可以在填充新表时保持在线服务。但这可能效果不佳。
第三种可能性是将您的巨型表(转换为平面文件)转储,然后使用新布局将其加载到新表中。这非常类似于第二种可能性,除了您免费获得表备份。您可以使用SELECT DATA INTO OUTFILE
和LOAD DATA INFILE
快速完成此操作。您需要访问服务器计算机的文件系统才能执行此操作。
在所有情况下,禁用,然后重新启用约束和键以使事情变得更快。
答案 1 :(得分:3)
使用不同的名称创建一个包含所需新结构的新表,例如NewTable。
然后使用以下查询从旧表中将数据插入到这个新表中:
INSERT INTO NewTable (field1, field2, etc...) SELECT field1, field2, ... FROM OldTable
完成此操作后,您可以删除旧表并将新表重命名为原始名称
DROP TABLE `OldTable`;
RENAME TABLE `NewTable` TO `OldTable` ;
我在一个非常大的桌子上尝试过这种方法,它比改变表格要快得多。
答案 2 :(得分:2)
使用MySQL 5.1并再次使用5.5,某些alter语句被增强,只是修改结构而不重写整个表(http://dev.mysql.com/doc/refman/5.5/en/alter-table.html - 就地搜索)。这种情况的可用性因您所做的更改类型和使用的引擎而异,最大的价值来自InnoDB插件。在您进行特定更改的情况下,整个表格将被重写。
当我们遇到这些问题时,我们通常会尝试利用副本数据库。只要您要添加而不是删除,您可以先对副本运行DDL,然后安排短暂停机以将副本提升为主角色。如果您碰巧在RDS上,这甚至是他们的副本实例http://aws.amazon.com/about-aws/whats-new/2012/10/11/amazon-rds-mysql-rr-promotion/的建议用途之一。
其他一些选择包括:
INTO OUTFILE
以避免表锁定)。完成后,您可以安排维护窗口以及REPLACE INTO
或UPDATE
自初始数据复制以来原始表中已更改的任何记录。更新完成后,两个表中的RENAME TABLE...
将更改包装起来。