我试图用新表替换InnoDB表,我希望所有指向旧表的外键引用指向新表.
所以我尝试了这个:
SET foreign_key_checks = 0;
ALTER TABLE foo RENAME foo_old;
ALTER TABLE foo_new RENAME foo;
Run Code Online (Sandbox Code Playgroud)
不幸的是,即使禁用了foreign_key_checks,指向foo的所有引用都会更改为指向foo_old.现在我正在寻找
我尝试删除外键并重新创建它们,但由于表格很大,需要几个小时.替换表的重点是在有限的停机时间内进行模式更改.
xel*_*ber 11
旧问题,但以下是可能的方法.基本上移动数据而不是重命名表.您当然需要确保新数据符合外键规则.
SET foreign_key_checks = 0;
CREATE TABLE IF NOT EXISTS foo_old LIKE foo;
INSERT INTO foo_old SELECT * FROM foo;
TRUNCATE foo;
INSERT INTO foo SELECT * FROM foo_new;
Run Code Online (Sandbox Code Playgroud)
确保将其作为一个查询运行,以便foreign_key_checks适用于整个事务.希望这可以帮助.
不幸的是,我不认为有一种方法可以解决你的问题而不先删除外键并重新创建它们.
这是次要的,但我也发现了你的RENAME
命令.您可以将它们链接在一起,除非所有步骤都成功,否则它将回滚所有其他重命名.这是语法:
RENAME TABLE foo TO foo_old, foo_new TO foo;
Run Code Online (Sandbox Code Playgroud)
在MySQL 5.6上innodb_file_per_table=ON
允许您动态交换表空间.这不能完全使用SQL来完成,因为文件操作需要单独执行.首先准备foo_new
要复制的表并删除foo
数据:
SET foreign_key_checks = 0;
ALTER TABLE foo DISCARD TABLESPACE;
FLUSH TABLES foo_new FOR EXPORT;
Run Code Online (Sandbox Code Playgroud)
此时,您需要将相关的InnoDB文件复制到正确的名称.文件存储在数据目录中.Debian的,例如,它们在默认情况下/var/lib/mysql/yourdatabase
和文件foo_new.ibd
,foo_new.cfg
以及foo_new.frm
.将它们分别复制到foo.ibd
,foo.cfg
和foo.frm
.例如:
$ cp foo_new.ibd foo.ibd
$ cp foo_new.frm foo.frm
$ cp foo_new.cfg foo.cfg
Run Code Online (Sandbox Code Playgroud)
注意MySQL可以访问新文件(例如,他们拥有正确的所有者,访问权限).完成后,您可以再次导入表并启用外键:
UNLOCK TABLES;
ALTER TABLE foo IMPORT TABLESPACE;
SET foreign_key_checks = 1;
Run Code Online (Sandbox Code Playgroud)
这只复制foo_new
到foo
.如果需要复制foo
,请重复这些步骤foo_old
.
InnoDB在外键中使用表的内部指针,因此无论给该表提供什么名称(使用RENAME
),约束都将保留,包括使用时SET foreign_key_checks = 0
。
无需重新构建整个表即可更改外键引用的方法
使用innodb_file_per_table=ON
将是我们可以使用的最接近的(请参阅@vhu答案)。
一种在不更新外键引用的情况下重命名表的方法。
如果数据变化不大,该解决方案将意味着最短的停机时间和工作量,并且不需要外壳访问服务器,可能只是使用两个数据库,并在适当的时间打开它们。
同步所有其他表可能比在应用程序中同步大表或临时复制mysql命令(删除,更新,插入)要快得多,直到您进行了一些更改为止。