Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 重命名InnoDB表而不更新其外键引用?_Mysql_Innodb - Fatal编程技术网

Mysql 重命名InnoDB表而不更新其外键引用?

Mysql 重命名InnoDB表而不更新其外键引用?,mysql,innodb,Mysql,Innodb,我试图用新表替换InnoDB表,我希望所有指向旧表的外键引用都指向新表 所以我试了一下: SET foreign_key_checks = 0; ALTER TABLE foo RENAME foo_old; ALTER TABLE foo_new RENAME foo; 不幸的是,即使禁用了外键检查,所有指向foo的引用也会更改为指向foo旧的。现在我正在寻找其中之一 一种在不重建整个表的情况下更改外键引用的方法,或 一种在不更新外键引用的情况下重命名表的方法 我试着删除外键并重新创建它

我试图用新表替换InnoDB表,我希望所有指向旧表的外键引用都指向新表

所以我试了一下:

SET foreign_key_checks = 0;
ALTER TABLE foo RENAME foo_old;
ALTER TABLE foo_new RENAME foo;
不幸的是,即使禁用了外键检查,所有指向foo的引用也会更改为指向foo旧的。现在我正在寻找其中之一

  • 一种在不重建整个表的情况下更改外键引用的方法,或
  • 一种在不更新外键引用的情况下重命名表的方法

我试着删除外键并重新创建它们,但由于表很大,这需要几个小时。替换表的全部目的是在有限的停机时间内进行模式更改

不幸的是,我不认为有办法解决您的问题,而不首先删除外键,然后由外键创建它们

这是次要的,但我也在您的
重命名
命令中发现了一些东西。您可以将它们链接在一起,除非所有步骤都成功,否则它将回滚所有其他重命名。以下是语法:

RENAME TABLE foo TO foo_old, foo_new TO foo;

老问题,但下面是一个可能的解决方法。 基本上是移动数据,而不是重命名表。当然,您需要确保新数据符合外键规则

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;

确保将其作为一个查询运行,以便外键检查适用于整个查询。希望这能有所帮助。

在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;
此时,您需要将相关的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
请注意MySQL可以访问新文件(例如,它们拥有正确的所有者和访问权限)。完成后,您可以再次导入表并启用外键:

UNLOCK TABLES;
ALTER TABLE foo IMPORT TABLESPACE;
SET foreign_key_checks = 1;

这仅将
foo\u new
复制到
foo
。如果需要将
foo
复制到
foo\u old
,请重复这些步骤

InnoDB在外键中使用表的内部指针,因此无论为该表指定什么名称(使用
RENAME
),都将保留约束,包括使用
设置外键检查=0

一种在不重建整个表的情况下更改外键引用的方法

使用
innodb\u file\u per\u table=ON
将是我们能去的最近的地方(见@vhu-answer)

一种在不更新外键引用的情况下重命名表的方法

意味着停机时间和工作量最低,并且不需要shell访问服务器的解决方案可能只是使用两个数据库,并在数据变化不大的情况下在适当的时间将其切换


如果您做了一些更改,则在切换之前,可以更快地同步应用程序中的每一个表,而不是大表或临时复制mysql命令(删除、更新、插入)。

我找到了解决此问题的方法。。。您只需删除源表,而不是重命名它

对于本例,我们将该表称为“mytbl”

  • 创建源表的副本,例如“mytbl_new”
  • 将数据复制到新表中
  • 删除源表“mytbl”
  • 将“mytbl_new”重命名为“mytbl”

  • 唯一的缺点是您无法保留原始表的备份,但您可以先将其转储。或者,如果需要原始表的逐字副本,可以创建一个额外的表副本。

    我注意到删除foo然后重新创建它可以保持外键的完整性。由于foo_new基本上是foo的一个副本(加上附加内容)(使用SELECT创建OUTFILE,然后加载数据填充),因此这可能是一个解决方案。我只需删除表,重新创建它,然后将数据加载到其中。只有通过重命名,我才喜欢这样一个事实,即我有一个“备份”表,以便在出现问题时使用。删除一个表会使引用保持不变(即使它们指向一个不存在的表),但在不更改引用的情况下重命名一个表是不可能的。@BartvanWissen,这种方法对你有用吗?@JamesC,
    RENAME
    会为你更改外键。i、 e.如果
    bar
    引用
    foo
    并将
    foo
    重命名为
    foo\u old
    ,则
    bar
    上的所有外键现在将引用
    foo\u old
    。将重命名链接到单个语句不会改变这一点。如果表中有数百万条记录,并且执行此操作的时间很短,则此操作不可行。(想想看,第一次复制需要两个小时,截断需要一段时间,再复制两个小时。)Like不会创建外键。。你需要检查一下吗?很荒谬的是,你不能简单地重命名一个表,而不引入潜在的数小时的数据操作。无论数据库引擎需要什么,这都很糟糕。我使用SQL Server,重命名表很容易。@Triynko SQL Server在重命名外键引用的表时的行为与MySQL相同,重命名是即时的,但重命名后的表仍被FKs引用。我不确定您是否完全阅读了原始版本。有人知道2015年该版本是否有任何更新吗?替换表是相同的,还是略有修改?例如,更改是否可以由alter完成?如果是这样的话,您可能想看看。如果有FK引用,则db不允许您删除该表。至少在mariadb 10.0.36中是这样的。WRT@Ravi的观点,是的,你需要
    SE