上周,以前公司的同事朋友找我幫忙,看看能否幫忙恢復一個MySQL 資料庫,具體情況為:資料庫版本為MySQL 5.6(具體版本不清楚),也不清楚具體的資料庫引擎; 沒有資料庫備份,只剩下資料庫下麵的一些文件(frm、idb),具體原因是因為出現問題的時候,重裝了MySQL,最要命的是ibdata1等... ...
上周,以前公司的同事朋友找我幫忙,看看能否幫忙恢復一個MySQL 資料庫,具體情況為:資料庫版本為MySQL 5.6(具體版本不清楚),也不清楚具體的資料庫引擎; 沒有資料庫備份,只剩下資料庫下麵的一些文件(frm、idb),具體原因是因為出現問題的時候,重裝了MySQL,最要命的是ibdata1等文件也沒有了,當然這中間細節過程如何,不清楚也不用去糾結了。大概就是這麼一個情況。
因為資料庫不大,將對應的文件拷貝到自己一臺測試伺服器的MySQL數據文件目錄下後(下麵實驗測試,對資料庫名等敏感信息做了一下混淆),如下所示,資料庫名為test,show tables可以看到相關的表。
其中有幾張表的存儲引擎為MyISAM,那麼這些表的數據是完全可以恢復的,但是大部分表的存儲引擎為InnoDB,訪問表或查看表都會提示“ERROR 1146 (42S02): Table 'xxxx' doesn't exist 不存在。
mysql> desc think_cache;
ERROR 1146 (42S02): Table 'test.think_cache' doesn't exist
mysql> show create table think_cache;
ERROR 1146 (42S02): Table 'test.think_cache' doesn't exist
mysql>
由於共用表空間的ibdata1數據文件不存在了,加之有沒有備份,所以我武斷的判斷這個資料庫真的無法恢復了,但是過後一天,這個朋友跟我說找了一家數據恢復公司將這個資料庫恢復了。 聽到這個消息頗有點學藝不精的尷尬(其實談不上尷尬吧,本來還在學習MySQL的路上,有些知識點不清楚也很正常。經驗是需要慢慢積累的),不過更多的是好奇別人是如何恢複數據的,既然別人能夠恢復,那麼自己下一次遇到這種情況也要能搞定。下麵就來複盤一下別人是如何恢複數據的(其實只要稍稍做點功課,發現這個其實挺簡單的)
首先,我們來瞭解一下MySQL 表空間數據文件idbdat1文件相關概念和知識點:
InnoDB採用按表空間(tablespace)的方式進行存儲數據, 預設配置情況下會有一個初始大小為10MB, 名字為ibdata1的文件, 該文件就是預設的表空間文件(tablespce file),用戶可以通過參數innodb_data_file_path對其進行設置,可以有多個數據文件,如果沒有設置innodb_file_per_table的話, 那些Innodb存儲類型的表的數據都放在這個共用表空間中,而系統變數innodb_file_per_table=1的話,那麼InnoDB存儲引擎類型的表就會產生一個獨立表空間,獨立表空間的命名規則為:表名.idb. 這些單獨的表空間文件僅存儲該表的數據、索引和插入緩衝BITMAP等信息,其它信息還是存放在共用表空間中。
其實當時主要是對這個概念有點模糊了,以為這個系統變數innodb_file_per_table預設是關閉的,數據都會存儲在共用表空間中,那麼這些文件刪除了,數據就無法恢復。所以武斷的下結論,其實從MySQL 5.6.6開始, 系統變數innodb_file_per_table預設是啟用的。只要再多瞭解一點或者說更深入瞭解一點的話,情況就會立馬就會反轉。也就是說如果開啟了獨立表空間,可從ibd文件中恢複數據。即使共用表空間的數據文件idbdata1丟失也不要緊,反之,如果未開啟獨立表空間時,idbdat1被刪除了,數據也會被刪除,只能從備份中恢復,真的沒有其他辦法。
那麼我們接下來看看,如何從idb文件中恢複數據吧,我們需要用到mysqlfrm工具, 需要安裝MySQL Utilities,下麵是安裝MySQL Utilities 1.5.5
# tar -xvf mysql-utilities-1.5.5.tar.gz
# cd mysql-utilities-1.5.5
# python ./setup.py build
# python ./setup.py install
提取frm文件的表結構信息
mysqlfrm 是一個恢復性質的工具,用來讀取.frm文件並從該文件中找到表定義數據生成CREATE語句。此處不對mysqlfrm工具做過多介紹,我們使用msqlfrm來生成該資料庫的表的CREATE語句
[root@DB-Server ~]# service mysql stop
Shutting down MySQL.... SUCCESS!
[root@DB-Server ~]# /usr/local/bin/mysqlfrm --basedir=/usr --port=3306 --user=root /data/mysql/test/ > test_frm.sql
[root@DB-Server ~]#
檢查導出的SQL語句,發現都是“ERROR: The server version for this file is too low. It requires a server version 5.6.29 or higher but your server is version 5.6.20. Try using a newer server or use diagnostic mode”這類錯誤:
[root@DB-Server ~]# more test_frm.sql
# Spawning server with --user=root.
# Starting the spawned server on port 3306 ... done.
# Reading .frm files
#
# Reading the think_cache.frm file.
ERROR: The server version for this file is too low. It requires a server version 5.6.29 or higher but your server is version 5.6.20. Try using a newer server or use diagnostic mode.
#
# Reading the think_session.frm file.
ERROR: The server version for this file is too low. It requires a server version 5.6.29 or higher but your server is version 5.6.20. Try using a newer server or use diagnostic mode.
#
# Reading the wx_activity_config.frm file.
ERROR: The server version for this file is too low. It requires a server version 5.6.29 or higher but your server is version 5.6.20. Try using a newer server or use diagnostic mode.
#
........................................................................................
從中可以看到這個資料庫之前的版本為MySQL為5.6.29,而我這裡的MySQL版本比這個低(MySQL 5.6.20)。所以必須找一個跟這個版本相同或高的MySQL資料庫操作才行。於是在另外一臺測試伺服器安裝了MySQL
[root@gettestlnx02 ~]# service mysqld stop
Stopping mysqld: [ OK ]
[root@gettestlnx02 tmp]# mv test /data/mysqldata/mysql/test
[root@gettestlnx02 tmp]# cd /data/mysqldata/mysql/
/usr/bin/mysqlfrm --basedir=/usr --port=3306 --user=root /data/mysqldata/mysql/test/ > test_frm.sql
如何要查看輸出信息,可以使用參數-vvv
/usr/bin/mysqlfrm --basedir=/usr --port=3306 --user=root -vvv /data/mysqldata/mysql/test/ > test_frm.sql
生成的SQL腳本沒有以分號結尾,本來想用sed命令給那些CREATE TABLE腳本加上分號結尾,但是發現其中大量CREATE TABLE的腳本結尾沒有規律,都是以COMMNET='xxxxx'結尾,只能手工添加分號(如下所示)
導入frm文件的表結構信息
mysql> use test;
Database changed
mysql> source test_frm.sql
Query OK, 0 rows affected (0.02 sec)
Query OK, 0 rows affected (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
Query OK, 0 rows affected (0.00 sec)
.................................
然後我們檢查這個資料庫的各類文件frm、ibd、MYI、MYD文件數量,後續做對比驗證用途。
[root@gettestlnx02 test]# ls -lrt *.frm | wc -l