前言:
在系統正常運作一定時間后,隨着市場、產品汪的需求不斷變更,比較大的一些表結構面臨不得不增加字段的方式來擴充滿足業務需求;
而 MySQL 在體量上了千萬、億級別數據的時候,Alter Table 的操作,可以讓你等一天,而且在高峰期執行這種 SQL 讓你的數據庫也承擔着壓力。
第一時間想到的解決方案就是新建一張表,去掉索引等關聯關系,然后加上需要修改的字段,接着寫上 insert select 語句進行導數據,
后面發現加上重建索引的操作,時間上幾乎沒有出入;
針對這種問題,趕緊翻翻 《高性能 MySQL》 ,里面有寫出一種解決方案,與大家分享一下。
一、工具
// “影子拷貝”,針對不同的場景而言的方式,在一台不提供服務的機器上執行 Alter Table 操作,然后和提供服務器的機器進行切換;
Facebook 數據庫運維團隊的“online scherma change”工具:
https://launchpad.net/mysqlatfacebook
Shlomi Noach 的 openrak toolkit 工具:
https://launchpad.net/mysqlatfacebook
// 不是所有的 Alter Table 操作都會引起表重建。
二、修改 .frm 文件
// .frm MySQL 數據庫表結構定義文件;(.myd 數據文件、.myi 索引文件、.idb 數據&索引文件 [前者 MyISAM 后者 InnoDB])
修改 .frm 文件非官方支持的,也沒有文檔記錄,並且也有可能無法正常工作了,采用這些技術自己承擔風險,做好備份!
下面這些操作有可能不需要重建表的:
1、移除(不是增加)一個列的 AUTO_INCREMENT 屬性。
2、增加、移除,或更改 ENUM 和 SET 常量。如果移除的是已有行數據用到其值的常量,查詢將會返回一個空字符串。
基本的技術是為想要的表結構創建一個新的 .frm 文件,然后用它替換掉已經存在的那張表的 .frm 文件,如下:
1、創建一張有相同結構的空表,並進行所需要的修改(例如增加 ENUM 常量);
2、執行 FLUSH TABLES WITH READ LOCK。這將會關閉所有正在使用的表,並且禁止任何表被打開;
3、交換 .frm 文件;
4、執行 UNLOCK TABLE 來釋放第 2 步的讀鎖;
假如我們需要為那些對電影更加謹慎的父母們增加一個 PG-14 的電影分級:
注意,我們是在常量列表的末尾增加一個新的值。如果把新增的值放在中間,
例如 PG-13 之后,則會導致已存在的數據的含義被改變:已經存在的 R 值將變成 PG-14,
而已經存在的 NC-17 將成為 R,等等。
接下來用操作系統的命令替換 .frm 文件:
/var/lib/mysql/sakial# mv film.frm film_tmp.frm /var/lib/mysql/sakial# mv film_new.frm film.frm /var/lib/mysql/sakial# mv film_tmp.frm film_new.frm
再回到 MySQL 命令行,現在可以解鎖並查看變更后的效果了:
UNLOCK TABLES; SHOW COLUMNS FROM sakila.film LIKE 'rating'\G
最后需要做的就是刪除這個臨時的輔助表了。