1. 表損壞的原因分析
創新互聯公司專注于企業營銷型網站建設、網站重做改版、南縣網站定制設計、自適應品牌網站建設、H5頁面制作、商城網站建設、集團公司官網建設、成都外貿網站建設公司、高端網站制作、響應式網頁設計等建站業務,價格優惠性價比高,為南縣等各大城市提供網站開發制作服務。
以下原因是導致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 、打開表失敗: Can’t open file: ‘×××.MYI’ (errno: 145) 。
5 、
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、 如果上面的方法修復無效,采用備份恢復表。
具體可以參考如下做法:
階段1 :檢查你的表
如果你有很多時間,運行myisamchk *.MYI 或myisamchk -e *.MYI 。使用-s (沉默)選項禁止不必要的信息。
如果mysqld 服務器處于宕機狀態,應使用--update-state 選項來告訴myisamchk 將表標記為’ 檢查過的’ 。
你必須只修復那些myisamchk 報告有錯誤的表。對這樣的表,繼續到階段2 。
如果在檢查時,你得到奇怪的錯誤( 例如out of memory 錯誤) ,或如果myisamchk 崩潰,到階段3 。
階段2 :簡單安全的修復
注釋:如果想更快地進行修復,當運行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 崩潰,到階段3 。
階段3 :困難的修復
只有在索引文件的第一個16K 塊被破壞,或包含不正確的信息,或如果索引文件丟失,你才應該到這個階段。在這種情況下,需要創建一個新的索引文件。按如下步驟操做:
把數據文件移到安全的地方。
使用表描述文件創建新的( 空) 數據文件和索引文件:
shell mysql db_name
mysql SET AUTOCOMMIT=1;
mysql TRUNCATE TABLE tbl_name;
mysql quit
如果你的MySQL 版本沒有TRUNCATE TABLE ,則使用DELETE FROM tbl_name 。
將老的數據文件拷貝到新創建的數據文件之中。(不要只是將老文件移回新文件之中;你要保留一個副本以防某些東西出錯。)
回到階段2 。現在myisamchk -r -q 應該工作了。(這不應該是一個無限循環)。
你還可以使用REPAIR TABLE tbl_name USE_FRM ,將自動執行整個程序。
階段4 :非常困難的修復
只有.frm 描述文件也破壞了,你才應該到達這個階段。這應該從未發生過,因為在表被創建以后,描述文件就不再改變了。
從一個備份恢復描述文件然后回到階段3 。你也可以恢復索引文件然后回到階段2 。對后者,你應該用myisamchk -r 啟動。
如果你沒有進行備份但是確切地知道表是怎樣創建的,在另一個數據庫中創建表的一個拷貝。刪除新的數據文件,然后從其他數據庫將描述文件和索引文件移到破壞的數據庫中。這樣提供了新的描述和索引文件,但是讓.MYD 數據文件獨自留下來了。回到階段2 并且嘗試重建索引文件。
InnoDB 表可以采用下面的方法修復:
如果數據庫頁被破壞,你可能想要用SELECT INTO OUTFILE 從從數據庫轉儲你的表,通常以這種方法獲取的大多數數據是完好的。即使這樣,損壞可能導致SELECT * FROM tbl_name 或者InnoDB 后臺操作崩潰或斷言,或者甚至使得InnoDB 前滾恢復崩潰。 盡管如此,你可以用它來強制InnoDB 存儲引擎啟動同時阻止后臺操作運行,以便你能轉儲你的表。例如:你可以在重啟服務器之前,在選項文件的[mysqld] 節添加如下的行:
[mysqld]innodb_force_recovery = 4innodb_force_recovery 被允許的非零值如下。一個更大的數字包含所有更小數字的預防措施。如果你能夠用一個多數是4 的選項值來轉儲你的表,那么你是比較安全的,只有一些在損壞的單獨頁面上的數據會丟失。一個為6 的值更夸張,因為數據庫頁被留在一個陳舊的狀態,這個狀態反過來可以引發對B 樹和其它數據庫結構的更多破壞。
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 被設置為大于0 的值時,InnoDB 阻止用戶執行INSERT, UPDATE 或DELETE 操作.
即使強制恢復被使用,你也可以DROP 或CREATE 表。如果你知道一個給定的表正在導致回滾崩潰,你可以移除它。你也可以用這個來停止由失敗的大宗導入或失敗的ALTER TABLE 導致的失控回滾。你可以殺掉mysqld 進程,然后設置innodb_force_recovery 為3 ,使得數據庫被掛起而不需要回滾,然后舍棄導致失控回滾的表。
網上找的
一、背景
近期,公司RDS云產品的MySQL Server版本進行升級,由目前使用的5.7.26版本升級到最新版本5.7.31;升級后測試同學發現:在MySQL創建用戶后,5.7.31版本重新啟動集群會出現啟動失敗的現象;而5.7.26版本在相同測試場景下是正常啟動的。這到底是為什么呢?
二、問題復現
2.1 實驗環境
2.2 操作步驟
按照測試同學的測試步驟,首先創建一個用戶:
然后關閉mysqld;這里需要介紹一下,我們集群的關閉方式是如下方式:
這種方式的內部實現類似于kill -9模式。所以我在線下環境使用kill -9的方式來復現,操作如下:
然后重啟mysqld,操作如下:
此時問題復現了,mysqld啟動失敗,我們查看了下error日志,信息如下:
根據報錯信息可以看出:MySQL的權限系統表發生了損壞,導致了mysqld啟動失敗;由于在MySQL 5.7及其之前版本該表是MyISAM引擎,且該引擎不支持事務,所以在mysqld異常崩潰會導致該類型引擎表的損壞;但在mysqld啟動時是有參數控制MyISAM引擎的恢復模式,且該參數在我們產品中也配置到了my點吸煙 f中,如下所示:
2.3 參數解析
對于該參數的官方文檔的解釋如下:
設置MyISAM存儲引擎恢復模式。選項值是OFF、DEFAULT、BACKUP、FORCE或QUICK的值的任意組合。如果指定多個值,請用逗號分隔。指定不帶參數的選項與指定DEFAULT相同,指定顯式值" "將禁用恢復(與OFF值相同)。如果啟用了恢復,則mysqld每次打開MyISAM表時,都會檢查該表是否標記為已崩潰或未正確關閉。(只有在禁用外部鎖定的情況下運行,最后一個選項才起作用。)在這種情況下,mysqld在表上運行檢查。如果表已損壞,mysqld將嘗試對其進行修復。
服務器自動修復表之前,它將有關修復的注釋寫到錯誤日志中。如果您希望能夠在無需用戶干預的情況下從大多數問題中恢復,則應使用選項BACKUP,FORCE。即使某些行將被刪除,這也會強制修復表,但是它將舊的數據文件保留為備份,以便您以后可以檢查發生了什么。
全局變量,只讀變量,默認為OFF。
三、問題修復
這類MySQL用戶表損耗的問題解決方式也是有多種,我這里列舉其中一種:
(1)my點吸煙 f中的[mysqld]標簽下添加skip_grant_tables,啟動時跳過加載系統字典。
(2)重啟mysqld,然后修復mysql schema下的所有表。
(3)在[mysqld]標簽下注釋或刪除掉skip_grant_tables,然后重啟mysqld。
此時mysqld是可以正常啟動的,無異常。
四、深入排查
在產品化中,以上修復方式很不優雅,只是作為臨時的解決方案;并且也存在一些令人疑惑的點:
帶著這些疑問,我們繼續排查出現該現象的原因;此時Google也沒有找到一些有效的信息,那么只能通過MySQL源代碼來尋找一些答案。
首先需要下載mysql 5.7.31版本的源代碼,并搭建mysql debug環境;具體步驟可以自動Google搜索一下,本文就不再贅述了。
在源代碼中搜索一下關鍵詞,用于打斷點的位置,然后進行調試:
定位到相關代碼,大概是sql/mysqld.cc的4958行,且存在if條件判斷,此時我們開始調試:
通過以上調試信息,可以判斷出acl_init函數返回的值為真;此時我們查看該函數的代碼 (sql/auth/sql_auth_cache.cc:1365):
根據該函數的注釋發現:該函數是初始化負責用戶/數據庫級特權檢查的結構,并從mysql schema中的表中為其加載特權信息;且return值為1代表的是初始化權限失敗。
此后開始逐步調試,觀察return相關信息,當調試到lock_table_names函數時,我們發現在Phase 3時return值為true,且根據代碼注釋發現true代表是Failure;具體代碼如下(sql/sql_base.cc:5549):
調試信息如下:
可以看到flags的值為0,而MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK為宏定義值0x1000,與flags的值 做按位與操作,結果自然也是0,當然MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY也是如此;need_global_read_lock_protection是bool類型值,代表是否需要全局讀鎖的保護,這個值是在table- mdl_request.type不為MDL_SHARED_READ_ONLY發生改變;check_readonly函數相關信息 下面概述。
此時也查看了下MySQL 5.7.26版本代碼作為對比,發現lock_table_names函數下的Phase 3后的部分代 碼是在5.7.29版本后新增的。如果是git clone的MySQL代碼可以用git blame命令查詢文件變化的信息:
上述展示的信息中,最左側的列值為commit id為05824063和0405ebee,有興趣的同學可以詳細看下。
此功能解決的問題是 BUG#28438114: SET READ_ONLY=1 SOMETIMES DOESN'T BLOCK CONCURRENT DDL.;當然這個代碼的變更功能也在5.7 Release Notes中有所體現,如下所示( m/doc/relnotes/mysql/5.7/en/news-5-7-29.html ):
最后我們再查看下check_readonly函數,該函數是基于read_only和super_read_only狀態執行標準化檢查,是禁止(TRUE)還是允許(FALSE)操作。代碼如下(sql/auth/sql_authorization.cc:489):
此時第一反應就是去檢查my點吸煙 f中是否包含read_only相關參數,檢查之后發現確實是使用了該參數, 如下:
此時注釋掉該參數,然后再次啟動mysqld,發現MyISAM表可以自動修復,且正常啟動;error log信息如下:
由于docker一些限制,我們在mysqld啟動會涉及兩次;所以解決該問題的方式為:第一次mysqld的啟動時先關閉read_only參數,第二次啟動時開啟read_only參數。之所以選擇默認開啟read_only參數, 是為了避免在mysqld啟動后,選主邏輯未完成時的保護措施;當然選主完成后,會自動對master執行 set global read_only=0 操作。
五、總結
六、附錄
調試的棧幀信息如下,有興趣的小伙伴可以研究下:
熟悉MySQL體系結構和innodb存儲引擎工作原理;以及MySQL備份恢復、復制、數據遷移等技術;專注于MySQL、MariaDB開源數據庫,喜好開源技術。
原文鏈接:
5.9.4. 表維護和崩潰恢復
后面幾節討論如何使用myisamchk來檢查或維護MyISAM表(對應.MYI和.MYD文件的表)。
你可以使用myisamchk實用程序來獲得有關你的數據庫表的信息或檢查、修復、優化他們。下列小節描述如何調用myisamchk(包括它的選項的描述),如何建立表的維護計劃,以及如何使用myisamchk執行各種功能。
盡管用myisamchk修復表很安全,在修復(或任何可以大量更改表的維護操作)之前先進行備份也是很好的習慣
影響索引的myisamchk操作會使ULLTEXT索引用full-text參數重建,不再與MySQL服務器使用的值兼容。要想避免,請閱讀5.9.5.1節,“用于myisamchk的一般選項”的說明。
在許多情況下,你會發現使用SQL語句實現MyISAM表的維護比執行myisamchk操作要容易地多:
· 要想檢查或維護MyISAM表,使用CHECK TABLE或REPAIR TABLE。
· 要想優化MyISAM表,使用OPTIMIZE TABLE。
· 要想分析MyISAM表,使用ANALYZE TABLE。
可以直接這些語句,或使用mysqlcheck客戶端程序,可以提供命令行接口。
這些語句比myisamchk有利的地方是服務器可以做任何工作。使用myisamchk,你必須確保服務器在同一時間不使用表。否則,myisamchk和服務器之間會出現不期望的相互干涉。
5.9.5. myisamchk:MyISAM表維護實用工具
5.9.5.1. 用于myisamchk的一般選項
5.9.5.2. 用于myisamchk的檢查選項
5.9.5.3. myisamchk的修復選項
5.9.5.4. 用于myisamchk的其它選項
5.9.5.5. myisamchk內存使用
5.9.5.6. 將myisamchk用于崩潰恢復
5.9.5.7. 如何檢查MyISAM表的錯誤
5.9.5.8. 如何修復表
5.9.5.9. 表優化
可以使用myisamchk實用程序來獲得有關數據庫表的信息或檢查、修復、優化他們。myisamchk適用MyISAM表(對應.MYI和.MYD文件的表)。
調用myisamchk的方法:
shell myisamchk [options] tbl_name ...
options指定你想讓myisamchk做什么。在后面描述它們。還可以通過調用myisamchk --help得到選項列表。
tbl_name是你想要檢查或修復的數據庫表。如果你不在數據庫目錄的某處運行myisamchk,你必須指定數據庫目錄的路徑,因為myisamchk不知道你的數據庫位于哪兒。實際上,myisamchk不在乎你正在操作的文件是否位于一個數據庫目錄;你可以將對應于數據庫表的文件拷貝到別處并且在那里執行恢復操作。
如果你愿意,可以用myisamchk命令行命名幾個表。還可以通過命名索引文件(用“ .MYI”后綴)來指定一個表。它允許你通過使用模式“*.MYI”指定在一個目錄所有的表。例如,如果你在數據庫目錄,可以這樣在目錄下檢查所有的MyISAM表:
shell myisamchk *.MYI
如果你不在數據庫目錄下,可通過指定到目錄的路徑檢查所有在那里的表:
shell myisamchk /path/to/database_dir/*.MYI
你甚至可以通過為MySQL數據目錄的路徑指定一個通配符來檢查所有的數據庫中的所有表:
shell myisamchk /path/to/datadir/*/*.MYI
推薦的快速檢查所有MyISAM表的方式是:
shell myisamchk --silent --fast /path/to/datadir/*/*.MYI
如果你想要檢查所有MyISAM表并修復任何破壞的表,可以使用下面的命令:
shell myisamchk --silent --force --fast --update-state \
-O key_buffer=64M -O sort_buffer=64M \
-O read_buffer=1M -O write_buffer=1M \
/path/to/datadir/*/*.MYI
該命令假定你有大于64MB的自由內存。關于用myisamchk分配內存的詳細信息,參見5.9.5.5節,“myisamchk內存使用”。
當你運行myisamchk時,必須確保其它程序不使用表。否則,當你運行myisamchk時,會顯示下面的錯誤消息:
warning: clients are using or haven't closed the table properly
這說明你正嘗試檢查正被另一個還沒有關閉文件或已經終止而沒有正確地關閉文件的程序(例如mysqld服務器)更新的表。
如果mysqld正在運行,你必須通過FLUSH TABLES強制清空仍然在內存中的任何表修改。當你運行myisamchk時,必須確保其它程序不使用表。避免該問題的最容易的方法是使用CHECK TABLE而不用myisamchk來檢查表。
5.9.5.1. 用于myisamchk的一般選項
本節描述的選項可以用于用myisamchk執行的任何類型的表維護操作。本節后面的章節中描述的選項只適合具體操作,例如檢查或修復表。
· --help,-?
顯示幫助消息并退出。
· --debug=debug_options, -# debug_options
輸出調試記錄文件。debug_options字符串經常是'd:t:o,filename'。
· --silent,-s
沉默模式。僅當發生錯誤時寫輸出。你能使用-s兩次(-ss)使myisamchk沉默。
· --verbose,-v
冗長模式。打印更多的信息。這能與-d和-e一起使用。為了更冗長,使用-v多次(-vv, -vvv)!
· --version, -V
顯示版本信息并退出。
· --wait, -w
如果表被鎖定,不是提示錯誤終止,而是在繼續前等待到表被解鎖。請注意如果用--skip-external-locking選項運行mysqld,只能用另一個myisamchk命令鎖定表。
還可以通過--var_name=value選項設置下面的變量:
變量
默認值
decode_bits
9
ft_max_word_len
取決于版本
ft_min_word_len
4
ft_stopword_file
內建列表
key_buffer_size
523264
myisam_block_size
1024
read_buffer_size
262136
sort_buffer_size
2097144
sort_key_blocks
16
stats_method
nulls_unequal
write_buffer_size
262136
可以用myisamchk --help檢查myisamchk變量及其 默認值:
當用排序鍵值修復鍵值時使用sort_buffer_size,使用--recover時這是很普通的情況。
當用--extend-check檢查表或通過一行一行地將鍵值插入表中(如同普通插入)來修改鍵值時使用Key_buffer_size。在以下情況通過鍵值緩沖區進行修復:
· 使用--safe-recover。
· 當直接創建鍵值文件時,需要對鍵值排序的臨時文件有兩倍大。通常是當CHAR、VARCHAR、或TEXT列的鍵值較大的情況,因為排序操作在處理過程中需要保存全部鍵值。如果你有大量臨時空間,可以通過排序強制使用myisamchk來修復,可以使用--sort-recover選項。
通過鍵值緩沖區的修復占用的硬盤空間比使用排序么少,但是要慢。
如果想要快速修復,將key_buffer_size和sort_buffer_size變量設置到大約可用內存的25%。可以將兩個變量設置為較大的值,因為一個時間只使用一個變量。
myisam_block_size是用于索引塊的內存大小。
stats_method影響當給定--analyze選項時,如何為索引統計搜集處理NULL值。它如同myisam_stats_method系統變量。詳細信息參見5.3.3節,“服務器系統變量”和7.4.7節,“MyISAM索引統計集合”的myisam_stats_method的描述。
ft_min_word_len和ft_max_word_len表示FULLTEXT索引的最小和最大字長。ft_stopword_file為停止字文件的文件名。需要在以下環境中對其進行設置。
如果你使用myisamchk來修改表索引(例如修復或分析),使用最小和最大字長和停止字文件的 默認全文參數值(除非你另外指定)重建FULLTEXT索引。這樣會導致查詢失敗。
出現這些問題是因為只有服務器知道這些參數。它們沒有保存在MyISAM索引文件中。如果你修改了服務器中的最小或最大字長或停止字文件,要避免該問題,為用于mysqld的myisamchk指定相同的ft_min_word_len,ft_max_word_len和ft_stopword_file值。例如,如果你將最小字長設置為3,可以這樣使用myisamchk來修復表:
shell myisamchk --recover --ft_min_word_len=3 tbl_name.MYI
要想確保myisamchk和服務器使用相同的全文
分享題目:mysql表壞了怎么辦 mysql表信息
文章路徑:http://vcdvsql.cn/article40/ddijeeo.html
成都網站建設公司_創新互聯,為您提供品牌網站設計、自適應網站、網站排名、網站維護、定制網站、靜態網站
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯