2011-06-17 48 views
28

我想用新表替換InnoDB表,並且我希望指向舊錶的所有外鍵引用都指向新表。重命名InnoDB表而不更新對其的外鍵引用?

所以,我想這一點:

SET foreign_key_checks = 0; 
ALTER TABLE foo RENAME foo_old; 
ALTER TABLE foo_new RENAME foo; 

不幸的是,即使有FOREIGN_KEY_CHECKS禁用,指向FOO的所有引用都更改爲指向foo_old。現在我正在尋找任何

  • 的方式來改變外鍵引用不回來重建整個表或
  • 的方式,而無需更新外鍵引用到重命名錶。

我嘗試刪除外鍵並重新創建它們,但由於表格很大,所以需要花費數小時。替換表格的重點是在有限的停機時間內改變模式。

+0

有沒有人知道在2015年這個問題上是否有任何更新? – Greg 2015-11-06 14:07:20

+1

更換表是否相同或略有修改?例如,改變可以通過改變來完成嗎?如果是這樣,你可能想看看[pt-online-schema-change -alter-foreign-keys-change](https://www.percona.com/doc/percona-toolkit/2.1/pt-online-架構change.html#cmdoption-PT-在線模式變化 - 改變,外國鍵法)。 – Dave 2015-11-10 13:06:51

回答

6

不幸的是,我不認爲有沒有解決您的問題的方法,而不先放棄外鍵,然後重新創建它們。

這是小問題,但我也發現你的RENAME命令。您可以將它們鏈接在一起,除非所有步驟都成功,否則它會回滾所有其他重命名。這裏是語法:

RENAME TABLE foo TO foo_old, foo_new TO foo; 
+3

我注意到,放棄foo然後重新創建它可以保持外鍵不變。由於foo_new基本上是foo的副本(加上額外)(使用SELECT INTO OUTFILE然後LOAD DATA INFILE創建),這可能是一個解決方案。我只需刪除表,重新創建它,然後將數據加載到該表中。只有重命名,我喜歡這樣一個事實,即當出現問題時,我有一個「備份」表。看起來落後的是,刪除表格會導致引用不變(即使它們指向不存在的表格),但是如果不更改引用,就不可能重命名錶格。 – 2011-06-17 11:29:08

+0

@BartvanWissen,這種方法最終會爲你工作嗎? – Greg 2015-11-06 14:07:02

8

老問題,但以下是一種可能的解決方法。 基本上移動數據而不是重命名錶。您當然需要確保新數據符合外鍵規則。

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; 

請確保您將它作爲一個查詢運行,以便foreign_key_checks適用於整個事情。希望這可以幫助。

7

在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.ibdfoo_new.cfgfoo_new.frm。將它們分別複製到foo.ibd,foo.cfgfoo.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_newfoo。如果您需要將foo複製到foo_old,請重複上述步驟。

3

InnoDB使用外鍵表中的內部指針,因此無論給出此表的名稱(使用RENAME),都會保留約束,包括當您使用SET foreign_key_checks = 0時。

的方式來改變外鍵引用回不重建整個表

使用innodb_file_per_table=ON將是我們可以去最近的(見@vhu答案)。

的方式來重命名錶,而無需更新外鍵引用。

這將意味着最低的停機時間和精力,並且不需要服務器shell訪問的解決方案,可能只是有兩個數據庫工作,並切換他們在適當的時候,如果數據不發生很大的變化

,如果你確實有一些變化這可能是更快的每一個其他的表比你的應用程序,直到開關的大單,或臨時複製mysql命令(刪除,更新,插入)同步。

0

我找到了解決這個問題的辦法......你只需放下源表而不是重命名它。

對於這個例子,我們將調用表'mytbl'。

  1. 創建源表,例如複製「mytbl_new」
  2. 將數據複製到新表
  3. 刪除源表「MYTBL」
  4. 重命名「mytbl_new」到「MYTBL」

唯一的缺點是你不能保持一個備份你原來的桌子,但你可以在手前用mysqldump。或者,如果您想要原始表的逐字副本,則可以創建額外的表副本。