對於內容驅動的網站,設計好壞的關鍵是關系型數據庫。在這個教程中,我們已經使用了MySQL關系型數據庫管理系統(RDBMS)建立了我們的數據庫。對於網站的開發者來說,MySQL是一個較受歡迎的選擇,這不僅是因為它對於任何平台上的非商業應用都是免費的,而且也因為它的架設和使用非常的簡單。正如我們在第一章中所看到的那樣,根據正確的指導,一個新的用戶可以在不超過30分鐘的時間內架設好一個MySQL服務,並將其運行起來(對於一個有經驗的用戶甚至只要10分鐘!)。
如果你想做的僅僅是架設一個MySQL服務環境,以用來做一些例子和練習,那麼我們在第一章安裝時所使用的初始化設置對你已經足夠了。但是,如果你是想建立一個真正的用於Web站點的數據庫--也許這個站點對於你的公司很重要--那麼你還需要學習一些有關MySQL的知識。
對於作為基於Internet的企業的一部分的商業事務來說,數據的備份是很重要的。不幸的是,因為備份的工作對於一個管理員來說往往是不太感興趣的,人們總是無法認清它的重要性,於是這方面的工作對於一個應用程序往往不能做得“足夠好”。如果直到現在你還不明白“我們是不是需要備份我們的數據庫”,或者是你認為“數據庫會和其它東西一起被備份”,那麼你得好好看看這一章的內容了。我們將會說明為什麼普通的文件備份方案對於許多MySQL服務是遠遠不夠的,然後我們會介紹備份和恢復一個MySQL數據庫的“正確的方法”。
在第一章中,我們設置了一個MySQL服務並通過一個有口令的‘root'來連接這個數據庫。MySQL的‘root'用戶(順便提一下,不要與Unix的‘root'用戶混淆)對於所有的庫和表都有讀/寫的權限。在許多情況下,我們需要建立其它的只能訪問某些數據庫和數據表的用戶,我們還需要對這種訪問進行限制(例如,對指定的表只能直接只讀訪問)。在這一章中,我們將學習如果使用兩個新的MySQL的命令:GRANT和REVOKE來完成這些工作。
在一些情況下,例如由於電源的問題,MySQL數據庫可能被損壞。這樣的損壞並不總是意味著必須使用備份來恢復。我們將會學習到如果利用MySQL數據庫的檢查和修復功能來解決簡單的數據庫損壞。
為什麼標准的備份是不夠的
和Web服務器一樣,絕大多數的MySQL服務器也必須不間斷地在線。這使得MySQL數據庫的備份顯得很重要。因為MySQL服務使用cache和緩沖區來提高對存儲在磁盤上的數據庫文件更新的效率,所以文件的內容和當前數據庫的內容可能並不完全一致。而標准的備份程序僅僅包括對系統和數據文件的拷貝,這種對MySQL數據文件的備份並不能完全滿足我們的需要,因為它們不能保證拷貝的文件可以在系統崩潰時的確能夠正常地使用。
此外,因為許多的數據庫必須整天地接受信息,標准的備份只能提供數據庫數據的“瞬間的”映象。如果MySQL數據庫文件被損壞,或是變得不可用,在最後一次備份之後添加的信息將會被丟失。在許多情況下,例如對於一個電子商務網站的處理用戶訂單的數據庫,這樣的丟失是不可容忍的。
MySQL中的工具可以對數據進行實時的備份,而在備份進行時,不會影響服務的效率。不幸的是,這需要你 為你的MySQL數據配置一個特殊的備份系統。而完全與你已制定的其它數據備份方案無關。然而,和任何一個好的備份系統一樣,在你真正用到它的時候,你會發現現在的麻煩是值得的。
在這一章中,我們提供的指導是用於一個運行Linux或其它基於Unix的操作系統的計算機上的。如果你使用的是Windows,方法也基本上一樣,只是其中的有些命令必須改動。
使用mysqldump進行數據庫備份
除了mysqld以外,MySQL服務器以及mysql(MySQL的客戶端),在安裝時還會產生很多有用的程序。例如,在前面,我們已經看到的mysqladmin,就是負責控制和搜集有關正在運行的MySQL服務的信息的程序。
mysqldump是另一個這樣的程序。當它運行時,它會連接到一個MySQL服務(就和mysql程序和PHP語言所做的一樣)並下載指定的數據庫的全部內容。然後它會輸出一系列的SQL的CREATE TABLE命令和INSERT命令,在一個空的MySQL數據庫中運行這些命令,就可以建立與當初的數據庫內容完全一樣的一個MySQL數據庫。
通過重定向mysqldump的輸出到一個文件,你可以存儲一個數據庫的“鏡像”以作為備份。下面的命令是用一個口令為mypass的root用戶連接到一個運行在myhost上的MySQL服務,並將名為dbname的數據庫的備份存儲到dbname_backup.sql文件中:
% mysqldump -h myhost -u root -pmypass dbname > dbname_backup.sql
要恢復這樣的一個數據庫,只需要運行下面的命令:
% mysqladmin -h myhost -u root -pmypass create dbname
% mysql -h myhost -u root -pmypass dbname < dbname_backup.sql
第一個命令使用mysqladmin程序建立一個數據庫。第二個命令連接到MySQL服務並使用通常的mysql程序,並將剛才得到的備份文件作為其中執行的命令。
通過這種方法,我們可以使用mysqldump建立我們數據庫的備份。因為mysqldump通過與MySQL服務的連接產生這個備份,這肯定要比直接訪問MySQL數據目錄下的數據庫文件來得更為安全,因為這樣的備份可以確保是數據庫的一個有效的拷貝,而不僅僅是數據庫文件的拷貝。
剩下來的問題就是如何解決這個“鏡像”與一個不斷更新的數據庫之間的同步。要做到這一點,你需要命令服務保持一個變更日志。
利用變更日志進行增量備份
正如我們前面提到的,在很多情況下,我們使用的MySQL數據庫會造成數據的丟失--甚至有的時候會丟失很重要的數據。在這樣的情況下,我們必須找到一種方法保持我們使用上面介紹的方法用mysqldump制作的備份與當前數據庫之間的同步。而解決方案就是讓MySQL服務維持一個更新日志。一個更新日志是一個關於所有數據庫接受到的可能改變數據庫內容的查詢的記錄。這將包括INSERT、UPDATE和CREATE TABLE語句,但是不包括SELECT語句。
通常的想法是維持一個變更日志,這樣當數據庫崩潰時,你的恢復過程應該是這樣的:首先使用備份(使用mysqldump命令產生),然後使用備份之後的變量日志。
你也可以使用變更日志撤消錯誤操作。例如,如果一個合作者告訴你他錯誤地使用了一個DROP TABLE命令,你可以對變更日志進行編輯以刪除這個命令,然後使用備份和修改過的變更日志進行恢復。通過這種方法,你甚至可以保持這次意外事故之後其它表的變化。作為預防措施,你也許還要收回你的合作者的 DROP權限(在下一部分你將看到該怎麼做)。
告訴MySQL服務器維持一個變更日志是非常簡單的,你只需要在服務的命令行中增加一個選項:
% safe-mysqld --log-update=update
上面的命令啟動MySQL服務,並告訴它在服務器的數據目錄下(如果你依照第一章中指導配置你的服務器的話,這個目錄將是/usr/local/mysql/var)建立名為update.001、update.002……的文件。一個新的這樣的文件將在服務器每一次刷新它的日志文件時被建立(通常,這是指服務每一次重啟動時)。如果你想將你的變更日志存儲到另一個地方(通常這是一個好主意--如果包含你的數據目錄的磁盤出了問題,你肯定不能指望它還能好好保存你的備份!),你可以指定變更日志的路徑。
但是,如果你的MySQL服務器是不間斷地工作的,在啟動MySQL服務時你也許還需要一些系統配置。在這種情況下,增加一個命令行選擇可能變得很困難。建立變更日志的另一個簡單的方法是在MySQL配置文件中增加相應的選項。
如果你還不清楚"什麼是MySQL配置文件",不要擔心。事實上,在此之前,我們一直沒用到過這樣的配置文件。要建立這個文件,以我們在第一章中建立的MySQL用戶(如果你是完全根據指導做的,這應該是mysqlusr)登錄到Linux。使用你習慣的文本編輯器,在你的MySQL數據目錄下(除非你選擇了其它地方安裝MySQL,這應該是指/usr/local/mysql/var)建立一個名為my.cnf的文件。在這個文件中,輸入下面一行:
[mysqld]log-update=/usr/backups/mysql/update
當然,你可以自由地指定你的日志文件所寫入的位置。保存這個文件並重啟你的MySQL服務。從現在開始,MySQL服務運行的情況將和你在命令行中使用了--log-update選項一樣。
很明顯,對於一個服務來說,變更日志可能占用大量的空間。因為這個原因以及MySQL不能自動地在建立新的日志文件刪除舊的日志文件,你需要自己管理你的變更日志文件。例如,下面的Unix shell腳本,會刪除所有一星期以前更改的變更日志文件,然後通知MySQL刷新它的日志文件。
#! /bin/sh
find /usr/backups/mysql/ -name "update.[0-9]*"
-type f -mtime +6 | xargs rm -f
/usr/local/mysql/bin/mysqladmin -u root
-ppassword flush-logs
如果當前的日志文件被刪除,最後一步(刷新日志文件)將建立一個新的變更日志,這意味著MySQL服務一直在線,而且在過去的一周中,沒有收到任何改變數據庫內容的查詢。
如果你是一個有經驗的用戶,使用“時鐘守護程序”設置一個腳本來定期(比方說,每周一次)執行數據庫的備份並刪除舊的變更日志應該是相當簡單的。如果你還需要一點幫助,請教你當地的Unix權威。'MySQL' by Paul DuBois中的MySQL管理一章中對設置這樣的一個系統也有詳細的指南。
假定你已經有了一個備份以及在此之後的變更日志的一個拷貝,恢復你的數據庫將是非常簡單的。在建立一個空數據庫後應用我們在上一節中討論的方法導入備份,然後使用帶--one-database命令行選項的mysql命令導入變更日志。這會指示服務器僅僅運行變更日志中與我們想要恢復的數據庫(在這個例子中是指dbname)相關的查詢:
% mysql -u root -ppassword --one-database dbname < update.100
% mysql -u root -ppassword --one-database dbname < update.102
...
MySQL訪問控制
在這個教程的早些時候,我們曾經提到一個叫做mysql的數據庫,在每一個MySQL服務中都包含這個數據庫,它是用來保存用戶的相關信息、他們的口令以及他們的權限的。但是,在此之前,我們一直使用root用戶登錄到MySQL服務,這個用戶可以訪問所有的數據庫和數據表。
如果你的MySQL服務僅僅被通過PHP訪問,而用你對於將root用戶的口令告訴什麼人很小心,那麼root帳號可能已經足夠了。但是,如果一個MySQL服務是被許多人共享的,(例如,一個Web主機希望對它的每一個用戶提供同一個MySQL服務),為不同的用戶設置相應的訪問權限就顯得很重要了。
在MySQL參考手冊的第六章中詳細介紹了MySQL的訪問控制系統。從原理上來說,用戶的訪問是由mysql數據庫中的五個數據表來管理的:user、db、host、tables_priv和columns_priv。如果你想直接使用INSERT、UPDATE和DELETE語句來編輯這些表,我建議你先閱讀一下MySQL指南中的相關章節。而從3.22.11版本開始,MySQL提供了簡單的方法來管理用戶的訪問。使用MySQL提供的非標准的命令GRANT和REVOKE,你可以建立用戶並賦予其相應的權限,而不必關心它在前面提到的五個表中的存儲形式。
使用GRANT
GRANT命令用來建立新用戶,指定用戶口令並增加用戶權限。其格式如下:
mysql> GRANT <privileges> ON <what>
-> TO <user> [IDENTIFIED BY "<password>"]
-> [WITH GRANT OPTION];
正如你看到的,在這個命令中有許多待填的內容。讓我們逐一地對它們進行介紹,並最終給出一些例子以讓你對它們的協同工作有一個了解。
<privileges>是一個用逗號分隔的你想要賦予的權限的列表。你可以指定的權限可以分為三種類型:
數據庫/數據表/數據列權限:
ALTER: 修改已存在的數據表(例如增加/刪除列)和索引。
CREATE: 建立新的數據庫或數據表。
DELETE: 刪除表的記錄。
DROP: 刪除數據表或數據庫。
INDEX: 建立或刪除索引。
INSERT: 增加表的記錄。
SELECT: 顯示/搜索表的記錄。
UPDATE: 修改表中已存在的記錄。
全局管理權限:
FILE: 在MySQL服務器上讀寫文件。
PROCESS: 顯示或殺死屬於其它用戶的服務線程。
RELOAD: 重載訪問控制表,刷新日志等。
SHUTDOWN: 關閉MySQL服務。
特別的權限:
ALL: 允許做任何事(和root一樣)。
USAGE: 只允許登錄--其它什麼也不允許做。
這些權限所涉及到的MySQL的特征,其中的一些我們至今還沒看到,而其中的絕大部分是你所熟悉的。
<what> 定義了這些權限所作用的區域。*.*意味著權限對所有數據庫和數據表有效。dbName.*意味著對名為dbName的數據庫中的所有數據表有效。dbName.tblName意味著僅對名為dbName中的名為tblName的數據表有效。你甚至還可以通過在賦予的權限後面使用圓括號中的數據列的列表以指定權限僅對這些列有效(在後面我們將看到這樣的例子)。
<user>指定可以應用這些權限的用戶。在MySQL中,一個用戶通過它登錄的用戶名和用戶使用的計算機的主機名/IP地址來指定。這兩個值都可以使用%通配符(例如kevin@%將允許使用用戶名kevin從任何機器上登錄以享有你指定的權限)。
<password>指定了用戶連接MySQL服務所用的口令。它被用方括號括起,說明IDENTIFIED BY "<password>"在GRANT命令中是可選項。這裡指定的口令會取代用戶原來的密碼。如果沒有為一個新用戶指定口令,當他進行連接時就不需要口令。
這個命令中可選的WITH GRANT OPTION部分指定了用戶可以使用GRANT/REVOKE命令將他擁有的權限賦予其他用戶。請小心使用這項功能--雖然這個問題可能不是那麼明顯!例如,兩個都擁有這個功能的用戶可能會相互共享他們的權限,這也許不是你當初想看到的。
讓我們來看兩個例子。建立一個名為dbmanager的用戶,他可以使用口令managedb從server.host.net連接MySQL,並僅僅可以訪問名為db的數據庫的全部內容(並可以將此權限賦予其他用戶),這可以使用下面的GRANT命令:
mysql> GRANT ALL ON db.*
-> TO
[email protected] -> IDENTIFIED BY "managedb"
-> WITH GRANT OPTION;
現在改變這個用戶的口令為funkychicken,命令格式如下:
mysql> GRANT USAGE ON *.*
-> TO
[email protected] -> IDENTIFIED BY "funkychicken";
請注意我們沒有賦予任何另外的權限(the USAGE權限只能允許用戶登錄),但是用戶已經存在的權限不會被改變。
現在讓我們建立一個新的名為jessica的用戶,他可以從host.net域的任意機器連接到MySQL。他可以更新數據庫中用戶的姓名和email地址,但是不需要查閱其它數據庫的信息。也就是說他對db數據庫具有只讀的權限(例如,SELECT),但是他可以對Users表的name列和email列執行UPDATE操作。命令如下:
mysql> GRANT SELECT ON db.*
-> TO jessica@%.host.net
-> IDENTIFIED BY "jessrules";
mysql> GRANT UPDATE (name,email) ON db.Users
-> TO jessica@%.host.net;
請注意在第一個命令中我們在指定Jessica可以用來連接的主機名時使用了%(通配符)符號。此外,我們也沒有給他向其他用戶傳遞他的權限的能力,因為我們在命令的最後沒有帶上WITH GRANT OPTION。第二個命令示范了如何通過在賦予的權限後面的圓括號中用逗號分隔的列的列表對特定的數據列賦予權限。
使用REVOKE
正如你所預期的那樣,REVOKE命令是用來去除一個用戶以前被賦予的權限的。命令的語法如下:
mysql> REVOKE <privileges> [(<columns>)]
-> ON <what> FROM <user>;
這個命令中各部分的功能和在上面的GRANT命令中時一樣。要去除Jessica的合作者的DROP權限(例如,如果他經常錯誤地刪除數據庫和表),你可以使用下面的命令:
mysql> REVOKE DROP ON *.* FROM idiot@%.host.net;
去除一個用戶的登錄權限大概是唯一不能使用REVOKE的。REVOKE ALL ON *.*會去除用戶的所有權限,但是他還可以登錄,要完全地刪除一個用戶,你需要在user表中刪除相應的記錄:
mysql> DELETE FROM user
-> WHERE User="idiot" AND Host="%.host.net";
訪問控制技巧
由於MySQL中訪問控制系統工作的方法的影響,在建立你的用戶之前你必須知道兩個特征。
當建立的用戶只能從MySQL服務運行的計算機上登錄到MySQL服務(也就是說,你需要他們telnet到服務器並在那裡運行MySQL的客戶端程序,或者是使用象PHP這樣的服務器端腳本語言進行通信),你大概會問自己GRANT命令的<user>部分應該填什麼內容。如果服務是運行在www.host.net。你是應該將用戶設置為
[email protected]還是username@localhost呢?
答案是,你不能依賴其中的任何一種來處理任何連接。從理論上來說,如果用戶在連接時(無論是使用mysql客戶端還是使用PHP的mysql_connect函數)指定了主機名,這個主機名必須與訪問控制系統中的記錄匹配。但是因為你也許不想強迫你的用戶指定主機名(事實上,mysql客戶端的用戶也許根本不會指定主機名),你最好使用下面這種工作環境。
對於用戶需要能夠從MySQL服務在其上運行的機器上連接MySQL的情況,在MySQL訪問控制系統中建立兩個用戶記錄:一個使用實際的主機名(例如,
[email protected]),另一個使用localhost(例如,username@localhost),當然,你需要為兩個用戶分別grant/revoke所有的權限。
MySQL管理者所要面對的另一個帶有普通性的問題是一個其中的主機名使用了通配符的用戶記錄(例如,前面提到jessica@%.host.net)沒起作用。發生這種情況,一般是由於MySQL訪問控制系統中記錄的優先級的問題。具體地說,越具體的主機名優先級越高(例如,www.host.net是最具體的,%.host.net是比較具體的,而%是最不具體的)。
在一個新安裝後,MySQL訪問控制系統包含兩個匿名用戶記錄(它允許在當前主機上使用任何用戶名進行連接--這兩個記錄分別支持從localhost連接以及從服務器的實現的主機名進行連接),以及兩個root用戶目錄。我們上面討論的情況發生時是由於匿名用戶目錄的優先級比我們的新記錄高,因為他們的主機名更具體。
讓我們看看www.host.net上user表的內容,我們假定已經添加了Jessica的記錄。數據行是按照MySQL服務在確認連接時的優先級排列的:
正如你看到的,因為Jessica的記錄的主機名最不具體,它的優先級最低。當Jessica試圖從www.host.net連接時,MySQL服務將他的連接匹配為一個匿名用戶記錄(空白的User值與任何人匹配)。因為這些匿名記錄不需要口令,而也許Jessica輸入了他的口令,MySQL將拒絕這個連接。即使Jessica沒有輸入口令,他可能也只被給予了匿名用戶的權限(非常有限),而不是他原來被賦予的權限。
解決這個問題的方法是,要麼你刪除匿名用戶的記錄(DELETE FROM user WHERE User=""),要麼再為所有的可能從localhost連接的用戶指定兩條記錄(例如,相對於localhost以及相對於服務器的實際主機名):
因為要為每個用戶維護三個用戶記錄(以及相應的三套權限)會很麻煩,所以我們推薦你刪除匿名用戶,除非你需要用他們來完成什麼特殊的應用:
被鎖在外面?
就象把鑰匙丟失在車上一樣,在花費了一個小時安裝並調試好一個新的MySQL服務器之後忘記了口令的確是件麻煩事。幸運的是,如果你有訪問MySQL運行的計算機的root權限,或者你能夠使用運行MySQL服務的用戶登錄(如果你按照第一章中的指導,這是指mysqlusr),那麼不會出什麼問題。按照下面的步驟,你可以獲得服務的控制權。
首先,你必須關閉MySQL服務。因為通常使用的mysqladmin需要用到你忘了的口令,你只能通過殺掉服務的進程來完成這項工作。使用ps命令或者看看服務的PID文件(在MySQL數據目錄下),確定MySQL服務的進程的ID,然後使用下面的命令終止它:
% kill <pid>
這裡<pid>是MySQL服務的進程的ID。這樣將可以終止服務。除非絕對必要,不要使用kill -9,因為這樣有可能損壞你的表文件。如果你被迫只能這麼做,下面將告訴你如何檢查和修復那些文件。
關閉了服務之後,你可以通過運行帶--skip-grant-tables命令行選項的safe-mysqld (在Windows下使用mysqld或mysqld-nt)命令重啟它。這將指示MySQL服務允許自由的訪問,明顯的,我們應該盡可能地短時間的使用這種模式運行服務,以避免固有的安全風險。
連接成功後,改變你的root口令:
mysql> USE mysql;
mysql> UPDATE user SET Password=PASSWORD("newpassword")
-> WHERE User="root";
最後,斷開連接並指示MySQL服務重載授權表以接收新的口令:
% mysqladmin flush-privileges
現在一切都好了--甚至不會有人知道你干了什麼。就象你雖然將鑰匙丟在了車上,而你自己也在車上一樣。
檢查和修復MySQL數據文件
由於臨時斷電,使用kill -9中止MySQL服務進程,或者是Jessica的朋友idiot@%.host.net又犯了一個錯誤,所有的這些都可能會毀壞MySQL的數據文件。如果在被干擾時,服務正在改變文件,文件可能會留下錯誤的或不一致的狀態。因為這樣的毀壞有時是不容易被發現的,當你發現這個錯誤時可能是很久以後的事了。於是,當你發現這個問題時,也許所有的備份都有同樣的錯誤。
MySQL參考手冊的第十五章講述了MySQL自帶的myisamchk的功能,以及如何使用它檢查和修復你的MySQL數據文件。雖然這一章對於每個想要搭建一個強壯的MySQL服務的人都是推薦閱讀的,我們還是有必要在這裡對其中的要點進行討論。
在我們繼續之前,你必須意識到myisamchk程序對用來檢查和修改的MySQL數據文件的訪問應該是唯一的。如果MySQL服務正在使用某一文件,並對myisamchk正在檢查的文件進行修改,myisamchk會誤以為發生了錯誤,並會試圖進行修復--這將導致MySQL服務的崩潰!這樣,要避免這種情況的發生,通常我們需要在工作時關閉MySQL服務。作為選擇,你也可以暫時關閉服務以制作一個文件的拷貝,然後在這個拷貝上工作。當你做完了以後,重新關閉服務並使用新的文件取代原來的文件(也許你還需要使用期間的變更日志)。
MySQL數據目錄不是太難理解的。每一個數據庫對應一個子目錄,每個子目錄中包含了對應於這個數據庫中的數據表的文件。每一個數據表對應三個文件,它們和表名相同,但是具有不同的擴展名。tblName.frm文件是表的定義,它保存了表中包含的數據列的內容和類型。tblName.MYD文件包含了表中的數據。tblName.MYI文件包含了表的索引(例如,它可能包含lookup表以幫助提高對表的主鍵列的查詢)。
要檢查一個表的錯誤,只需要運行myisamchk(在MySQL的bin目錄下)並提供文件的位置和表名,或者是表的索引文件名:
% myisamchk /usr/local/mysql/var/dbName/tblName
% myisamchk /usr/local/mysql/var/dbName/tblName.MYI
上面的兩個命令都可以執行對指定表的檢查。要檢查數據庫中所有的表,可以使用通配符:
% myisamchk /usr/local/mysql/var/dbName/*.MYI
要檢查所有數據庫中的所有表,可以使用兩個通配符:
% myisamchk /usr/local/mysql/var/*/*.MYI
如果不帶任何選項,myisamchk將對表文件執行普通的檢查。如果你對一個表有懷疑,但是普通的檢查不能發現任何錯誤,你可以執行更徹底的檢查(但是也更慢!),這需要使用--extend-check選項:
% myisamchk --extend-check /path/to/tblName
對錯誤的檢查是沒有破壞性的,這意味著你不必擔心執行對你的數據文件的檢查會使已經存在的問題變得更糟。另一方面,修復選項,雖然通常也是安全的,但是它對你的數據文件的更改是無法撤消的。因為這個原因,我們強烈推薦你試圖修復一個被破壞的表文件時首先做個備份,並確保在制作這個備份之前你的MySQL服務是關閉的。
當你試圖修復一個被破壞的表的問題時,有三種修復類型。如果你得到一個錯誤信息指出一個臨時文件不能建立,刪除信息所指出的文件並再試一次--這通常是上一次修復操作遺留下來的。
這三種修復方法如下所示:
第一種是最快的,用來修復最普通的問題;而最後一種是最慢的,用來修復一些其它方法所不能修復的問題。
檢查和修復MySQL數據文件
如果上面的方法無法修復一個被損壞的表,在你放棄之前,你還可以試試下面這兩個技巧:
如果你懷疑表的索引文件(*.MYI)發生了不可修復的錯誤,甚至是丟失了這個文件,你可以使用數據文件(*.MYD)和數據格式文件(*.frm)重新生成它。首先制作一個數據文件(tblName.MYD)的拷貝。重啟你的MySQL服務並連接到這個服務上,使用下面的命令刪除表的內容:
mysql> DELETE FROM tblName;
在刪除表的內容的同時,會建立一個新的索引文件。退出登錄並重新關閉服務,然後用你剛才保存的數據文件(tblName.MYD)覆蓋新的(空)數據文件。最後,使用myisamchk執行標准的修復(上面的第二種方法),根據表的數據的內容和表的格式文件重新生成索引數據。
如果你的表的格式文件(tblName.frm)丟失了或者是發生了不可修復的錯誤,但是你清楚如何使用相應的CREATE TABLE語句來重新生成這張表,你可以重新生成一個新的.frm文件並和你的數據文件和索引文件(如果索引文件有問題,使用上面的方法重建一個新的)一起使用。首先制作一個數據和索引文件的拷貝,然後刪除原來的文件(刪除數據目錄下有關這個表的所有記錄)。
啟動MySQL服務並使用當初的CREATE TABLE文件建立一個新的表。新的.frm文件應該可以正常工作了,但是最好你還是執行一下標准的修復(上面的第二種方法)。
結語
OK,的確這一章沒有多少我們通常所習慣的可以具體執行某項實際工作的代碼。但是所有的這些工作--備份和恢復數據庫,管理MySQL的訪問控制系統,數據表的檢查和修復--都將有助於我們建立一個經得住時間考驗的MySQL數據庫服務器。
在本教程的倒數第二章——第九章中,我們會學習一些更復雜的SQL技術以使得我們的關系型數據庫服務器可以完成一些你之前也許從未想到過的工作。