利用innodb_force_recovery修復MySQL數據頁損壞


  現象:啟動MySQL服務時報1067錯誤,服務無法啟動。

  查看xxx.err錯誤日志發現有數據頁損壞信息:

    InnoDB: Database page corruption on disk or a failed

    InnoDB: file read of page 200.

  出現上述現象是由於突然斷電、強制關機、強制殺死MySQL進程等操作所導致的。

 

  首先修改my.ini中的innodb_force_recovery參數(4-6),使mysqld跳過恢復步驟,將mysqld 啟動,將數據導出來然后重建數據庫。

  innodb_force_recovery可以設置為1-6,大的數字包含前面所有數字的影響。

     1. (SRV_FORCE_IGNORE_CORRUPT):忽略檢查到的corrupt頁。

     2. (SRV_FORCE_NO_BACKGROUND):阻止主線程的運行,如主線程需要執行full purge操作,會導致crash

     3. (SRV_FORCE_NO_TRX_UNDO):不執行事務回滾操作。

     4. (SRV_FORCE_NO_IBUF_MERGE):不執行插入緩沖的合並操作。

     5. (SRV_FORCE_NO_UNDO_LOG_SCAN):不查看重做日志,InnoDB存儲引擎會將未提交的事務視為已提交。

     6. (SRV_FORCE_NO_LOG_REDO):不執行前滾的操作。

   注意 

     當設置參數值大於0后,可以對表進行select,create,drop操作,insert,update或者delete這類操作是不允許的。

  

  可以嘗試使用MySQLbin目錄下的mysqlcheck.exe工具來嘗試發現並修復MyISAM表的損壞數據頁。

  如果僅是MyISAM數據頁損壞,修復后,刪除my.ini中的innodb_force_recovery參數,嘗試啟動。

  如果是InnoDB數據表發生了數據頁損壞,需要導出數據,重新建庫。

  可以嘗試運行

    select concat('select 1 from ',table_name,';') from information_schema.tables where table_schema='xxx';查詢到的結果定位哪些InnoDB出現了損壞,嘗試使用冗余數據修復。

 

  最后使用MySQL5\bin>mysqldump -uroot -pOSSDB123 databasename >e:\xxx.sql導出表結構和數據,使用load重建建庫。也可以使用SELECT INTO OUTFILE從數據庫轉儲你的表,通常以這種方法獲取的數據是完好的。

  

  

  下面是網上的一篇相關的文章:

  1.     表損壞的原因分析 

  以下原因是導致mysql 表毀壞的常見原因: 

    1、 服務器突然斷電導致數據文件損壞。 

    2、 強制關機,沒有先關閉mysql 服務。 

    3、 mysqld 進程在寫表時被殺掉。 

    4、 使用myisamchk 的同時,mysqld 也在操作表。    

    5、 磁盤故障。  

    6、 服務器死機。 

    7、 mysql 本身的bug 。 

 

  2.表損壞的症狀           

  一個損壞的表的典型症狀如下: 

     1 、當在從表中選擇數據之時,你得到如下錯誤:  

      Incorrect key file for table: '...'. Try to repair it 

     2 、查詢不能在表中找到行或返回不完全的數據。 

     3 Error: Table 'p' is marked as crashed and should be repaired 。 

     4 、打開表失敗: Cant open file: ‘×××.MYI’ (errno: 145) 

  

  3.預防 MySQL 表損壞 

   可以采用以下手段預防mysql 表損壞:  

    1 、定期使用myisamchk 檢查MyISAM 表(注意要關閉mysqld ),推薦使用check table 來檢查表(不用關閉mysqld )。 

    2 、在做過大量的更新或刪除操作后,推薦使用OPTIMIZE TABLE 來優化表,這樣既減少了文件碎片,又減少了表損壞的概率。 

    3 、關閉服務器前,先關閉mysqld (正常關閉服務,不要使用kill -9 來殺進程)。 

    4 、使用ups 電源,避免出現突然斷電的情況。 

    5 、使用最新的穩定發布版mysql ,減少mysql 本身的bug 導致表損壞。 

    6 、對於InnoDB 引擎,你可以使用innodb_tablespace_monitor 來檢查表空間文件內文件空間管理的完整性。 

    7 、對磁盤做raid ,減少磁盤出錯並提高性能。 

    8 、數據庫服務器最好只跑mysqld 和必要的其他服務,不要跑其他業務服務,這樣減少死機導致表損壞的可能。 

    9 、不怕萬一,只怕意外,平時做好備份是預防表損壞的有效手段。 

  4. MySQL 表損壞的修復 

  MyISAM 表可以采用以下步驟進行修復 : 

    1、  使用 reapair table myisamchk 來修復。  

    2、  如果上面的方法修復無效,采用備份恢復表。 

 

  具體可以參考如下做法: 

  階段:檢查你的表 

    如果你有很多時間,運行myisamchk *.MYI myisamchk -e *.MYI 。使用-s (沉默)選項禁止不必要的信息。  

    如果mysqld 服務器處於宕機狀態,應使用--update-state 選項來告訴myisamchk 將表標記為檢查過的。 

    你必須只修復那些myisamchk 報告有錯誤的表。對這樣的表,繼續到階段。 

    如果在檢查時,你得到奇怪的錯誤例如out of memory 錯誤,或如果myisamchk 崩潰,到階段。 

  階段:簡單安全的修復 

    注釋:如果想更快地進行修復,當運行myisamchk 時,你應將sort_buffer_size Key_buffer_size 變量的值設置為可用內存的大約25% 。 

    首先,試試myisamchk -r -q tbl_name(-r -q 意味着“ 快速恢復模式”。這將試圖不接觸數據文件來修復索引文件。如果數據文件包含它應有的一切內容和指向數據文件內正確地點的刪除連接,這應該管用並且表可被修復。開始修復下一張表。否則,執行下列過程: 

    在繼續前對數據文件進行備份。 

    使用myisamchk -r tbl_name(-r 意味着“ 恢復模式”。這將從數據文件中刪除不正確的記錄和已被刪除的記錄並重建索引文件。 

    如果前面的步驟失敗,使用myisamchk --safe-recover tbl_name 。安全恢復模式使用一個老的恢復方法,處理常規恢復模式不行的少數情況但是更慢。 

    如果在修復時,你得到奇怪的錯誤例如out of memory 錯誤,或如果myisamchk 崩潰,到階段。  

  階段:困難的修復 

    只有在索引文件的第一個16K 塊被破壞,或包含不正確的信息,或如果索引文件丟失,你才應該到這個階段。在這種情況下,需要創建一個新的索引文件。按如下步驟操做: 

    把數據文件移到安全的地方。 

    使用表描述文件創建新的數據文件和索引文件: 

    shell> mysql db_name 

    mysql> SET AUTOCOMMIT=1; 

    mysql> TRUNCATE TABLE tbl_name; 

    mysql> quit  

    如果你的MySQL 版本沒有TRUNCATE TABLE ,則使用DELETE FROM tbl_name 。 

    將老的數據文件拷貝到新創建的數據文件之中。(不要只是將老文件移回新文件之中;你要保留一個副本以防某些東西出錯。) 

    回到階段。現在myisamchk -r -q 應該工作了。(這不應該是一個無限循環)。 

    你還可以使用REPAIR TABLE tbl_name USE_FRM ,將自動執行整個程序。 

  階段:非常困難的修復 

    只有.frm 描述文件也破壞了,你才應該到達這個階段。這應該從未發生過,因為在表被創建以后,描述文件就不再改變了。 

     從一個備份恢復描述文件然后回到階段。你也可以恢復索引文件然后回到階段。對后者,你應該用myisamchk -r 啟動。 

    如果你沒有進行備份但是確切地知道表是怎樣創建的,在另一個數據庫中創建表的一個拷貝。刪除新的數據文件,然后從其他數據庫將描述文件和索引文件移到破壞的數據庫中。這樣提供了新的描述和索引文件,但是讓.MYD 數據文件獨自留下來了。回到階段並且嘗試重建索引文件。 

 

  InnoDB 表可以采用下面的方法修復: 

    如果數據庫頁被破壞,你可能想要用SELECT INTO OUTFILE 從從數據庫轉儲你的表,通常以這種方法獲取的大多數數據是完好的。即使這樣,損壞可能導致SELECT * FROM tbl_name 或者InnoDB 后台操作崩潰或斷言,或者甚至使得InnoDB 前滾恢復崩潰。 盡管如此,你可以用它來強制InnoDB 存儲引擎啟動同時阻止后台操作運行,以便你能轉儲你的表。例如:你可以在重啟服務器之前,在選項文件的[mysqld] 節添加如下的行: 

        [mysqld]innodb_force_recovery = 4innodb_force_recovery 被允許的非零值如下。一個更大的數字包含所有更小數字的預防措施。如果你能夠用一個多數是的選項值來轉儲你的表,那么你是比較安全的,只有一些在損壞的單獨頁面上的數據會丟失。一個為的值更誇張,因為數據庫頁被留在一個陳舊的狀態,這個狀態反過來可以引發對樹和其它數據庫結構的更多破壞。 

        1 (SRV_FORCE_IGNORE_CORRUPT) 

      即使服務器檢測到一個損壞的頁,也讓服務器運行着;試着讓SELECT * FROM tbl_name 跳過損壞的索引記錄和頁,這樣有助於轉儲表。 

        2 (SRV_FORCE_NO_BACKGROUND) 

      阻止主線程運行,如果崩潰可能在凈化操作過程中發生,這將阻止它。 

         3 (SRV_FORCE_NO_TRX_UNDO) 

      恢復后不運行事務回滾。 

         4 (SRV_FORCE_NO_IBUF_MERGE) 

      也阻止插入緩沖合並操作。如果你可能會導致一個崩潰。最好不要做這些操作,不要計算表統計表。 

         5 (SRV_FORCE_NO_UNDO_LOG_SCAN) 

       啟動數據庫之時不查看未完成日志:InnoDB 把未完成的事務視為已提交的。 

         6 (SRV_FORCE_NO_LOG_REDO) 

      不要在恢復連接中做日志前滾。 

      數據庫不能另外地帶着這些選項中被允許的選項來使用。作為一個安全措施,當innodb_force_recovery 被設置為大於的值時,InnoDB 阻止用戶執行INSERT, UPDATE DELETE 操作

      即使強制恢復被使用,你也可以DROP CREATE 表。如果你知道一個給定的表正在導致回滾崩潰,你可以移除它。你也可以用這個來停止由失敗的大宗導入或失敗的ALTER TABLE 導致的失控回滾。你可以殺掉mysqld 進程,然后設置innodb_force_recovery ,使得數據庫被掛起而不需要回滾,然后舍棄導致失控回滾的表。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM