MySQL服務(wù)無法啟動(dòng)的問題有可能是:
/A/ 第一反應(yīng)
A/1 初始步驟
A/2 如果 MySQL崩潰
/B/ 識(shí)別問題
B/1 檢查日志
B/1.1 頁面損壞
B/1.2 InnoDB 時(shí)間旅行和日志序列號(hào)錯(cuò)誤
B/1.3 數(shù)據(jù)字典錯(cuò)誤
B/2 檢查表的錯(cuò)誤
B/2.1 使用 CHECK TABLE / mysqlcheck
B/2.2 使用innochecksum
/C/ 恢復(fù)你的數(shù)據(jù)
C/1 MySQL Utilities / 從 .frm 文件中提取 CREATE TABLE 語句
C/1.1 下載和安裝 MySQL Utilities
C/1.2 從 .frm 文件中提取 CREATE TABLE 語句
C/2 損壞的表
C/2.1 使用 CREATE .. LIKE 恢復(fù)表
C/2.2 恢復(fù)多個(gè)/所有 InnoDB 數(shù)據(jù)庫并重新創(chuàng)建 ibdata/ib_log 文件
C/3 日志序列號(hào)不匹配/將來
C/3.1 刪除和重新創(chuàng)建數(shù)據(jù)
C/3.2 重新創(chuàng)建 ib_logfiles
C/3.3 執(zhí)行引擎交換
C/4 數(shù)據(jù)字典問題
C/4.1 如何正確刪除 .ibd 文件
C/4.2 .ibd 文件丟失后重新創(chuàng)建表
C/4.3 .frm 文件存在但表不存在
C/4.4 孤立表或缺少 .frm 文件
以下是詳細(xì)的解決辦法:
/A/ 第一反應(yīng)
A/1 初始步驟 - 停止、備份、重新啟動(dòng)
1.停止MySQL 服務(wù)器。如果它已經(jīng)離線或正在崩潰,請(qǐng)?zhí)降?2 步。
代碼:
/scripts/restartsrv_mysql--stop這里的目標(biāo)是凍結(jié)數(shù)據(jù)和表文件的當(dāng)前狀態(tài),這樣就不會(huì)發(fā)生新的寫入,并且我們可以制作文件副本,而不用擔(dān)心會(huì)導(dǎo)致數(shù)據(jù)不一致或存儲(chǔ)信息丟失的更改。
2.備份您的數(shù)據(jù)和日志文件,如果不是整個(gè) MySQL 數(shù)據(jù)目錄。
代碼:
mkdir /root/innodb.bak (orbackuppathofyour choice) cd /var/lib/mysql (oralternatedatadirectory,ifconfigured) ddif=ibdata1of=ibdata1.bakconv=noerror cp -p ./ibdata* /root/innodb.bak/ cp -p ./ib_log* /root/innodb.bak/首先,您要?jiǎng)?chuàng)建一個(gè)目錄來放置任何文件副本,然后,您要在 /var/lib/mysql(或您的數(shù)據(jù)目錄)中創(chuàng)建 ibdata1 文件的本地備份,以及 ibdata 的備份和 ib_logfiles 進(jìn)入您的備份目錄。我喜歡同時(shí)使用 dd 和 cp 來制作 ibdata 文件的副本,因?yàn)檫@兩個(gè)實(shí)用程序之間的性質(zhì)不同。dd 使用程序復(fù)制原始文件,而 cp 將文件的內(nèi)容復(fù)制到新文件。我沒有經(jīng)歷過任何特殊情況,這對(duì)恢復(fù)成功至關(guān)重要,但我認(rèn)為這仍然是我的一個(gè)習(xí)慣,我懷疑這可能不是一個(gè)壞習(xí)慣。
理想情況下,特別是如果您還沒有備份,那么此時(shí)您可能會(huì)想要嘗試對(duì)您的數(shù)據(jù)目錄進(jìn)行完整的復(fù)制。
代碼:
cp -Rp /var/lib/mysql{,.orig}我意識(shí)到這對(duì)于緊急情況下的某些人來說可能過于耗時(shí)或不切實(shí)際,所以如果這不可行,那沒關(guān)系 - 數(shù)據(jù)文件和 InnoDB 數(shù)據(jù)庫目錄至少應(yīng)該提供一些可以在需要時(shí)依賴的東西。
3.備份你的 InnoDB 數(shù)據(jù)庫文件夾
假設(shè)您尚未備份完整的 MySQL 數(shù)據(jù)目錄,您仍然需要確保包含 InnoDB 表的任何數(shù)據(jù)庫也備份了各自的文件夾。如果您不確定您的哪些數(shù)據(jù)庫包含 InnoDB 表,您可以使用類似這樣的命令來檢查包含 .ibd 文件的目錄并將它們復(fù)制到您的備份文件夾(本示例中為 /root/innodb.bak - 另外,如果您的 DATADIR 不是默認(rèn)值,則需要在開始時(shí)更新變量):
代碼:
DATADIR=/var/lib/mysql; find$DATADIR-typef -name *.ibd | awk -F/{print $(NF-1)}| sort | uniq | xargs -I {} cp -Rp$DATADIR/{} /root/innodb.bak4.啟動(dòng)MySQL 服務(wù)器(如果可以的話)
此時(shí),可以安全地使 MySQL 重新聯(lián)機(jī),前提是您可以這樣做而不會(huì)導(dǎo)致崩潰。如果您可以將其聯(lián)機(jī),請(qǐng)繼續(xù)并啟動(dòng) MySQL 服務(wù),然后執(zhí)行 mysqldump - 我建議執(zhí)行以下操作(如果您愿意,可以將這些轉(zhuǎn)儲(chǔ)到 /root 以外的其他路徑 - 請(qǐng)記住您選擇的內(nèi)容):
代碼:
/etc/init.d/mysql start mysqldump --single-transaction -AER >/root/dump_wtrans.sql mysqldump -AER >/root/dump.sql使用單事務(wù)標(biāo)志轉(zhuǎn)儲(chǔ)它會(huì)在單個(gè)事務(wù)中創(chuàng)建轉(zhuǎn)儲(chǔ),這可以防止鎖定數(shù)據(jù)庫,并且如果您正在運(yùn)行 100% InnoDB 環(huán)境可能會(huì)有所幫助 - 所以為了安全起見,特別是如果您是不確定,我建議同時(shí)運(yùn)行。
請(qǐng)務(wù)必檢查您的 SQL 轉(zhuǎn)儲(chǔ)內(nèi)容以確保數(shù)據(jù)確實(shí)存在。在某些情況下,如果由于某種原因無法訪問數(shù)據(jù),則只會(huì)出現(xiàn)表結(jié)構(gòu)。如果您操作的數(shù)據(jù)庫經(jīng)常運(yùn)行 ALTER TABLE 命令,則在使用 --single-transaction 時(shí)尤其如此。如果 mysqldump 與特定表上的 ALTER TABLE 一致,則有可能只存在該結(jié)構(gòu)。(在 MySQL 錯(cuò)誤報(bào)告 71017中詳細(xì)討論)
注意:如果您正在處理文件系統(tǒng)損壞,請(qǐng)嘗試將這些文件備份到另一個(gè)磁盤驅(qū)動(dòng)器(如果可用)(或者甚至備份到安全的遠(yuǎn)程主機(jī),如果可行)
A/2 如果 MySQL 崩潰
如果 MySQL 有崩潰,并拒絕重新啟動(dòng),那么這可能是您目前主要關(guān)心的問題。當(dāng)然,您希望它在線用于生產(chǎn)目的,但最重要的是,讓 MySQL 在線可以讓您獲得數(shù)據(jù)的真實(shí) MySQL 轉(zhuǎn)儲(chǔ),這樣您就可以最大限度地減少永久丟失任何數(shù)據(jù)的機(jī)會(huì),并幫助修復(fù)可能存在的表損壞。
因?yàn)?InnoDB 的 ACID 合規(guī)性(MySQL :: MySQL 5.6 Reference Manual :: 14.2.1 MySQL and the ACID Model),它遵守嚴(yán)格的數(shù)據(jù)一致性標(biāo)準(zhǔn)。這實(shí)質(zhì)上意味著,如果它遇到任何數(shù)據(jù)問題,它幾乎總是會(huì)使 MySQL 崩潰,以防止進(jìn)一步的一致性問題。從理論上講,這是一件好事,但在實(shí)踐中,計(jì)劃外停機(jī)絕不是一件好事。
然而,使用 innodb_force_recovery 選項(xiàng)通常可以幫助至少讓 MySQL 回到可訪問狀態(tài)。也就是說,最好知道它為什么有效,以及如何小心使用它。
使用 innodb_force_recovery
默認(rèn)情況下,InnoDB 已經(jīng)嘗試基本恢復(fù)步驟,當(dāng)它發(fā)現(xiàn)問題時(shí),但通常情況下,您需要添加innodb_force_recovery在您的 /etc/my.cnf 文件中設(shè)置以幫助它。這指示 InnoDB 以恢復(fù)模式啟動(dòng),告訴它跳過 InnoDB 啟動(dòng)過程的各個(gè)部分,這通常是發(fā)生崩潰的地方。您需要從最低值 1 開始,然后僅根據(jù)需要增加它,最高可能值為 6。此設(shè)置在 my.cnf 文件的 [mysqld] 部分下輸入,如本示例所示:
代碼:
[mysqld]innodb_force_recovery=1您還可以運(yùn)行以下單行命令將其自動(dòng)添加到您的 /etc/my.cnf 文件中的正確部分下(將開頭的mode =變量中的數(shù)字更改為您想要使用的任何模式):
代碼:
mode=1; sed -i "/^\[mysqld\]/{N;s/$/\ninnodb_force_recovery=$mode/}" /etc/my.cnf然后,一旦您準(zhǔn)備好將服務(wù)器恢復(fù)到默認(rèn)模式,您可以使用以下命令刪除 innodb_force_recovery 行:
代碼:
sed-i/innodb_force_recovery/d/etc/my.cnf此配置選項(xiàng)不應(yīng)用作保持服務(wù)器在線的長(zhǎng)期甚至中期解決方案。如果您的服務(wù)器只能在啟用 innodb_force_recovery 的情況下保持在線,那么您的服務(wù)器上仍然存在需要解決的主要問題。如果 innodb_force_recovery 長(zhǎng)時(shí)間處于活動(dòng)狀態(tài),您可能會(huì)在服務(wù)器上創(chuàng)建更多問題,特別是如果設(shè)置為高值(沒有充分的理由將 innodb_force_recovery 長(zhǎng)時(shí)間設(shè)置為 6)。此模式完全是臨時(shí)的 - 僅用于恢復(fù)目的。
以下是每種模式的作用的簡(jiǎn)要概述(每種模式也會(huì)自行組合,這意味著較高的值包含所有較低值的特征):
模式 1 - 當(dāng)看到損壞的頁面時(shí)不會(huì)使 MySQL 崩潰模式 2 - 不運(yùn)行后臺(tái)操作模式 3 - 不嘗試回滾事務(wù)模式 4 - 不計(jì)算統(tǒng)計(jì)數(shù)據(jù)或應(yīng)用存儲(chǔ)/緩沖的更改模式 5 - 啟動(dòng)期間不查看撤消日志模式 6 - 啟動(dòng)期間不從重做日志 (ib_logfiles) 前滾例如:如果您的 MySQL 服務(wù)器以模式 3 啟動(dòng),而不是模式 2,則可以安全地假設(shè)崩潰與事務(wù)回滾過程有關(guān)。另外,請(qǐng)注意,從 MySQL 5.6.15 開始,模式 4-6 會(huì)將 MySQL 置于只讀模式。
如果您已經(jīng)經(jīng)歷了所有的 innodb_force_recovery 模式,并且您仍然因 InnoDB 錯(cuò)誤而崩潰,那么下一個(gè)最佳舉措是嘗試收集一些有關(guān)可能導(dǎo)致崩潰的額外信息
。/B/ 識(shí)別問題
InnoDB 問題可以通過多種不同的方式彈出,雖然籠統(tǒng)的術(shù)語腐敗通常用于涵蓋很多問題——通常是不準(zhǔn)確的——但嘗試具體確定你的問題通常是個(gè)好主意處理。
B/1 檢查日志
如果您懷疑 InnoDB 表或數(shù)據(jù)庫已損壞,可能是因?yàn)槟⒁獾綌?shù)據(jù)損壞、不存在的數(shù)據(jù)或拒絕啟動(dòng)的 MySQL 服務(wù)。對(duì)于任何這些情況,您首先要查看的是 MySQL 錯(cuò)誤日志。在典型設(shè)置中,這將位于 /var/lib/mysql/ 中,該文件將是您的主機(jī)名,帶有 .err 后綴。如果您不知道您的主機(jī)名,或者不想全部輸入(如果不是默認(rèn)值,請(qǐng)將數(shù)據(jù)目錄替換為您自己的),這里有一個(gè)快速命令可以提取日志中的最后 200 行:
代碼:
tail-200/var/lib/mysql/`hostname`.err這將執(zhí)行主機(jī)名命令,并使用返回的字符串代替主機(jī)名,這是命令行中反引號(hào)的功能。
您可能會(huì)在此處看到一些可以幫助您確定您遇到的腐敗類型(如果有)的內(nèi)容。在本指南中,我將介紹您將遇到的三種最常見的與損壞相關(guān)的問題——頁面損壞、日志序列號(hào)問題和數(shù)據(jù)字典問題。以下是一些示例,并解釋了它們的含義:
B/1.1 頁面損壞代碼:InnoDB: Database page corruption on disk or a failedInnoDB: file read of page 515891.這通常會(huì)在之前提供更多信息,您應(yīng)該注意這些信息,因?yàn)樗赡馨恍┯嘘P(guān)此損壞具體發(fā)生在何處的有用信息,但最終這會(huì)告訴您 InnoDB 似乎認(rèn)為您有頁面引用的頁面 ID 上存在損壞,或者可能只是無法以一種或另一種方式讀取文件。這不一定表明真正損壞的證據(jù),事實(shí)上,在某些情況下,這可能只是操作系統(tǒng)損壞其自己的文件緩存的結(jié)果。因此,通常建議嘗試重新啟動(dòng)計(jì)算機(jī) - 當(dāng)然是在進(jìn)行備份之后 - 然后再繼續(xù)進(jìn)行任何進(jìn)一步的操作。也就是說 - 如果重新啟動(dòng)確實(shí)解決了您的問題,您可能需要確保您的 RAM 沒有缺陷或即將淘汰,因?yàn)檫@可能是操作系統(tǒng)損壞其自己的文件緩存的常見原因之一。在嘗試任何恢復(fù)之前,您可能希望解決這種情況,以避免立即遇到同樣問題的風(fēng)險(xiǎn)。如果您不確定,或者您重新啟動(dòng)后仍然懷疑存在損壞,您可以運(yùn)行以下腳本來執(zhí)行對(duì)所有 .ibd 文件進(jìn)行innochecksum以嘗試識(shí)別損壞。如果 MySQL 仍然無法成功啟動(dòng),這將特別有用,因?yàn)樗苯釉谖募线\(yùn)行而無需 MySQL 訪問(事實(shí)上,如果它正在檢查的表空間在服務(wù)器上打開,它將無法工作):代碼:!/bin/bashfor i in $(ls /var/lib/mysql/*/*.ibd)doinnochecksum $idoneinnochecksum 實(shí)用程序查看表空間文件中的頁面,并計(jì)算每個(gè)頁面的校驗(yàn)和。然后,它將這些中的每一個(gè)與存儲(chǔ)的校驗(yàn)和進(jìn)行比較,并讓您知道是否存在不匹配。如果是這樣,那通常表明頁面已以某種方式損壞。如果沒有發(fā)現(xiàn)不匹配,它將不會(huì)顯示任何輸出(除非包含 -v 用于詳細(xì)輸出)。如果 MySQL 在線且可訪問,您始終可以使用 CHECK TABLE 語句,如下所述:MySQL :: MySQL 5.5 Reference Manual :: 13.7.2.2 CHECK TABLE SyntaxB/1.2 InnoDB 時(shí)間旅行和日志序列號(hào)錯(cuò)誤代碼:mysql: 120901 9:43:55 InnoDB: Error: page 70944 log sequence number 8 1483471899mysql: InnoDB: is in the future! Current system log sequence number 5 612394935.mysql: InnoDB: Your database may be corrupt or you may have copied the InnoDBmysql: InnoDB: tablespace but not the InnoDB log files. Seemysql: InnoDB: [url=http://dev.mysql.com/doc/refman/5.5/en/forcing-innodb-recovery.html]MySQL :: MySQL 5.5 Reference Manual :: 14.21.2 Starting InnoDB on a Corrupted Database[/url]首先,解釋一下究竟什么是日志序列號(hào) (LSN)。對(duì)于 InnoDB 引擎上發(fā)生的每個(gè)操作,記錄都會(huì)寫入重做日志文件,默認(rèn)情況下,通常在 MySQL 數(shù)據(jù)目錄中被視為 ib_logfile0 和 ib_logfile1。這兩個(gè)文件有一個(gè)固定的大小(在 MySQL 5.6.8+ 中,每個(gè)文件默認(rèn)為 48M),記錄按順序?qū)懭脒@些文件,從第一個(gè)日志文件開始直到它到達(dá)末尾,然后繼續(xù)第二個(gè)日志文件。一旦它到達(dá)第二個(gè)日志文件的末尾(假設(shè)只配置了 2 個(gè)默認(rèn)日志文件 - 請(qǐng)參閱innodb_log_files_in_group),它會(huì)重新開始并再次開始在第一個(gè)日志文件的開頭寫入。這些記錄中的每一個(gè)都被賦予一個(gè)關(guān)聯(lián)的 LSN。此外,當(dāng)數(shù)據(jù)庫被修改時(shí),該數(shù)據(jù)庫中的特定頁面也會(huì)被賦予一個(gè)關(guān)聯(lián)的 LSN。在這兩者之間,這些 LSN 會(huì)一起檢查,以確保以正確的順序執(zhí)行操作。LSN 本身本質(zhì)上是日志文件的偏移量,存儲(chǔ)在數(shù)據(jù)庫頁面標(biāo)題中的 LSN 告訴 InnoDB 需要刷新多少日志。在某個(gè)地方,無論是意外重啟、內(nèi)存問題、文件系統(tǒng)損壞、復(fù)制問題、手動(dòng)更改 InnoDB 文件還是其他原因,這些 LSN 都變得不同步。無論它是否使您的服務(wù)器崩潰,這都應(yīng)該被視為合法的損壞,并且通常是您想要解決的問題B/1.3 數(shù)據(jù)字典錯(cuò)誤代碼:[ERROR] Table ./database/table has no primary key in InnoDB data dictionary, but has one in MySQL!InnoDB: Error: table database/tableInnoDB: in InnoDB data dictionary has tablespace id 423,InnoDB: but tablespace with that id or name does not exist. HaveInnoDB: you deleted or moved .ibd files?[ERROR] Cannot find or open table database/table fromthe internal data dictionary of InnoDB though the .frm file for thetable exists. Maybe you have deleted and recreated InnoDB datafiles but have forgotten to delete the corresponding .frm filesof InnoDB tables, or you have moved .frm files to another database?or, the table contains indexes that this version of the enginedoesnt support.稍微解釋一下 InnoDB 的數(shù)據(jù)字典,它存在于系統(tǒng)表空間中——它本身作為存儲(chǔ)在 ibdata1 文件中的一組特殊頁面存在(系統(tǒng)表空間將始終被引用為空間 0)——并存儲(chǔ)任何表的元數(shù)據(jù)InnoDB 顯式處理的、列或索引。這不是結(jié)構(gòu)元素的主要位置——它們位于每個(gè) InnoDB 表的.frm文件中——但是,它確實(shí)包含許多相同的信息。這是您通常會(huì)看到導(dǎo)致這些錯(cuò)誤的差異的地方。如果出于任何原因更改、移動(dòng)、手動(dòng)更改或替換了 ibdata1 文件 - 您會(huì)突然得到一個(gè)數(shù)據(jù)字典,它不能反映文件或數(shù)據(jù)庫結(jié)構(gòu)中存在的內(nèi)容。如果您已經(jīng)閱讀了前面的錯(cuò)誤描述,此時(shí)您應(yīng)該明白,存在于 ibdata1(或以其他方式命名)文件中的數(shù)據(jù)與存在于各個(gè)表空間/.ibd/.frm 中的數(shù)據(jù)之間存在明顯的關(guān)聯(lián)文件。當(dāng)這種關(guān)聯(lián)丟失或切斷時(shí),可能會(huì)發(fā)生不好的事情。因此,您會(huì)看到出現(xiàn)此類數(shù)據(jù)字典錯(cuò)誤的最常見原因是因?yàn)槟承﹥?nèi)容被移動(dòng)或手動(dòng)更改。它通常歸結(jié)為:數(shù)據(jù)字典希望此文件或表空間在此處,但它不是!,或.ibd/.frm 文件希望此項(xiàng)目在數(shù)據(jù)字典中,但它不是! 。再次記住,數(shù)據(jù)字典存儲(chǔ)在 ibdata 文件中,在大多數(shù)環(huán)境中,它只是存儲(chǔ)在 MySQL 數(shù)據(jù)目錄中的 ibdata1。B/2 檢查表的錯(cuò)誤
日志通常是問題發(fā)生時(shí)的直接指示,但有時(shí)它們可能有點(diǎn)模糊。通常,您會(huì)看到損壞的跡象,但不知道哪些表、頁面或數(shù)據(jù)庫受到影響。檢查表的兩種與 InnoDB 相關(guān)的方法是CHECK TABLESQL 語句和innochecksum實(shí)用程序。您在此處使用的方法將取決于一個(gè)因素:您的 MySQL 服務(wù)器是在線還是離線。
MySQL 正在運(yùn)行且可訪問?使用檢查表。innochecksum 不檢查服務(wù)器當(dāng)前打開的表空間。MySQL 已崩潰或以其他方式脫機(jī)?innochecksum是這里的方法 - 它查看表空間文件中的頁面,計(jì)算每個(gè)頁面的校驗(yàn)和,并將其與存儲(chǔ)的校驗(yàn)和值進(jìn)行比較。如果這些不匹配,MySQL 將崩潰,并且損壞或數(shù)據(jù)修改以某種方式顯而易見,因此這可能是確認(rèn)表空間中的合法問題的可靠方法。B/2.1 使用 CHECK TABLE / mysqlcheck
CHECK TABLE 命令,也被mysqlcheck實(shí)用程序使用(特別是 -c 標(biāo)志,但是 mysqlcheck 默認(rèn)為這種行為),通過許多不同的確認(rèn)和比較檢查來嘗試和識(shí)別腐敗的跡象。CHECK TABLE 和 mysqlcheck 都適用于 MyISAM和InnoDB 表,但是——在本文的上下文中——我將重點(diǎn)關(guān)注它對(duì) InnoDB 表的作用。
請(qǐng)注意,mysqlcheck -r 的 REPAIR 功能和REPAIR TABLE MySQL 命令在 InnoDB 表上不起作用;mysqlcheck 主要僅在這種情況下用于識(shí)別問題 - 而不是解決問題。
以下是它在內(nèi)部專門尋找的內(nèi)容的細(xì)分:
存在相應(yīng)的 .ibd 表空間文件。主索引一致性正確的順序(按鍵升序)唯一約束完好無損索引條目數(shù)對(duì)表中的所有其他索引重復(fù)步驟 1-5。最后,所有表都經(jīng)過自適應(yīng)哈希索引檢查。如果其中任何一個(gè)返回不正確或不一致的值,則該表可能被標(biāo)記為已損壞。一旦表被標(biāo)記為損壞,在問題得到解決或后續(xù)表檢查能夠確認(rèn)問題不再存在之前,不能再使用該表。
在某些情況下,如果 CHECK TABLE 例程在 MySQL 自己遇到問題之前發(fā)現(xiàn)了 InnoDB 表的問題,這實(shí)際上可能會(huì)導(dǎo)致 MySQL 服務(wù)器被關(guān)閉以避免導(dǎo)致額外的錯(cuò)誤。雖然這可能是一件好事,因?yàn)樗梢詭椭柚谷魏芜M(jìn)一步的損害發(fā)生,但當(dāng)您決定在 InnoDB 表上運(yùn)行 CHECK TABLE 或 mysqlcheck 時(shí),意識(shí)到這一點(diǎn)總是好的。
這不是發(fā)現(xiàn)的問題是簡(jiǎn)單的損壞或錯(cuò)誤的情況。發(fā)現(xiàn)的損壞/錯(cuò)誤只會(huì)導(dǎo)致相應(yīng)地標(biāo)記索引/表。
運(yùn)行 CHECK TABLE
CHECK TABLE 作為命令必須在 MySQL shell 中運(yùn)行,或者通過 MySQL 在其他地方執(zhí)行。例如,這是我通過將現(xiàn)有的 dictionary.ibd 文件替換為來自同一數(shù)據(jù)庫的另一個(gè)表的 .idb 文件而創(chuàng)建的一種情況,您可以在其中看到在普通表上執(zhí)行的 CHECK TABLE 與已損壞或已損壞的表之間的比較遇到錯(cuò)誤:
代碼:
mysql> CHECK TABLE roundcube.users; +-----------------+-------+----------+----------+| Table |Op| Msg_type |Msg_text| +-----------------+-------+----------+----------+ |roundcube.users| check |status| OK |+-----------------+-------+----------+----------+1rowinset (0.13sec) mysql> CHECK TABLE roundcube.dictionary; +----------------------+-------+----------+----------------------------------------------------------------+| Table |Op| Msg_type |Msg_text| +----------------------+-------+----------+----------------------------------------------------------------+ |roundcube.dictionary| check |Warning| InnoDB: Tablespace is missingfortable roundcube/dictionary || roundcube.dictionary |check| Error |Tableroundcube.dictionarydoesnt exist | | roundcube.dictionary | check | status | Operation failed | +----------------------+-------+----------+----------------------------------------------------------------+ 3 rows in set (0.00 sec)在這種情況下,遇到的錯(cuò)誤實(shí)際上保證了服務(wù)器會(huì)自動(dòng)關(guān)閉。我第一次在 roundcube.dictionary 上運(yùn)行 CHECK TABLE 的那一刻,服務(wù)器崩潰了。這是因?yàn)槲覍⒒顒?dòng)的 MySQL 實(shí)例引入了問題的存在。
InnoDB 的數(shù)據(jù)一致性合規(guī)性堅(jiān)持認(rèn)為,一旦發(fā)現(xiàn)此類問題,就立即停止。根據(jù)確切觸發(fā)崩潰的原因,需要不同級(jí)別的 innodb_force_recovery 才能恢復(fù) MySQL 服務(wù)器。在缺少表空間的情況下,最小值 - 1 - 可以正常工作。
請(qǐng)記住,MySQL 服務(wù)器因某種原因而被強(qiáng)制崩潰. 不要通過快速啟用 innodb_force_recovery 直接跳回 MySQL!這有可能,有時(shí)甚至是確定性,會(huì)導(dǎo)致比它解決的問題更多的問題。
運(yùn)行 mysqlcheck
通常,您需要一次檢查多個(gè)表或數(shù)據(jù)庫。CHECK TABLE 不支持通配符,因此在檢查數(shù)據(jù)庫中的所有表或檢查服務(wù)器上的所有數(shù)據(jù)庫時(shí)使用起來很不方便。mysqlcheck - 默認(rèn)情況下從命令行執(zhí)行 CHECK TABLE - 通過允許您輕松檢查整個(gè)數(shù)據(jù)庫或所有數(shù)據(jù)庫來彌補(bǔ)這一點(diǎn)。在數(shù)據(jù)庫上執(zhí)行 CHECK TABLE 的默認(rèn)語法是(將 db_name 替換為您的數(shù)據(jù)庫名稱):
代碼:
mysqlcheckdb_name然后它將輸出對(duì)該數(shù)據(jù)庫中每個(gè)表執(zhí)行 CHECK TABLE 的結(jié)果。如果您只想在數(shù)據(jù)庫中的幾個(gè)選擇表上執(zhí)行它,您還可以在數(shù)據(jù)庫名稱之后指定表 (mysqlcheck db_name tbl1_name tbl2_name...)。
這是我在前一個(gè)場(chǎng)景中使用的圓形立方體數(shù)據(jù)庫上執(zhí)行的示例:
代碼:
-bash-4.1mysqlcheck roundcuberoundcube.cache OK roundcube.cache_index OK roundcube.cache_messages OK roundcube.cache_thread OK roundcube.contactgroupmembers OK roundcube.contactgroups OK roundcube.contacts OK roundcube.cp_schema_version OK roundcube.dictionaryWarning:InnoDB:Tablespaceismissingfortableroundcube/dictionaryError:Tableroundcube.dictionarydoesnt exist status : Operation failed roundcube.identities Warning : InnoDB: Tablespace is missing for tableroundcube/identitiesError : Tableroundcube.identitiesdoesnt existstatus: Operationfailedroundcube.searches OK roundcube.session OK roundcube.system OK roundcube.users OK此外,您可以使用 -A 標(biāo)志(或 --all-databases)對(duì)服務(wù)器上所有數(shù)據(jù)庫中的所有表執(zhí)行 CHECK TABLE。
B/2.2 使用innochecksum
如前所述,InnoDB 需要有一致的數(shù)據(jù),當(dāng)它自己遇到校驗(yàn)和不匹配時(shí),它會(huì)立即停止一個(gè)活動(dòng)的服務(wù)器。考慮到這一點(diǎn),innochecksum 不僅可以幫助在事后識(shí)別損壞,而且可以幫助您總體上關(guān)注您的校驗(yàn)和狀態(tài)。在預(yù)防的上下文中,這里涉及的唯一缺點(diǎn)是它不能在任何打開的表空間文件上運(yùn)行。因此,為了獲得有關(guān)表校驗(yàn)和狀態(tài)的任何體面圖片,需要使服務(wù)器脫機(jī)。
但是,因?yàn)槲覀冋谔幚淼氖潜罎⒌?MySQL 服務(wù)器上的損壞,所以這可能是您最不擔(dān)心的問題。innochecksum 在這些情況下非常適合跟蹤不匹配的校驗(yàn)和,特別是因?yàn)樗恍枰?wù)器在線。
您從 innochecksum 獲得的輸出將根據(jù)發(fā)生的情況而有所不同,并且通常 - 除非您使用 -v 指定詳細(xì)輸出 - 除非實(shí)際發(fā)現(xiàn)問題,否則您將看不到任何輸出。這是在數(shù)據(jù)文件中發(fā)現(xiàn)的校驗(yàn)和失敗的示例:
代碼:
page 8 invalid (fails old stylechecksum) page8:oldstyle: calculated =0x8195646B; recorded = 0x DA79A2EEinnochecksum 實(shí)用程序目前僅對(duì)特別引用的表空間文件 (.ibd) 進(jìn)行操作,但您可以輕松地使用如下的 find 命令對(duì)所有 .ibd 文件執(zhí)行 innochecksum(適當(dāng)調(diào)整 DATADIR):
代碼:
DATADIR=/var/lib/mysql; find $DATADIR -type f -name *.ibd -o -name ibdata* | xargs -I{} innochecksum {}/C/ 恢復(fù)您的數(shù)據(jù)
一旦您確定了問題并適當(dāng)?shù)販?zhǔn)備了您的服務(wù)器,您的下一步就是讓您的數(shù)據(jù)恢復(fù)正常工作。MySQL此時(shí)應(yīng)該在線并且至少部分響應(yīng),無論是使用innodb_force_recovery還是其他方式。
C/1 MySQL 實(shí)用程序 / 從 .frm 文件中提取 CREATE TABLE 語句
MySQL 提供了一組可下載的實(shí)用程序,其中包括一些可能有助于恢復(fù)過程的工具——特別是,包括一個(gè)名為mysqlfrm的實(shí)用程序。此實(shí)用程序可以相當(dāng)容易地從 .frm 文件中提取表的 CREATE TABLE 語句。這種說法可以極很有用,因?yàn)閹缀跛杏杏玫幕謴?fù)方法都涉及能夠重新創(chuàng)建您嘗試修復(fù)的原始表的結(jié)構(gòu),而且通常,這必須在沒有任何直接 MySQL 訪問原始表本身的情況下完成。
C/1.1 下載和安裝 MySQL 實(shí)用程序:
在此處下載軟件包。將其提取到您的服務(wù)器中的某處代碼:tar xvzf mysql-utilities*切換到解壓后的目錄,賦予 setup.py 執(zhí)行權(quán)限,并運(yùn)行它的構(gòu)建和安裝操作代碼:cd mysql-utilities-1.4.3chmod +x setup.py./setup.py build./setup.py installC/1.2 從 .frm 文件中提取 CREATE TABLE 語句:
mysqlfrm將根據(jù)您現(xiàn)有的安裝創(chuàng)建自己的臨時(shí) MySQL 守護(hù)程序,這意味著如果您現(xiàn)有的 MySQL 安裝已經(jīng)在運(yùn)行,您需要指定一個(gè)備用端口。這是我運(yùn)行以從staff.frm文件中提取 CREATE TABLE 的示例:
代碼:
mysqlfrm --basedir=/usr --user=mysql --port=3308 /var/lib/mysql/testdb/staff.frm這是隨后的輸出:
代碼:
Spawning server with --user=mysql.Starting the spawned server on port 3308 ... done.Reading .frm filesReading the staff.frm file.CREATE statement for staff.frm:CREATETABLE`staff`(`staff_id`tinyint(3)unsignedNOTNULLAUTO_INCREMENT,`first_name`varchar(45)NOTNULL,`last_name`varchar(45)NOTNULL,`address_id`smallint(5)unsignedNOTNULL,`picture`blob,`email`varchar(50)DEFAULTNULL,`store_id`tinyint(3)unsignedNOTNULL,`active`tinyint(1)NOTNULLDEFAULT1,`username`varchar(16)NOTNULL,`password`varchar(40)CHARACTERSETutf8COLLATEutf8_binDEFAULTNULL,`last_update`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP, PRIMARYKEY(`staff_id`),KEY`idx_fk_store_id`(`store_id`),KEY`idx_fk_address_id`(`address_id`) )ENGINE=InnoDBDEFAULTCHARSET=utf8...done.從CREATE TABLE部分到CHARSET=utf8的上述輸出中的所有內(nèi)容都是完整的、可執(zhí)行的 CREATE TABLE 語句,它是重新創(chuàng)建具有正確結(jié)構(gòu)的staff表所需的。要在 MySQL shell 中執(zhí)行此操作,我只需粘貼該完整語句,并用分號(hào) ( 結(jié)尾
。在某些情況下,您還很可能需要禁用外鍵檢查才能成功:
代碼:
SETFOREIGN_KEY_CHECKS=0;C/2 損壞的表
如果您確定服務(wù)器中當(dāng)前存在損壞的表,您可以在此處采取一些方法,具體取決于嚴(yán)重程度。在幾乎所有表損壞的情況下,您至少需要在 innodb_force_recovery 設(shè)置為 1 的情況下運(yùn)行 InnoDB,以允許 MySQL 在您使用它時(shí)保持在線。
C/2.1 使用 CREATE .. LIKE 恢復(fù)表
此方法的目標(biāo)是嘗試并使用表的現(xiàn)有結(jié)構(gòu)和數(shù)據(jù),假設(shè)它們是可訪問的,以簡(jiǎn)單地創(chuàng)建具有相同結(jié)構(gòu)和數(shù)據(jù)的新表,以達(dá)到目的更換原件。基本步驟如下:
只需運(yùn)行以下命令即可訪問 MySQL shell:代碼:mysql這引用了 /root/.my.cnf 文件以獲取憑據(jù)。如果它們是準(zhǔn)確的,您將不需要從根 shell 提供憑據(jù)。否則,您需要手動(dòng)提供:代碼:mysql -u root -p成功后,您應(yīng)該會(huì)看到這樣的提示:代碼:mysql>運(yùn)行以下 MySQL 語句,分別將 tablename 和 dbname 替換為您的表和數(shù)據(jù)庫的名稱:代碼:USE dbname;CREATE TABLE tablename_recovered LIKE tablename;INSERT INTO tablename_recovered SELECT * FROM tablename;如果您在這里沒有遇到任何問題,那么您可能很幸運(yùn)。此時(shí),您可以刪除原始表,并將_recovered表名稱更改回原始表:代碼:DROP dbname.tablename;RENAME TABLE dbname.tablename_recovered TO dbname.tablename;當(dāng)涉及頁面損壞時(shí),此方法是最簡(jiǎn)單的,但可能成功率最低,因?yàn)樗蕾囉谀軌驈墓δ苌线x擇所有數(shù)據(jù)并根據(jù)其結(jié)構(gòu)創(chuàng)建恢復(fù)表。如果其中任何一個(gè)無法訪問或以其他方式無法讀取,則此方法可能會(huì)失敗。
但是,如果它在其中涉及增量插入的SELECT *部分失敗,您確實(shí)有另一個(gè)選擇。因此,您不必執(zhí)行上面顯示的INSERT INTO ... SELECT * ...,而是執(zhí)行以下操作:
代碼:
insertignoreintotablename_recoveredselect*fromtablenamelimit10;insertignoreintotablename_recoveredselect*fromtablenamelimit50;insertignoreintotablename_recoveredselect*fromtablenamelimit100;insertignoreintotablename_recoveredselect*fromtablenamelimit200; ...使用這種方法,您可以拼湊可訪問的數(shù)據(jù),直到您到達(dá)故障點(diǎn),此時(shí)您可能會(huì)失去與 MySQL 服務(wù)器的連接。
C/2.2 恢復(fù)多個(gè)/所有 InnoDB 數(shù)據(jù)庫并重新創(chuàng)建 ibdata/ib_log 文件
此方法的成功將再次取決于 mysqldump 從每個(gè)有問題的表中生成功能數(shù)據(jù)集的能力,但通常更全面的方法,因?yàn)樗婕俺跏蓟碌?ibdata 和 ib_log 文件。然而,正因?yàn)槿绱耍绻徊扇≈?jǐn)慎措施,這種方法也很有可能以失敗告終。確保您已經(jīng)完成了 First Response 中的步驟,并且在繼續(xù)執(zhí)行此操作之前,您有一組單獨(dú)的備份。
如果您已經(jīng)有要在現(xiàn)有損壞的數(shù)據(jù)庫上恢復(fù)的備份轉(zhuǎn)儲(chǔ),您也可以使用此方法 - 只需從第 2 步開始。
執(zhí)行所有數(shù)據(jù)庫的 mysqldump。代碼:mysqldump -AER > /root/recovery_dump.sql如果您在此處遇到任何錯(cuò)誤,請(qǐng)停下來仔細(xì)查看錯(cuò)誤。如果它們表明您的任何重要數(shù)據(jù)已損壞到無法正確轉(zhuǎn)儲(chǔ)的程度,您可能不想繼續(xù)使用此方法。此外,請(qǐng)務(wù)必查看生成的轉(zhuǎn)儲(chǔ)文件,以確保它實(shí)際上包含預(yù)期的數(shù)據(jù)。刪除所有受影響的 InnoDB 數(shù)據(jù)庫。代碼:mysql> SET FOREIGN_KEY_CHECKS=0;mysql> DROP DATABASE db1;mysql> DROP DATABASE db2;...在禁用 innodb_fast_shutdown 后停止 mysqld,以確保執(zhí)行干凈、完全的關(guān)閉。代碼:mysql -e "SET GLOBAL innodb_fast_shutdown = 0"/etc/init.d/mysql stop重定位 InnoDB 數(shù)據(jù)和重做日志文件代碼:mv /var/lib/mysql/ibdata* /tmp/mv /var/lib/mysql/ib_log* /tmp/注釋掉或刪除您當(dāng)前在 /etc/my.cnf 中的任何 innodb_force_recovery 條目。代碼:sed -i /innodb_force_recovery/d /etc/my.cnf啟動(dòng) mysqld 并監(jiān)控日志以確保它上線并適當(dāng)?shù)爻跏蓟瘮?shù)據(jù)和重做日志文件代碼:nohup /etc/init.d/mysql start & tail -f /var/lib/mysql/`hostname`.err恢復(fù)轉(zhuǎn)儲(chǔ),一旦您確信 MySQL 仍然功能在線并準(zhǔn)備好導(dǎo)入數(shù)據(jù)。代碼:mysql < /root/recovery_dump.sqlC/3 日志序列號(hào)不匹配/將來
作為一種嘗試確保您的數(shù)據(jù)保持一致并允許相當(dāng)于撤消/重做功能的方式,InnoDB 在日志中維護(hù)所謂的日志序列號(hào)文件和表空間文件。每次對(duì) InnoDB 表中的任何數(shù)據(jù)進(jìn)行更改時(shí),該更改都會(huì)導(dǎo)致日志序列號(hào)更新。這相當(dāng)于一個(gè)偏移量,它指示 InnoDB 在文件中向前或向后看多遠(yuǎn),以便引用特定的數(shù)據(jù)狀態(tài)。
如果在任何時(shí)間點(diǎn)發(fā)生的事情導(dǎo)致一個(gè)更新,而不是另一個(gè),你最終會(huì)在你的 MySQL 日志中看到關(guān)于不匹配的日志序列號(hào)的錯(cuò)誤,或者日志序列號(hào)在未來。重要的是讓這些回到正軌,以便您的數(shù)據(jù)庫服務(wù)器再次正常運(yùn)行
。C/3.1 刪除和重新創(chuàng)建數(shù)據(jù)
這是最有效也是唯一真實(shí)的解決方案,但不幸的是,對(duì)于許多人來說,它是最不適用的,因?yàn)樵诂F(xiàn)實(shí)世界的情況下,并不是每個(gè)人都能輕松獲得這些數(shù)據(jù)(盡管如果你現(xiàn)在正在經(jīng)歷這種體驗(yàn),它可能是考慮建立有效備份解決方案的好時(shí)機(jī))。但是,如果您的 MySQL 實(shí)例沒有崩潰,并且您能夠創(chuàng)建一個(gè) mysqldump,那么嘗試重新導(dǎo)入它當(dāng)然值得一試。您可以按照恢復(fù)多個(gè)/所有 InnoDB中詳細(xì)說明的步驟進(jìn)行操作Databases and Re-create ibdata/ib_log files" 方法在上述 Corrupted Tables 部分下嘗試恢復(fù)現(xiàn)有數(shù)據(jù)庫的轉(zhuǎn)儲(chǔ)
同樣,在此處進(jìn)行任何更改之前,請(qǐng)確保您已經(jīng)復(fù)制了所有重要的 ibdata、ib_logfile、.ibd 和 .frm 文件。
C/3.2 重新創(chuàng)建 ib_logfiles
如果您只處理單個(gè) MySQL 實(shí)例,而不是 master->slave 或其他集群情況,這可能是一種有效的嘗試方法。這里的目標(biāo)是將現(xiàn)有的 ib_logfiles 排除在外,允許 MySQL 在重新啟動(dòng)時(shí)重新初始化它們。老實(shí)說,我用這種方法取得的成功相當(dāng)有限,但它已經(jīng)工作了足夠多的時(shí)間,值得一提:
代碼:
mysql -e"SET GLOBAL innodb_fast_shutdown = 0"/etc/init.d/mysql stop cd /var/lib/mysql mv ib_logfile0 ib_logfile0.bak mv ib_logfile1 ib_logfile1.bak /etc/init.d/mysql start第一個(gè)命令確保 InnoDB 執(zhí)行徹底關(guān)閉,這有時(shí)可以幫助解決這種情況,值得在這里包括。
C/3.3 執(zhí)行引擎交換
這是另一種相當(dāng)激烈的方法,盡管它很嚴(yán)厲,但在我個(gè)人的經(jīng)驗(yàn)中似乎有相當(dāng)可靠的成功率,盡管它肯定取決于你正在使用什么樣的環(huán)境. 此方法還要求 MySQL 能夠成功啟動(dòng)。
要將數(shù)據(jù)庫中的所有表從 InnoDB 轉(zhuǎn)換為 MyISAM,請(qǐng)運(yùn)行 MySQL 以下命令,將 db_name 替換為相關(guān)數(shù)據(jù)庫名稱:代碼:mysql -e "SELECT concat(ALTER TABLE , TABLE_NAME, ENGINE=MYISAM;) FROM Information_schema.TABLES WHERE TABLE_SCHEMA = db_name AND ENGINE = InnoDB AND TABLE_TYPE = BASE TABLE"然后,在停止 MySQL 之后,您希望將 ibdata* 和 ib_logfiles 排除在外:代碼:/etc/init.d/mysql stopmkdir -p /root/innodb.bakmv ib* /root/innodb.bak//etc/init.d/mysql start現(xiàn)在您已經(jīng)使用 MyISAM 啟動(dòng)了 MySQL 表,是時(shí)候?qū)⑺鼈冝D(zhuǎn)換回 InnoDB,手指交叉(再次將 db_name 替換為您的數(shù)據(jù)庫名稱):代碼:mysql -e "SELECT concat(ALTER TABLE , TABLE_NAME, ENGINE=InnoDB;) FROM Information_schema.TABLES WHERE TABLE_SCHEMA = db_name AND ENGINE = MyISAM"C/4 數(shù)據(jù)字典問題
雖然這些錯(cuò)誤各不相同,但最常見的數(shù)據(jù)字典問題與表空間或表文件不處于 InnoDB 期望它們所處的狀態(tài)有關(guān),通常是由于不正確刪除 InnoDB .ibd 或 . frm 文件,或由于刪除/移動(dòng) ibdata 文件。考慮到這一點(diǎn),現(xiàn)在是注意以下事項(xiàng)的好時(shí)機(jī):
C/4.1 如何正確刪除 .ibd 文件
數(shù)據(jù)庫各自子目錄中的 .ibd 文件表示這些數(shù)據(jù)庫中表的表空間。刪除文件本身會(huì)導(dǎo)致 InnoDB 為維護(hù)數(shù)據(jù)一致性而保留的記錄出現(xiàn)許多問題。如果你只需要出于任何原因刪除表空間(例如嘗試導(dǎo)入新的表空間/ibd 文件),正確的方法是使用 ALTER TABLE ... DISCARD TABLESPACE 語句,例如:
代碼:
mysql -e "ALTERTABLEroundcube.staff DISCARDTABLESPACE"在上面的例子中,roundcube 是數(shù)據(jù)庫,staff 是表。如果您在執(zhí)行此操作后檢查數(shù)據(jù)庫目錄,您會(huì)注意到雖然該表的 .frm 文件仍然存在,但 .ibd 文件不存在。但請(qǐng)記住,*表*條目本身仍然存在于服務(wù)器上**。
注意:通常,您必須在執(zhí)行此操作之前禁用 foreign_key_checks,這可以通過以下方式完成:
代碼:
SETFOREIGN_KEY_CHECKS=0;C/4.2 .ibd 文件丟失后重新創(chuàng)建表
如果您刪除或更改了表空間 (.ibd) 文件,您很可能會(huì)遇到如下所示的錯(cuò)誤:
代碼:
[ERROR] MySQL is trying toopenatablehandle but the .ibd filefortabledbname/tblname doesnotexist.在這種情況下,它仍然認(rèn)為該表以某種方式存在,這意味著在解決該問題之前您將無法正確地重新創(chuàng)建該表。幸運(yùn)的是,盡管執(zhí)行失敗,InnoDB 足夠聰明,可以意識(shí)到發(fā)生了什么,并且如果您運(yùn)行以下命令(在適當(dāng)?shù)牡胤教鎿Q dbname 和 tblname),它會(huì)執(zhí)行幾個(gè)方便的過程:
第一步是嘗試擺脫表空間的剩余部分:代碼:ALTER TABLE dbname.tblname DISCARD TABLESPACE;它可能會(huì)或可能不會(huì)在 MySQL shell 上出錯(cuò),但如果您查看錯(cuò)誤日志,它仍然會(huì)繼續(xù)并清理緩沖區(qū):代碼:InnoDB: Warning: cannot delete tablespace 251 in DISCARD TABLESPACE.InnoDB: But let us remove the insert buffer entries for this tablespace.然后,嘗試刪除實(shí)際的表記錄(如果您需要保存 .frm 文件以再次獲取 create table 語句,請(qǐng)確保在執(zhí)行此步驟之前已復(fù)制它):代碼:DROP TABLE dbname.tblname;您很可能會(huì)遇到類似的錯(cuò)誤,但以下內(nèi)容將再次出現(xiàn)在日志中:代碼:InnoDB: We removed now the InnoDB internal data dictionary entryInnoDB: of table `dbname/tblname`.之后,您可以使用備份或復(fù)制的 .frm 文件(使用上述 mysqlfrm 方法)重新創(chuàng)建表。C/4.3 .frm 文件存在但表不存在
這與上一期的思路相同,只是情況更簡(jiǎn)單,更容易解決,最終:
代碼:
InnoDB: Cannotfindtabletest/child2 from the internal data dictionary InnoDB: of InnoDB though the .frm fileforthetableexists.在這里,最常見的問題是部分執(zhí)行的 drop 或 alter 語句沒有導(dǎo)致所有表的文件都被正確刪除。在這些情況下,可以安全地刪除 .frm 文件,InnoDB 應(yīng)該相應(yīng)地進(jìn)行調(diào)整。但是,我的建議不是刪除它,而是將其復(fù)制到備份文件夾中,至少是暫時(shí)的,以便您確實(shí)擁有 CREATE TABLE 語句,如果您出于任何原因需要訪問它。
如果您不打算刪除此表,或者 .ibd 文件已通過其他方式刪除,那么 - 除了通過挖掘 ibdata 文件嘗試進(jìn)行一些深度數(shù)據(jù)恢復(fù)之外 - 您恢復(fù)此表的唯一選擇是從備份中恢復(fù),因?yàn)?InnoDB 本質(zhì)上是在錯(cuò)誤中指出這個(gè) .frm 文件絕對(duì)是有問題的表中唯一剩下的東西。如果是這種情況,絕對(duì)不要?jiǎng)h除 .frm 文件 - 只需重新定位它,這樣您就有機(jī)會(huì)重新創(chuàng)建表并重新構(gòu)建數(shù)據(jù)。
C/4.4 孤立表或缺少 .frm 文件
如果 .frm 文件因任何原因丟失,您可能會(huì)看到如下錯(cuò)誤:
代碼:
InnoDB:Error: table dbname/tblname already exists in InnoDB internalInnoDB: data dictionary. Have you deleted the .frm fileInnoDB: and not used DROP TABLE? ...在這種情況下,通常遵循此錯(cuò)誤的說明描述了處理此錯(cuò)誤的最有效方法:
代碼:
InnoDB: You candropthe orphanedtableinsideInnoDBbyInnoDB: creating anInnoDBtablewiththe samenameinanotherInnoDB:databaseandmoving the .frmfiletothecurrentdatabase.InnoDB:ThenMySQL thinks thetableexists,andDROPTABLEwillInnoDB: succeed.這意味著,如果您有孤立表的 CREATE TABLE 語句,無論是通過備份還是其他方式,您都可以簡(jiǎn)單地創(chuàng)建一個(gè)測(cè)試數(shù)據(jù)庫,并在測(cè)試數(shù)據(jù)庫中創(chuàng)建表的副本(僅結(jié)構(gòu))。這將創(chuàng)建一個(gè)可用的 .frm 文件,該文件可用于復(fù)制到原始數(shù)據(jù)庫,并替換為替換丟失的 .frm,最后允許您刪除表。這是一個(gè)簡(jiǎn)短的示例,假設(shè)原始數(shù)據(jù)庫和表名都只是測(cè)試:
代碼:
mysqlmysql>CREATE DATABASE test2;mysql>CREATE TABLE ... CHARSET=utf8;mysql>quitcp /var/lib/mysql/test2/test.frm /var/lib/mysql/test/mysqlmysql>SET FOREIGN_KEY_CHECKS=0;mysql>DROP TABLE test.test;結(jié)論
InnoDB 的數(shù)據(jù)一致性標(biāo)準(zhǔn)是一把雙刃劍。當(dāng)它被仔細(xì)管理并充分了解它的運(yùn)作方式時(shí),它是一個(gè)了不起的引擎,但不幸的是,當(dāng)它涉及到環(huán)境的變化時(shí),它并不是最寬容的。它有一些自己處理情況的好方法,以及一些出色的錯(cuò)誤日志記錄,但在確保環(huán)境穩(wěn)定時(shí),它絕對(duì)需要你注意。
我強(qiáng)烈建議,如果您有興趣閱讀 InnoDB 及其功能/特性,請(qǐng)查看以下一些閱讀材料:
MySQL :: MySQL 5.5 Reference Manual :: 14 The InnoDB Storage Engine On learning InnoDB :核心之旅——杰里米·科爾 您搜索了 Innodb - MySQL 性能博客
如果還是有問題,先不要驚慌,至少確保做了第一反應(yīng)中描述的備份,這樣如果最后真的需要數(shù)據(jù)恢復(fù)服務(wù),會(huì)有問題發(fā)生后不就的備份文件,以免因?yàn)閱栴}發(fā)生后,因?yàn)閷懭氪螖?shù)過多恢復(fù)不成功的情況。