參數innodb_force_recovery影響了整個InnoDB存儲引擎的恢復狀況。該值默認為0,表示當需要恢復時執行所有的恢復操作。當不能進行有效恢復時,如數據頁發生了corruption,MySQL數據庫可能會宕機,並把錯誤寫入錯誤日志中。
但是,在某些情況下,我們可能並不需要執行完整的恢復操作,我們自己知道如何進行恢復。比如正在對一個表執行alter table操作,這時意外發生了,數據庫重啟時會對InnoDB表執行回滾操作。對於一個大表,這需要很長時間,甚至可能是幾個小時。這時我們可以自行進行恢復,例如可以把表刪除,從備份中重新將數據導入表中,這些操作的速度可能要遠遠快於回滾操作。
innodb_force_recovery還可以設置為6個非零值: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):不查看撤銷日志(Undo Log),InnoDB存儲引擎會將未提交的事務視為已提交。
- 6(SRV_FORCE_NO_LOG_REDO):不執行前滾的操作。
需要注意的是,當設置參數innodb_force_recovery大於0后,可以對表進行select、create、drop操作,但insert、update或者delete這類操作是不允許的。
模擬故障
我們來做個實驗,模擬故障的發生。在第一會話中,對一張接近1 000W行的InnoDB存儲引擎表執行更新操作,但是完成后不要馬上提交:
start transaction;
update Profile set password='';
--start transaction語句開啟了事務,同時防止了自動提交的發生,update操作則會產生大量的回滾日志。這時,我們人為地kill掉MySQL數據庫服務器。
ps-ef|grep mysqld
kill-9 pid
通過kill命令,我們人為地模擬了一次數據庫宕機故障,當MySQL數據庫下次啟動時會對update的這個事務執行回滾操作,而這些信息都會記錄在錯誤日志文件中,默認后綴名為err。如果查看錯誤日志文件,可得到如下結果:
090922 13:40:20 InnoDB:Started;log sequence number 6 2530474615 InnoDB:Starting in background the rollback of uncommitted transactions 090922 13:40:20 InnoDB:Rolling back trx with id 0 5281035,8867280 rows to undo InnoDB:Progress in percents:1090922 13:40:20 090922 13:40:20[Note]/usr/local/mysql/bin/mysqld:ready for connections. Version:'5.0.45-log'socket:'/tmp/mysql.sock'port:3306 MySQL Community Server(GPL) 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 InnoDB:Rolling back of trx id 0 5281035 completed 090922 13:49:21 InnoDB:Rollback of non-prepared transactions completed
可以看到,如果采用默認的策略,即把innodb_force_recovery設為0,InnoDB會在每次啟動后對發生問題的表執行恢復操作,通過錯誤日志文件,可知這次回滾操作需要回滾8 867 280行記錄,總共耗時約9分多鍾。
我們做再做一次同樣的測試,只不過在啟動MySQL數據庫前將參數innodb_force_recovery設為3,然后觀察InnoDB存儲引擎是否還會執行回滾操作,查看錯誤日志文件,可看到:
090922 14:26:23 InnoDB:Started;log sequence number 7 2253251193 InnoDB:!innodb_force_recovery is set to 3! 090922 14:26:23[Note]/usr/local/mysql/bin/mysqld:ready for connections. Version:'5.0.45-log'socket:'/tmp/mysql.sock'port:3306 MySQL Community Server(GPL)
這里出現了“!”,InnoDB警告你已經將innodb_force_recovery設置為3,不會進行undo的回滾操作了。因此數據庫很快啟動完成,但是你應該很小心當前數據庫的狀態,並仔細確認是否不需要回滾操作。