最近在巡檢的時候,發現mysql錯誤日誌中,報如下錯誤:
1779986 2015-10-06 00:06:37 7f5215214700 InnoDB: Error: Table "mysql"."innodb_table_stats" not found. 1779987 2015-10-06 00:06:37 7f5215214700 InnoDB: Recalculation of persistent statistics requested for table "xxxx"."xxxxxx" but the required persistent statistics storage is not present or is corrupted. Using transient stats instead.
經過排查,發現是mysql 的幾張系統表不見了,到底是那幾張呢?
MySQL 5.6的ibdata1表空間包含了5個InnoDB基礎表,如下:
mysql> select table_name from information_schema.tables where table_schema='mysql' and engine='InnoDB'; +----------------------+ | table_name | +----------------------+ | innodb_index_stats | | innodb_table_stats | | slave_master_info | | slave_relay_log_info | | slave_worker_info | +----------------------+ 5 rows in set (0.00 sec)
在MySQL 5.6之前,如果關閉MySQL後刪除ibdata1,再重新啓動MySQL的時候ibdata1會被重新創建, 但從MySQL 5.6開始,這5個表不會被重建,究其緣由是因爲這幾張表的存儲引擎是innodb,而且在MySQL5.5 中並沒有這幾張表。大致來看看5.6與5.5系統表的區別:
MySQL 5.5 系統表 +---------------------------+ | columns_priv | | db | | event | | func | | help_category | | help_keyword | | help_relation | | help_topic | | host | | ndb_binlog_index | | plugin | | proc | | procs_priv | | proxies_priv | | servers | | tables_priv | | time_zone | | time_zone_leap_second | | time_zone_name | | time_zone_transition | | time_zone_transition_type | | user | +---------------------------+ 22 rows in set (0.00 sec)
MySQL 5.6 系統表 +---------------------------+ | Tables_in_mysql | +---------------------------+ | columns_priv | | db | | event | | func | | general_log | | help_category | | help_keyword | | help_relation | | help_topic | | innodb_index_stats | | innodb_table_stats | | ndb_binlog_index | | plugin | | proc | | procs_priv | | proxies_priv | | servers | | slave_master_info | | slave_relay_log_info | | slave_worker_info | | slow_log | | tables_priv | | time_zone | | time_zone_leap_second | | time_zone_name | | time_zone_transition | | time_zone_transition_type | | user | +---------------------------+ 28 rows in set (0.00 sec)
由上述統計可以看到,在mysql5.6 中,除了增加了上述5張表,還添加了general_log 、slow_log 表,並且將5.5中的host表合到了5.6中的user表中。
在錯誤日誌中追溯原因,發現是在一次故障遷移中,刪除過ibdata1文件,在重啓之後,自動創建的ibdata1文件,但這幾張innodb系統表並沒加載到表空間中。這些錯誤雖然並不影響業務,但很影響備份,在錯誤日誌中大量出現,也是很煩的。
那麼對於這樣的錯誤,我們該如何處理?
1、如果是slave備機,停止複製,記錄pos等信息(對於不復制mysql庫來說,也沒有必要做這一步)
mysql>stop slave ;
2、刪除上述系統表
drop table mysql.innodb_index_stats;
drop table mysql.innodb_table_stats;
drop table mysql.slave_master_info;
drop table mysql.slave_relay_log_info;
drop table mysql.slave_worker_info ;
3、刪除相關的.frm與 .ibd 文件
rm -rf innodb_*_stats*
rm -rf slave_*
4、重新創建上述系統表
從其他機器上,使用mysqldump將這幾張表的表結構備份出來,放到該機器上重新執行,備份腳本如下:
#!/bin/sh TABLELIST="innodb_index_stats" TABLELIST="${TABLELIST} innodb_table_stats" TABLELIST="${TABLELIST} slave_master_info" TABLELIST="${TABLELIST} slave_relay_log_info" TABLELIST="${TABLELIST} slave_worker_info" mysqldump -uroot -p mysql ${TABLELIST} > mysql_innodb_tables.sql
將 mysql_innodb_tables.sql拷貝到出現壞表錯誤的那臺數據庫機器,並將其導入到系統庫mysql庫中.
# mysql -uroot -p mysql < mysql_innodb_tables.sql
運行FLUSH TABLES(可選)
5、重啓數據庫
6、啓動slave,如果報錯,重新change master
7、重新確定錯誤日誌中有無類似報錯
注意:不要輕易刪除ibdata1文件,在不同的版本、不同的分支,系統表都有可能不太一樣,如mysql 5.6 與 MariaDB 10.0的系統表,mysql5.5 與mysql 5.6 的 系統表等等,在做遷移或升級時,很容易忽略掉這些細節,所以在做之前,一定要備份,不要任性而爲。