附錄A:問題和常見錯誤

目錄

A.1. 如何確定導致問題的原因
A.2. 使用MySQL程式時的常見錯誤
A.2.1. 拒絕訪問
A.2.2. 無法連接到[local] MySQL伺服器
A.2.3. 客戶端不支援鑒定協議
A.2.4. 輸入密碼時出現密碼錯誤
A.2.5. 主機的host_name被屏蔽
A.2.6. 連接數過多
A.2.7. 內存溢出
A.2.8. MySQL伺服器不可用
A.2.9. 訊息包過大
A.2.10. 通信錯誤和失效連接
A.2.11. 資料表已滿
A.2.12. 無法建立檔案/寫入檔案
A.2.13. 命令不同步
A.2.14. 忽略用戶
A.2.15. 資料表tbl_name不存在
A.2.16. 無法初始化字元編碼
A.2.17. 檔案未找到
A.3. 與安裝有關的事宜
A.3.1. 與MySQL客戶端庫的連結問題
A.3.2. 如何以普通用戶身份運行MySQL
A.3.3. 與檔案授權有關的問題
A.4. 與管理有關的事宜
A.4.1. 如何復位根用戶密碼
A.4.2. 如果MySQL依然崩潰,應作些什麼
A.4.3. MySQL處理磁盤滿的方式
A.4.4. MySQL將臨時檔案儲存在哪裡
A.4.5. 如何保護或更改MySQL套接字檔案/tmp/mysql.sock
A.4.6. 時區問題
A.5. 與查詢有關的事宜
A.5.1. 搜索中的大小寫敏感性
A.5.2. 使用DATE列方面的問題
A.5.3. 與NULL值有關的問題
A.5.4. 與列別名有關的問題
A.5.5. 非事務資料表回滾失敗
A.5.6. 從相關資料表刪除行
A.5.7. 解決與不匹配行有關的問題
A.5.8. 與浮點比較有關的問題
A.6. 與最佳化器有關的事宜
A.7. 與資料表定義有關的事宜
A.7.1. 與ALTER TABLE有關的問題
A.7.2. 如何更改資料表中的列順序
A.7.3. TEMPORARY TABLE問題
A.8. MySQL中的已知事宜
A.8.1. MySQL中的打開事宜
在本附錄中,列出了一些您可能會遇到的常見問題和錯誤消息。並介紹了確定故障原因的方法,以及為解決問題所應採取的措施。

A.1. 如何確定導致問題的原因

當您遇到問題時,首先要做的是找出導致問題的程式和設備部件:

·         如果遇到下述徵兆之一,或許是因為硬件問題(如內存、主板、CPU或硬盤)或內核問題:

1.    鍵盤不工作。正常情況下可通過按Caps Lock建進行檢查。如果Caps Lock的點亮狀態未改變,就需要更換鍵盤(在此之前,應嘗試重啟計算機,並檢查與鍵盤相連的所有電纜)。

2.    鼠標指針不移動。

3.    機器未對遠程機器的Ping命令做出應答。

4.    MySQL無關的其他程式工作不正常。

5.    系統意外重啟(有問題的用戶級程式應不能使系統出現嚴重問題)。

在該情況下,應檢查所有的電纜並運行某些診斷工具,對您的硬件進行檢查!此外,還應檢查是否有能夠解決問題的、適用於您的作業系統的補丁、更新或服務包。請檢查所有的庫(如glibc)是否是最新的。

使用配備ECC內存的機器以便盡早發現問題總是個好主意。

·         如果鍵盤已鎖定,可從另一台機器登錄到您的機器,並執行kbd_mode –a,或許能恢復。

·         請檢查系統的日誌檔案(/var/log/messages或類似物)以找出問題的原因。如果您認為問題出在MySQL中,應檢查MySQL的日誌檔案。請參見5.11節,「MySQL日誌檔案」

·         如果您不認為存在硬件問題,應嘗試找出導致問題的原因。請使用topps、任務管理器或類似程式,以檢查哪個程式佔用了所有CPU時間或鎖定了機器。

·         使用topdf或類似程式檢查是否內存不夠、磁盤空間不足、檔案描述符缺乏、或其他關鍵資源缺少。

·         如果問題是失去控制的程序,應嘗試殺死它。如果殺不死程序,或許是因為作業系統中存在問題。

如果在檢查了所有其他可能性之後,並得出結論問題是由MySQL伺服器或MySQL客戶端導致的,應建立提供給我方的郵件列資料表或支援團隊的問題報告。在問題報告中,請詳細描述系統的行為,以及您認為發生了什麼情況。+3.

還應闡明為什麼您認為是MySQL導致了問題。請考慮本章介紹的所有情況。準確闡明當您檢查系統時問題是如何出現的。對於程式和日誌檔案的任何輸出和錯誤消息,請使用「複製和粘貼」方法。

盡量詳細描述不工作的程式,以及您所見到的所有徵兆。我們過去收到過很多僅說明「系統不工作」的問題報告。這不會為我們提供有助於解決問題的訊息。

如果程式失敗,瞭解下述訊息總是有用的:

·         有嫌疑的程式是否出現了分段故障(是否轉儲內核)?

·         程式是否佔用了所有可用的CPU時間?用top.進行檢查。讓程式運行一段時間,或許能簡單地評估某些事是否是計算密集性的。

·         如果問題是因mysqld伺服器導致的,使用mysqladmin -u root pingmysqladmin -u root processlist是否能獲得伺服器的響應?

·         當您嘗試連接到MySQL伺服器(例如,mysql)時,客戶端程式給出的訊息是什麼?客戶端是否堵塞?是否獲得了來自程式的任何輸出?

發送問題報告時,請遵循1.7.1.2節,「請教問題或通報問題」中給出的說明。

A.2. 使用MySQL程式時的常見錯誤

本節列出了用戶運行MySQL伺服器時常會遇到的一些錯誤。儘管問題是在您嘗試運行客戶端時出現的,但對很多問題的解決方案來說,需要更改MySQL伺服器的配置。

A.2.1. 拒絕訪問

導致拒絕訪問錯誤的原因很多。該錯誤常與連接時伺服器允許客戶端使用的MySQL帳號有關。請參見5.7.8節,「拒絕訪問錯誤的原因。請參見5.7.2節,「權限系統工作原理」

A.2.2. 無法連接到[local] MySQL伺服器

Unix平台上的MySQL客戶端能夠以兩種不同的方式連接到mysqld伺服器:通過檔案系統中的檔案(預設為/tmp/mysql.sock)使用Unix套接字進行連接,或通過端口號使用TCP/IP進行連接。Unix套接字檔案的連接速度比TCP/IP快,但僅能在與相同計算機上的伺服器相連時使用。如果未指定指定主機名或指定了特殊的主機名localhost,將使用Unix套接字。

如果MySQL伺服器運行在Windows 9xMe上,僅能通過TCP/IP進行連接。如伺服器運行在Windows NT2000XP2003上,而且使用--enable-named-pipe選項啟動,如果在運行伺服器的機器上運行客戶端,也能使用命名管道進行連接。預設情況下,命名管道的名稱為MySQL。如果在連接到mysqld時未給定主機名,MySQL客戶端首先會嘗試連接到命名管道。如果不能工作,將連接到TCP/IP端口。使用「.」作為主機名,可在Windows平台上強制使用命名管道。

錯誤(2002)「無法連接到…」通常意味著在系統沒有運行的MySQL伺服器,或在連接到伺服器時使用了不正確的Unix套接字檔案名或TCP/IP端口號。

首先檢查伺服器主機上是否有名為mysqld的程序(在Unix平台上使用ps xa | grep mysqld,或在Windows平台上使用任務管理器)。如果沒有這類程序,應啟動伺服器。請參見2.9.2.3節,「啟動MySQL伺服器以及其故障診斷和排除」

如果mysqld程序正在運行,可使用下述命令檢查。在您的具體設置中,端口號或Unix套接字檔案名可能會有所不同。host_ip代資料表運行伺服器的機器的IP編號。

shell> mysqladmin version
shell> mysqladmin variables
shell> mysqladmin -h `hostname` version variables
shell> mysqladmin -h `hostname` --port=3306 version
shell> mysqladmin -h host_ip version
shell> mysqladmin --protocol=socket --socket=/tmp/mysql.sock version

注意,應與主機名命令一起使用「`」而不是「』」,這會使主機名輸出(當前主機名)被代入mysqladmin命令。如果沒有主機名命令或正運行在Windows平台上,應以手動方式輸入機器的主機名(無「`」符號),後跟-h選項。也可以使用TCP/IP協議用-h 127.0.0.1連接到本地主機。

下面給出了一些「無法連接到本地MySQL伺服器」錯誤的可能原因:

1.    Mysqld未運行。請檢查作業系統的程序列資料表以確保mysqld程序正在運行。

2.    您正在具有很多TCP/IP連接的Windows平台上運行MySQL伺服器。如果您的客戶端經常出現錯誤,請參見A.2.2.1節,「在Windows上與MySQL伺服器的連接失敗」,以找出規避方法。

3.    您正在使用MIT-pthreads的系統上運行。如果您正在運行不具有固有線程的作業系統,mysqld將使用MIT-pthreads軟件包。請參見2.1.1節,「MySQL支援的作業系統」。但是,並非所有的MIT-pthreads版本均支援Unix套接字檔案。在不支援套接字檔案的系統上,連接到伺服器時,必須明確指定主機名。請使用下述命令來檢查是否連接到了伺服器:

4.           shell> mysqladmin -h `hostname` version

5.    某人移動了mysqld使用的Unix套接字檔案(預設為/tmp/mysql.sock)。例如,您可能執行了將舊檔案從/tmp目錄刪除的cron任務。您總能執行mysqladmin version來檢查mysqladmin試圖使用的Unix套接字檔案是否的確存在。在該情況下,更正方式是更改cron任務,不刪除mysql.sock檔案,或將套接字檔案置於其他地方。請參見A.4.5節,「如何保護或更改MySQL套接字檔案/tmp/mysql.sock

6.    您使用--socket=/path/to/socket選項啟動了mysqld伺服器,當忘記將套接字檔案的新名稱通知客戶端程式。如果更改了關於伺服器的套接字路徑,也必須通知MySQL客戶端。可在運行客戶端程式時使用相同的—socket選項來完成該任務。此外,您還應確保客戶端具有訪問檔案mysql.sock的權限。要想找出套接字檔案的位置,可使用:

7.           shell> netstat -ln | grep mysql

請參見A.4.5節,「如何保護或更改MySQL套接字檔案/tmp/mysql.sock

8.    您正在使用Linux而且1個伺服器線程已死亡(內核已清除)。在此情況下,在重啟MySQL伺服器之前,必須殺死其他mysqld線程(例如,使用killmysql_zap指令)。請參見A.4.2節,「如果MySQL依然崩潰,應作些什麼」

9.    伺服器或客戶端程式不具有訪問包含Unix套接字檔案的目錄或套接字檔案本身的恰當權限。在該情況下,必須更改目錄或套接字檔案的訪問權限,以便伺服器或客戶端程式能夠訪問它們,或用–socket選項重啟mysqld,在該選項中指定伺服器能建立、而且客戶端可訪問的目錄下的套接字檔案名。

如果遇到錯誤消息「無法連接到some_host上的MySQL伺服器」,可嘗試採取下述步驟以找出問題所在:

·         執行「telnet some_host 3306並按兩次回車鍵,檢查伺服器是否運行在該主機上(3306是預設的MySQL端口號。如果您的伺服器正在監聽不同的端口,請更改該值)。如果有1MySQL伺服器正在運行並監聽該端口,您應收到包含伺服器版本號的回應。如果遇到錯誤,如「telnet:無法連接到遠程主機:拒絕連接,資料表示在該定端口上沒有運行的伺服器。

·         如果伺服器正運行在本地主機上,請使用Unix套接字檔案,並使用mysqladmin -h localhost variables進行連接。驗證伺服器監聽的TCP/IP端口號(它是port變數的值)。

·         確保您的mysqld伺服器未用--skip-networking選項啟動。如果使用了該選項,將無法使用TCP/IP連接到它。

·         檢查並確認不存在屏蔽了對MySQL訪問的防火牆。需要配置諸如ZoneAlarmWindows XP個人防火牆等應用程式,以允許對MySQL伺服器的外部訪問。

A.2.2.1. 在Windows上與MySQL伺服器的連接失敗

當您在具有很多TCP/IP連接的Windows上運行MySQL伺服器,並經常在客戶端上遇到「無法連接到MySQL伺服器」錯誤時,可能是因為Windows不允許足夠的臨時(短命)端口用於這類連接。

預設情況下,Windows允許用於使用5000個臨時(短命)TCP端口。任何端口關閉後,它將在TIME_WAIT狀態保持120秒。與重新初始化全新的連接相比,該狀態允許以更低的開銷重新使用連接。但是,在該時間逝去前,無法再次使用該端口。

對於小的可用TCP端口堆棧(5000),以及具有TIME_WAIT狀態的大量在短時間內打開和關閉的TCP端口,您很可能遇到端口耗盡問題。處理該問題的方法有兩種:

·         通過調查連接池以及可能的持久連接,減少快速消耗的TCP端口數。

·         調整Windows註冊資料表中的某些設置(請參見下面)。

要點:下述步驟涉及更改Windows 註冊資料表。更改註冊資料表之前,請備份註冊資料表,並確認您已掌握在出現問題時恢復註冊資料表的方法。關於備份年、恢復和編輯註冊資料表的更多訊息,請請參見Microsoft知識庫中的下述文獻:http://support.microsoft.com/kb/256986/EN-US/

·         啟動註冊資料表編輯器(Regedt32.exe)。

·         在註冊資料表中確定下述鍵值的位置:

·                HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

·         在「編輯」菜單上點擊「新增值」,然後增加下述註冊值:

·                Value Name: MaxUserPort
·                Data Type: REG_DWORD
·                Value: 65534

它用於設置為任何用戶提供的臨時端口數。有效範圍介於500065534之間(十進制)。預設值為0x13885000,十進制)。

·         在「編輯」菜單上點擊「新增值」,然後增加下述註冊值:

·                Value Name: TcpTimedWaitDelay
·                Data Type: REG_DWORD
·                Value: 30

它用於設置關閉之前將TCP端口連接保持在TIME_WAIT狀態的秒數。有效範圍介於0秒和300秒之間。預設值為0x78120秒)。

·         退出註冊資料表編輯器。

·         重新引導機器。

註釋:撤銷上述設置十分簡單,就像刪除您建立的註冊資料表一樣。

A.2.3. 客戶端不支援鑒定協議

MySQL 5.1採用了基於密碼混編算法的鑒定協議,它與早期客戶端(4.1之前)使用的協議不兼容。如果您將伺服器升級到4.1之上,用早期的客戶端進行連接可能失敗,並給出下述消息:

shell> mysql
客戶端不支援伺服器請求的鑒定協議:請考慮升級MySQL客戶端。

要想解決該問題,應使用下述方法之一:

·         升級所有的客戶端程式,以使用4.1.1或更新的客戶端庫。

·         4.1版之前的客戶端連接到伺服器時,請使用仍具有4.1版之前風格密碼的帳號。

·         對於需要使用4.1版之前的客戶端的每位用戶,將密碼恢復為4.1版之前的風格。可以使用SET PASSWORD語句和OLD_PASSWORD()函數完成該任務:

·                mysql> SET PASSWORD FOR
·                    -> 'some_user'@'some_host' = OLD_PASSWORD('newpwd');

也可以使用UPDATEFLUSH PRIVILEGES

mysql> UPDATE mysql.user SET Password = OLD_PASSWORD('newpwd')
    -> WHERE Host = 'some_host' AND User = 'some_user';
mysql> FLUSH PRIVILEGES;

用您打算使用的密碼替換前例中的「newpwd」。MySQL不能告訴您原來的密碼是什麼,因此,您需要選擇新的密碼。

·         通知伺服器使用舊的密碼混編算法:

1.    使用「--old-passwords」選項啟動mysqld

2.    對於已將密碼更新為較長4.1格式的每個帳號,為其指定具有舊格式的密碼。可以使用下述查詢確定這些帳號:

3.                 mysql> SELECT Host, User, Password FROM mysql.user
4.                     -> WHERE LENGTH(Password) > 16;

對於查詢顯示的每個帳號記錄,請使用HostUser值,並使用OLD_PASSWORD()函數以及SET PASSWORDUPDATE之一指定密碼,如前面所介紹的那樣。

註釋:在早期的PHP版本中,mysql延伸不支援MySQL 4.1.1和更高版中的鑒定協議。無論使用的PHP版本是什麼,它均是正確的。如果您打算與MySQL 4.1或更高版本一起使用mysql延伸,需要使用前面介紹的選項之一,配置MySQL,以便與較早的客戶端一起使用。mysqli延伸(支援改進的MySQL」,在PHP 5中增加)與MySQL 4.1和更高版本中使用的改進的密碼混編算法兼容,不需要對MySQL進行特殊配置就能使用該MySQL客戶端庫。關於mysqli延伸的更多訊息,請參見http://php.net/mysqli

關於密碼混編和鑒定功能的額外背景知識,請參見5.7.9節,「MySQL 4.1中的密碼哈希處理」

A.2.4. 輸入密碼時出現密碼錯誤

使用無下述密碼值的「—password」-p」選項使用時,MySQL客戶端程式將提示輸入密碼:
shell> mysql -u user_name -p
Enter password:

在某些系統上,當您在選項檔案或命令行上指定時,您可能會發現密碼能夠工作,但是當您在「Enter password:」提示下以交互方式輸入密碼時,您可能會發現輸入的密碼不工作。當系統所提供的用於讀取密碼的庫將密碼值限定在少數字元時(典型情況下為8個),就會出現該問題。這是與系統庫有關的問題,與MySQL無關。要想處理該問題,可將MySQL密碼更改為由8個字元或更少字元構成的值,或將密碼置於選項檔案中。

A.2.5. 主機的host_name被屏蔽

如果遇到下述錯誤,資料表示mysqld已收到來來自主機「host_name」的很多連接請求,但該主機卻在中途中斷。

由於出現很多連接錯誤,主機'host_name'被屏蔽。
可使用'mysqladmin flush-hosts'解除屏蔽。

允許的中斷連接請求的數目由max_connect_errors系統變數的值決定。當超出max_connect_errors規定的連接請求時,mysqld將認為某處出錯(例如,某人正試圖插入),並屏蔽主機的進一步連接請求,直至執行了mysqladmin flush-hosts命令,或發出了FLUSH HOSTS語句為止。請參見5.3.3節,「伺服器系統變數」

在預設情況下,mysqld會在10次連接錯誤後屏蔽主機。您可以通過下述方式啟動伺服器來調整該值:

shell> mysqld_safe --max_connect_errors=10000 &

如果在給定主機上遇到該錯誤,首先應核實該主機的TCP/IP連接是否正確。如果存在網絡問題,增加max_connect_errors變數的值不會有任何好處。

A.2.6. 連接數過多

當您試圖連接到mysqld伺服器時遇到「過多連接」錯誤,這資料表示所有可用的連接均已被其他客戶端使用。

允許的連接數由max_connections系統變數控制。預設值為100。如果需要支援更多的連接,應使用該變數的較大值重啟mysqld

mysqld實際上允許max_connections+1個客戶端進行連接。額外的連接保留給具有SUPER權限的帳號。通過為系統管理員而不是普通用戶授予SUPER權限(普通用戶不應具有該權限),系統管理員能夠連接到伺服器,並使用SHOW PROCESSLIST來診斷問題,即使已連接的無特權客戶端數已達到最大值也同樣。請參見13.5.4.16節,「SHOW PROCESSLIST語法」

MySQL能支援的最大連接數取決於給定平台上線程庫的質量。LinuxSolaris應能支援500-1000個並發連接,具體情況取決於RAM容量,以及客戶端正在作什麼。MySQL AB提供的靜態Linux庫能支援高達4000個連接。

A.2.7. 內存溢出

如果使用mysql客戶端程式發出了查詢,並收到下述錯誤之一,則資料表示mysql沒有足夠內存來保存全部查詢結果:

mysql: Out of memory at line 42, 'malloc.c'
mysql: needed 8136 byte (8k), memory in use: 12481367 bytes (12189k)
錯誤2008: MySQL client ran out of memory

要想更正該問題,首先應檢查查詢是否正確。返回這麼多行是否合理?如果不合理,更正查詢並再次嘗試。否則,應使用「--quick」選項使用mysql。這樣,將使用mysql_use_result() C API函數來檢索結果集,這類函數能夠降低客戶端上的負載(但會加重伺服器上的負載)。

A.2.8. MySQL伺服器不可用

在本節中,還介紹了出現查詢錯誤期間,與丟失了伺服器連接有關的事宜。

MySQL伺服器不可用錯誤的最常見原因是伺服器超時以及連接已關閉。在該情況下,通常能見到下述錯誤代碼之一(具體的錯誤代碼與作業系統有關):

錯誤代碼

描述

CR_SERVER_GONE_ERROR

客戶端無法將問題發送至伺服器。

CR_SERVER_LOST

寫入伺服器時客戶端未收到錯誤,但也未獲得問題的完整答案(或任何答案)。

在預設情況下,如果未發生任何事,8小時後伺服器將關閉連接。也可以在啟動mysqld時,通過設置wait_timeout變數更改時間限制。請參見5.3.3節,「伺服器系統變數」.

如果有1個指令,您僅需要再次發出查詢,讓客戶端再次進行自動連接即可。其中,假定在客戶端中啟用了自動再連接功能(對於mysql命令行客戶端,這是預設設置)。

MySQL伺服器不可用錯誤的一些其他常見原因如下:

·         您(或db系統管理員)使用KILL語句或mysqladmin kill命令殺死了正在運行的線程。

·         您試圖在關閉了與伺服器的連接後運行查詢。這表明應更正應用程式中的邏輯錯誤。

·         您在客戶端一側遇到TCP/IP連接超時錯誤。如果您使用了命令:mysql_options(..., MYSQL_OPT_READ_TIMEOUT,...)mysql_options(..., MYSQL_OPT_WRITE_TIMEOUT,...),就可能出現該問題。在該情況下,增加超時值可能有助於問題的解決。

·         您在伺服器端遇到超時錯誤,而且禁止了客戶端中的自動再連接功能(MYSQL結構中的再連接標誌等於0)。

·         您正在使用Windows客戶端,而且在發出命令之前伺服器撤銷了連接(或許是因為已超過wait_timeout

Windows平台上出現問題的原因,在某些情況下,將TCP/IP連接寫入伺服器時,MySQL未收到來自作業系統的錯誤,但當試圖從連接讀取答案時出現錯誤。

在該情況下,即使MYSQL結構中的再連接標誌等於1MySQL也不會執行自動再連接並再次發出查詢,這是因為它不知道伺服器是否收到原始查詢。

對此的解決方式是:如果自上一次查詢以來經過了較長時間,在連接上執行mysql_ping(正是MyODBC所作的);或在mysqld伺服器上將wait_timeout設置得很高,使之實際上不存在超時。

·         如果您向伺服器發出了不正確或過大的查詢,也會遇到這類問題。如果mysqld收到過大或無序的訊息包,它會認為客戶端出錯,並關閉連接。如果需要執行較大的查詢(例如,正在處理大的BLOB列),可通過設置伺服器的max_allowed_packet變數,增加查詢限制值,該變數的預設值為1MB。或許,您還需增加客戶端上的最大訊息包大小。關於設置訊息包大小的更多訊息,請參見A.2.9節,「訊息包過大」

·         如果您的客戶端低於4.0.8而且您的伺服器高於4.0.8,當您接收16MB或更大的訊息包時,可能會丟失連接。

·         如果MySQL是用「--skip-networking」選項啟動的,也會見到MySQL伺服器不可用錯誤。

·         您遇到了執行查詢時伺服器宕機的問題。

通過執行mysqladmin version並檢查伺服器的正常工作時間,可檢查伺服器是否宕機並重啟。如果客戶端連接是因mysqld崩潰和重啟而中斷的,應將重點放在搜尋崩潰您方面。首先應再次檢查發出的查詢是否再次殺死了伺服器。請參見A.4.2節,「如果MySQL依然崩潰,應作些什麼」

用「--log-warnings=2選項啟動mysqld,可獲得關於連接的更多訊息。這樣,就能將某些中斷連接錯誤記錄到hostname.err檔案中。請參見5.11.1節,「錯誤日誌」

如果您打算建立與該問題有關的問題報告,務必包含下述訊息:

1.    指明MySQL伺服器是否宕機。通過伺服器錯誤日誌可發現這方面的訊息。請參見A.4.2節,「如果MySQL依然崩潰,應作些什麼」

2.    如果特定查詢殺死了mysqld,而且在運行查詢前用CHECK TABLE檢查了涉及的資料表,您是否能提供可重複的測試範例?請參見E.1.6節,「如果出現資料表崩潰,請生成測試案例」

3.    MySQL伺服器中,系統變數wait_timeout的值是什麼?mysqladmin variables給出了該變數的值)。

4.    您是否嘗試使用「--log」選項來運行mysqld,以確定是否在日誌中出現問題?

另請參見A.2.10節,「通信錯誤和失效連接」

請參見1.7.1.2節,「請教問題或通報問題」

A.2.9. 訊息包過大

通信訊息包是發送至MySQL伺服器的單個SQL語句,或發送至客戶端的單一行。

MySQL 5.1伺服器和客戶端之間最大能發送的可能訊息包為1GB

MySQL客戶端或mysqld伺服器收到大於max_allowed_packet字節的訊息包時,將發出訊息包過大錯誤,並關閉連接。對於某些客戶端,如果通信訊息包過大,在執行查詢期間,了能回遇到丟失與MySQL伺服器的連接錯誤。

客戶端和伺服器均有自己的max_allowed_packet變數,因此,如您打算處理大的訊息包,必須增加客戶端和伺服器上的該變數。

如果您正在使用mysql客戶端程式,其max_allowed_packet變數的預設值為16MB。要想設置較大的值,可用下述方式啟動mysql

mysql> mysql --max_allowed_packet=32M

它將訊息包的大小設置為32MB

伺服器的預設max_allowed_packet值為1MB。如果伺服器需要處理大的查詢,可增加該值(例如,如果準備處理大的BLOB列)。例如,要想將該設置為16MB,可採用下述方式啟動伺服器:

mysql> mysqld --max_allowed_packet=16M

也能使用選項檔案來設置max_allowed_packet要想將伺服器的該變數設置為16MB,可在選項檔案中增加下行內容:

[mysqld]
max_allowed_packet=16M

增加該變數的值十分安全,這是因為僅當需要時才會分配額外內存。例如,僅當您發出長查詢或mysqld必須返回大的結果行時mysqld才會分配更多內存。該變數之所以取較小預設值是一種預防措施,以捕獲客戶端和伺服器之間的錯誤訊息包,並確保不會因偶然使用大的訊息包而導致內存溢出。

如果您正是用大的BLOB值,而且未為mysqld授予為處理查詢而訪問足夠內存的權限,也會遇到與大訊息包有關的奇怪問題。如果懷疑出現了該情況,請嘗試在mysqld_safe指令開始增加ulimit -d 256000,並重啟mysqld

A.2.10. 通信錯誤和失效連接

對於連接問題,伺服器錯誤日誌是有用的資訊來源。請參見5.11.1節,「錯誤日誌」。如果伺服器是用「--log-warnings」選項啟動的,在錯誤日誌中可能會發現下述消息:

010301 14:38:23  Aborted connection 854 to db: 'users' user: 'josh'

如果「Aborted connections」(放棄連接)消息出現在錯誤日誌中,可能的原因是:

1.    客戶端程式在退出之前未使用mysql_close()

2.    客戶端的空閒時間超過wait_timeoutinteractive_timeout秒,未向伺服器發出任何請求。請參見5.3.3節,「伺服器系統變數」

3.    客戶端在數據傳輸中途突然結束。

出現這類情況時,伺服器將增加「Aborted_clients」(放棄客戶端)狀態變數。

出現下述情況時,伺服器將增加「Aborted_clients」(放棄客戶端)狀態變數。

·         客戶端不具有連接至資料庫的權限。

·         客戶端採用了不正確的密碼。

·         連接訊息包不含正確訊息。

·         獲取連接訊息包的時間超過connect_timeout秒。請參見5.3.3節,「伺服器系統變數」

如果出現這類情況,可能表明某人正試圖侵入您的伺服器!

對於放棄客戶端或放棄連接問題,其他可能的源應包括:

·         Linux一起使用以太網協議,半雙工或全雙工。很多Linux以太網驅動均存在該問題。應通過FTP在客戶端和伺服器機器之間傳輸大檔案來測試該問題。如果傳輸處於burst-pause-burst-pause(爆發-暫停-爆發-暫停)模式,表明您遇到了Linux雙工故障。唯一的解決方法是,將網卡和Hub/交換器的雙工模式切換為全雙工或半雙工,並對結果進行測試以確定最佳設置。

·         與線程庫有關的某些問題導致讀取中斷。

·         配置不良的TCP/IP

·         有問題的以太網、Hub、交換器、電纜等。僅能通過更換硬件才能恰當診斷。

·         變數max_allowed_packet過小或查詢要求的內存超過為mysqld分配的內存。請參見A.2.9節,「訊息包過大」

另請參見A.2.8節,「MySQL伺服器不可用」

A.2.11. 資料表已滿

資料表已滿錯誤出現的方式有數種:

·         您正在使用低於3.23版的MySQL伺服器,而且「內存中」臨時資料表超過了tmp_table_size字節。要想避免該問題,可使用「-O tmp_table_size=val」選項以便mysqld增加臨時資料表的大小,或在發出有問題的查詢之前,使用SQL選項SQL_BIG_TABLES請參見13.5.3節,「SET語法」

也可以使用「--big-tables」選項啟動mysqld。它與使用針對所有查詢的SQL_BIG_TABLES完全相同。

MySQL 3.23起,該問題應不再出現。如果「內存中」臨時資料表超過tmp_table_size,伺服器會自動將其轉換為基於磁盤的MyISAM資料表。

·         您正在使用InnoDB資料表,並超出了InnoDB資料表空間。在該情況下,解決方法是增加InnoDB資料表空間。請參見15.2.7節,「新增和刪除InnoDB數據和日誌檔案

·         您正在僅支援2GB檔案的作業系統上使用ISAMMyISAM資料表,數據檔案或索引檔案達到了該限制值。

·         您正在使用MyISAM資料表,而且資料表所需的空間超過內部指針允許的大小。如果在建立資料表時未指定MAX_ROWS資料表,MySQL將使用myisam_data_pointer_size系統變數。預設值為6字節,它足以容納65536TB數據。請參見5.3.3節,「伺服器系統變數」

使用該語句,可檢查最大數據/索引大小:

SHOW TABLE STATUS FROM database LIKE 'tbl_name';

也可以使用myisamchk -dv /path/to/table-index-file

如果指針大小過小,可使用ALTER TABLE更正該問題:

ALTER TABLE tbl_name MAX_ROWS=1000000000 AVG_ROW_LENGTH=nnn;

僅應為具有BLOBTEXT列的資料表指定AVG_ROW_LENGTH在該情況下,MySQL不能僅根據行數最佳化所需的空間。

A.2.12. 無法建立檔案/寫入檔案

如果對某些查詢遇到下述類型的錯誤,它意味著MySQL不能為臨時目錄下的結果集建立臨時檔案:

無法建立/寫入檔案'\\sqla3fe_0.ism'

前述錯誤是Windows平台上的典型消息,Unix平台上的消息與之類似。

一種更正方式是使用「--tmpdir」選項啟動mysqld,或在選項檔案的[mysqld]部分增加該選項。例如,要想指定目錄C:\temp,可使用:

[mysqld]
tmpdir=C:/temp

目錄C:\temp必須存在,並有足夠的空間允許MySQL寫入它。請參見4.3.2節,「使用選項檔案」

該錯誤的另一個原因可能是授權事宜。請確認MySQL伺服器能夠寫入tmpdir目錄。

此外,還用使用perror檢查錯誤代碼。伺服器無法寫入資料表的一個原因是檔案系統已滿。

shell> perror 28
錯誤代碼28:磁盤上無剩餘空間。

A.2.13. 命令不同步

如果遇到「命令不同步」錯誤,將無法在您的客戶端代碼中運行該命令,您正在以錯誤順序使用客戶端函數。

例如,如果您正使用mysql_use_result(),並打算在使用mysql_free_result()之前執行新查詢,就會出現該問題。如果您試圖執行兩次查詢,但並未在兩次查詢之間使用mysql_use_result()mysql_store_result(),也會出現該問題。

A.2.14. 忽略用戶

如果遇到下述錯誤,資料表示當啟動mysqld時或重新加載授權資料表時,在用戶資料表中發現具有非法密碼的帳號。

發現用戶'some_user'@'some_host'密碼錯誤:忽略用戶。

作為其結果,授權系統將簡單忽略帳號。

在下面的介紹中,指明了可能的原因和問題的更正措施:

1.    或許,您正打算用舊的用戶資料表運行新版本的mysqld。執行mysqlshow mysql user檢查Password(密碼)列是否短於16個字元,通過該方式可檢查該問題。如果結果是肯定的,可運行指令/add_long_password指令更正該問題。

2.    帳號具有舊的密碼(8字元長),而且未使用「--old-protocol」選項啟動mysqld。更新用戶資料表中的帳號,使之具有新的密碼,或使用「--old-protocol」選項重啟mysqld

3.    在用戶資料表中未使用PASSWORD()函數指定了密碼。使用mysql用新密碼更新用戶資料表中的帳號,務必使用PASSWORD()函數:

4.           mysql> UPDATE user SET Password=PASSWORD('newpwd')
5.               -> WHERE User='some_user' AND Host='some_host';

A.2.15. 資料表tbl_name不存在

如果遇到下述錯誤之一,通常意味著當前資料庫中不存在具有給定名稱的資料表:

資料表'tbl_name'不存在
無法找到檔案:'tbl_name' (errno: 2)

在某些情況下,資料表或許存在,但未正確引用它:

·         由於MySQL使用目錄和檔案來保存資料庫和資料表,如果它們位於區分檔案名大小寫的檔案系統上,資料庫和資料表名也區分檔案大小寫。

·         即使對於不區分大小寫的檔案系統,如Windows,在查詢內對給定資料表的所有引用必須使用相同的大小寫。

可以使用SHOW TABLES檢查位於當前資料庫中的資料表。請參見13.5.4節,「SHOW語法」

A.2.16. 無法初始化字元編碼

如果存在字元編碼問題,可能會遇到下述錯誤:

MySQL連接失敗:無法初始化字元編碼charset_name

導致該錯誤的原因:

·         字元編碼為多字節字元編碼,但客戶端不支援該字元編碼。在該情況下,需要使用「--with-charset=charset_name」或「--with-extra-charsets=charset_name」選項運行configure以重新編譯客戶端。請參見2.8.2節,「典型配置選項

所有的標準MySQL二進制檔案均是採用「--with-extra-character-sets=complex」編譯的,能夠支援所有的多字節字元編碼。請參見5.10.1節,「數據和排序用字元編碼」

·         字元編碼是未編譯到mysqld中的簡單字元編碼,而且字元編碼定義檔案不在客戶端預期的位置。

在該情況下,需要採取下述方法之一解決問題:

1.    重新編譯客戶端,使之支援字元編碼。請參見2.8.2節,「典型配置選項

2.    為客戶端指定字元編碼定義檔案所在的目錄。對於很多客戶端,可使用「--character-sets-dir」選項完成該任務。

3.    將字元編碼定義檔案複製到客戶端預期的位置。

A.2.17. 檔案未找到

如果遇到「ERROR '...'未發現(errno: 23)」無法打開檔案:... (errno: 24)」,或來自MySQL的具有errno 23errno 24的其它錯誤,它資料表示未為MySQL伺服器分配足夠的檔案描述符。您可以使用perror實用工具來瞭解錯誤編號的含義:

shell> perror 23
錯誤代碼23:檔案資料表溢出
shell> perror 24
錯誤代碼24:打開檔案過多
shell> perror 11
錯誤代碼11:資源暫時不可用

這裡的問題是,mysqld正試圖同時打開過多的檔案。您可以通知mysqld不要一次打開過多檔案,或增加mysqld可用檔案描述符的數目。

要想通知mysqld將一次打開的檔案控制在較小的數目上,可降低table_cache系統變數的值(),從而減少資料表高速緩衝(預設值為64)。降低max_connections的值也能降低打開檔案的數目(預設值為100)。

要想更改mysqld可用的檔案描述符的數目,可在mysqld_safe上使用「--open-files-limit」選項或設置(自MySQL 3.23.30開始)open_files_limit系統變數。請參見5.3.3節,「伺服器系統變數」。設置這些值的最簡單方式是在選項檔案中增加1個選項。請參見4.3.2節,「使用選項檔案」。如果mysqld的版本較低,不支援設置打開檔案的數目,可編輯mysqld_safe指令。在指令中有1個註釋掉的行ulimit -n 256。您可以刪除#』字元取消對該行的註釋,更改數值256,以設置mysqld可用的檔案描述符數目。

「--open-files-limit」ulimit能夠增加檔案描述符的數目,但最高不能超過作業系統限制的數目。此外還有1個「硬」限制,僅當以根用戶身份啟動mysqld_safemysqld時才能覆蓋它(請記住,在該情況下,還需使用「--user」選項啟動伺服器,以便在啟動後不再以根用戶身份繼續運行)。如果需要增加作業系統限制的對各程序可用檔案描述符的數目,請參閱系統文檔。

註釋:如果運行tcsh shellulimit不工作!請求當前限制值時,tcsh還能通報不正確的值。在該情況下,應使用sh啟動mysqld_safe

A.3. 與安裝有關的事宜

A.3.1. 與MySQL客戶端庫的連結問題

當您連結到應用程式以使用MySQL客戶端庫時,可能會遇到以mysql_開始的未定義引用錯誤,如下所示:

/tmp/ccFKsdPa.o: 在函數`main':
/tmp/ccFKsdPa.o(.text+0xb): `mysql_init'的未定義引用。
/tmp/ccFKsdPa.o(.text+0x31): `mysql_real_connect'的未定義引用。
/tmp/ccFKsdPa.o(.text+0x57): `mysql_real_connect'的未定義引用。
/tmp/ccFKsdPa.o(.text+0x69): `mysql_error'的未定義引用。
/tmp/ccFKsdPa.o(.text+0x9a): `mysql_close'的未定義引用。

通過在連結命令後增加「-Ldir_path -lmysqlclient」選項,應能解決該問題,其中,dir_path代資料表客戶端庫所在目錄的路徑名。要想確定正確的目錄,可嘗試下述命令:

shell> mysql_config --libs

來自mysql_config的輸出可能會指明應在連結命令上指定的其他庫。

對於非壓縮或壓縮函數,如果遇到未定義引用錯誤,可在連結命令後新增-lz,並再次嘗試。

對於應在系統上存在的函數(如connect),如果遇到未定義引用錯誤,請檢查相關函數的手冊頁,以便確定應在連結命令上增加哪些庫。

對於系統上不存在的函數,可能會遇到未定義引用錯誤,如下所示:

mf_format.o(.text+0x201): `__lxstat'的未定義引用。

它通常意味著您的MySQL客戶端庫是在與您的系統不100%兼容的系統上編譯的。在該情況下,應下載最新的MySQL原始碼分發版,並自己編譯MySQL。請參見2.8節,「使用原始碼分發版安裝MySQL」

當您試圖執行MySQL程式時,可能會遇到運行時未定義引用錯誤。如果這類錯誤指明了以mysql_開始的符號,或指明未發現mysqlclient,這意味著您的系統無法找到共享的libmysqlclient.so庫。對其的更正方式是,通知系統在庫所在位置搜索共享庫。請使用與系統相適應的下述方法:

·         libmysqlclient.so所在目錄的路徑新增到LD_LIBRARY_PATH環境變數中。

·         libmysqlclient.so所在目錄的路徑新增到LD_LIBRARY環境變數中。

·         libmysqlclient.so拷貝到可被系統搜索的目錄下,如/lib,然後通過執行ldconfig更新共享庫訊息。

解決該問題的另一種方法是,以靜態方式將您的程式與「-static」選項連結在一起,或在連結代碼之前刪除動態MySQL庫。使用第2種方法之前,應確保沒有使用動態庫的其它程式。

A.3.2. 如何以普通用戶身份運行MySQL

Windows平台上,能夠使用普通用戶帳號以Windows服務方式運行伺服器。

Unix平台上,不是任何用戶都能啟動並運行MySQL伺服器mysqld。但是,處於安全方面的原因,應避免以Unix根用戶身份運行伺服器。要想更改mysqld,使之能以正常的無特權Unix用戶user_name身份運行,必須採取下述步驟:

如果伺服器正在運行,停止它(使用mysqladmin shutdown)。

更改資料庫目錄和檔案,允許user_name讀寫其中的檔案(可能需要以Unix根用戶身份完成這類設置):

shell> chown -R user_name /path/to/mysql/datadir

如果未這樣做,當以user_name身份運行時,伺服器無法訪問資料庫或資料表。

如果MySQL數據目錄下的目錄或檔案採用的是符號連結,還需跟蹤這些連結,並更改它們指向的目錄和檔案。chown –R可幫助您跟蹤符號連結。

user_name身份啟動伺服器。如果您正在使用MySQL 3.22或更高版本,另一種可選方式是,以Unix根用戶身份啟動mysqld,並使用--user=user_name選項。mysqld啟動,然後在接受任何連接前,切換至Unix用戶user_name並以該用戶身份運行。

要想在系統啟動時自動以給定的用戶身份啟動伺服器,可在伺服器數據目錄下的/etc/my.cnf選項檔案或my.cnf選項檔案的[mysqld]組中,通過增加用戶選項來指定帳號。。例如:

[mysqld]
user=user_name

如果您的Unix機器本身並不安全,應在授權資料表中為MySQL根帳號指定密碼。如不然,任何在該機器上具有登錄帳號的用戶都能使用「--user=root」選項運行mysql客戶端,並執行任何操作。在任何情況下均應為MySQL帳號指定密碼,這是個好主意,尤其是在伺服器主機上存在其他登錄帳號時,更是如此。請參見2.9節,「安裝後的設置和測試」

A.3.3. 與檔案授權有關的問題

如果遇到與檔案授權有關的問題,可能數啟動mysqldUMASK環境變數設置得不正確。例如,當您建立資料表時,MySQL可能會發出下述錯誤消息:

ERROR: 無法找到檔案:'path/with/filename.frm' (Errcode: 13)

UMASK的預設值是0660。通過下述方式啟動mysqld_safe,可改變該情況:

shell> UMASK=384  # = 600 in octal
shell> export UMASK
shell> mysqld_safe &

在預設情況下,MySQL0700的授權建立資料庫和RAID目錄。您可以通過設置UMASK_DIR變數更改該行為。如果您設置了它的值,將使用組合的UMASKUMASK_DIR值建立新目錄。例如,如果您打算為所有新的目錄授予組訪問權限,可:

shell> UMASK_DIR=504  # = 770 in octal
shell> export UMASK_DIR
shell> mysqld_safe &

MySQL 3.23.25和更高版本中,如果是以0開始的,MySQL將認為UMASKUMASK_DIR的值均採用八進制形式。

請參見附錄F:環境變數

A.4. 與管理有關的事宜

A.4.1. 如何復位根用戶密碼

如果您從未為MySQL設置根用戶密碼,伺服器在以根用戶身份進行連接時不需要密碼。但是,建議您為每個帳號設置密碼。請參見5.6.1節,「通用安全指南」

如果您以前設置了根用戶密碼,但卻忘記了該密碼,可設置新的密碼。下述步驟是針對Windows平台的。在本節後面的內容中,介紹了針對Unix平台的步驟。

Windows平台下,該步驟是:

以系統管理員身份登錄到系統。

如果MySQL伺服器正在運行,停止它。對於作為Windows服務運行的伺服器,進入服務管理器:

開始菜單->控制面板->管理工具->服務

然後在列資料表中找出MySQL伺服器,並停止它。

如果伺服器不是作為服務而運行的,可能需要使用任務管理器來強制停止它。

建立1個文本檔案,並將下述命令置於單一行中:

SET PASSWORD FOR 'root'@'localhost' = PASSWORD('MyNewPassword');

用任意名稱保存該檔案。在本例中,該檔案為C:\mysql-init.txt

打開控制台窗口,進入DOS命令提示:

開始菜單->運行-> cmd

假定您已將MySQL安裝到C:\mysql。如果您將MySQL安裝到了另一位置,請對下述命令進行相應的調整。

DOS命令提示符下,執行命令:

C:\> C:\mysql\bin\mysqld-nt --init-file=C:\mysql-init.txt

在伺服器啟動時,執行由「--init-file」選項命名的檔案的內容,更改根用戶密碼。當伺服器成功啟動後,應刪除C:\mysql-init.txt

如果您使用MySQL安裝嚮導安裝了MySQL,或許需要指定「--defaults-file」選項:

C:\> C:\Program Files\MySQL\MySQL Server 5.1\bin\mysqld-nt.exe
         --defaults-file="C:\Program Files\MySQL\MySQL Server 5.1\my.ini"
         --init-file=C:\mysql-init.txt

使用服務管理器,可找到恰當的「--defaults-file」設置:

開始菜單->控制面板->管理工具->服務

在列資料表中找出MySQL服務,右擊,並選擇「屬性」選項。在可執行字段的Path(路徑)中包含「--defaults-file」設置。

停止MySQL伺服器,然後在正常模式下重啟它。如果以服務方式運行伺服器,應從Windows服務窗口啟動它。如果以手動方式啟動了伺服器,能夠像正常情形下一樣使用命令。

應能使用新密碼進行連接。

Unix環境下,重置根用戶密碼的步驟如下:

Unix根用戶身份、或以運行mysqld伺服器的相同身份登錄到系統。

找到包含伺服器程序ID.pid檔案。該檔案的準確位置和名稱取決於您的分發版、主機名和配置。常見位置是/var/lib/mysql//var/run/mysqld//usr/local/mysql/data/一般情況下,檔案名的延伸名為.pid,並以mysqld或系統的主機名開始。

在下述命令中使用.pid檔案的路徑名,向mysqld程序發出正常的kill(而不是kill -9),可停止MySQL伺服器:

shell> kill `cat /mysql-data-directory/host_name.pid`

注意,cat命令使用符號「`」而不是「』」:這會使cat的輸出代入到kill命令中。

建立文本檔案,並將下述命令放在檔案內的1行上:

SET PASSWORD FOR 'root'@'localhost' = PASSWORD('MyNewPassword');

用任意名稱保存檔案。對於本例,檔案為~/mysql-init

用特殊的「--init-file=~/mysql-init」選項重啟MySQL伺服器:

shell> mysqld_safe --init-file=~/mysql-init &

檔案init-file的內容在伺服器啟動時執行,更改根用戶密碼。伺服器成功啟動後,應刪除~/mysql-init

應能使用新密碼進行連接。

作為可選方式,在任何平台上,可使用mysql客戶端設置新密碼(但該方法不夠安全):

停止mysqld,並用「--skip-grant-tables --user=root」選項重啟它Windows用戶可省略--user=root部分)。

使用下述命令連接到mysqld伺服器:

shell> mysql -u root

mysql客戶端發出下述語句:

mysql> UPDATE mysql.user SET Password=PASSWORD('newpwd')
    ->                   WHERE User='root';
mysql> FLUSH PRIVILEGES;

用打算使用的實際根用戶密碼替換「newpwd」。

應能使用新密碼進行連接。

A.4.2. 如果MySQL依然崩潰,應作些什麼

正式發佈之前,每個MySQL版本均在很多平台上進行了測試。這不資料表示MySQL中不存在問題,但是,如果存在問題,它們應很少,而且很難發現。如果您遇到問題,如果您嘗試找出導致系統崩潰的準確原因,這始終很有幫助,這是因為,如果這樣的話,快速解決問題的機會很大。

首先,應嘗試找出問題是否與mysqld伺服器有關,或是否與客戶端有關。通過執行mysqladmin version,可檢查mysqld伺服器運行了多長時間。如果mysqld宕機並重啟,應查看伺服器的錯誤日誌以找出原因。請參見5.11.1節,「錯誤日誌」

在某些系統上,在錯誤日誌中,可發現mysqld宕機的堆棧跟蹤,可使用resolve_stack_dump程式解決它。請參見E.1.4節,「使用堆棧跟蹤」。注意,錯誤日誌中的變數值並非始終是100%正確的。

很多伺服器崩潰是因損壞的數據檔案或索引檔案而導致的,每次執行完SQL語句之後並在向客戶端通告結果之前,MySQL將使用write()系統使用更新磁盤上的檔案(如果您使用了「--delay-key-write」選項,情況並非如此,此時將寫入數據檔案而不是索引檔案)。這意味著,即使mysqld崩潰,數據檔案的內容也是安全的,這是因為作業系統能保證將未刷新的數據寫入磁盤。使用「--flush」選項啟動mysqld,這樣,每次執行完SQL語句後,可強制MySQL將所有內容寫入磁盤。

前述介紹表明,在正常情況下不會出現損壞的資料表,除非出現了下述情況之一:

在更新過程中,MySQL伺服器或伺服器主機被停止。

您發現了mysqld中存在的1個問題,該問題導致mysqld在更新中途中止。

mysqld操作的同時,某些外部程式正在操控數據檔案或索引檔案,未恰當鎖定資料表。

您正使用系統上的相同數據目錄運行很多mysqld伺服器,該系統不支援良好的檔案系統鎖定(通常是由lockd鎖定管理器負責的),或使用「--skip-external-locking」選項運行了多個伺服器。

崩潰的數據檔案或索引檔案,其中包含導致mysqld混亂的損壞很嚴重的數據。

在數據儲存節點發現問題。這種可能性不大,但至少是可能的。在該情況下,可在修復的資料表副本上,通過使用ALTER TABLE嘗試將資料表類型更改為另一種儲存引擎。

由於很難得知為什麼某事會出現崩潰,首先請檢查用於其他方面的事項是否崩潰。請嘗試採取下述措施:

mysqladmin shutdown停止mysqld伺服器,從數據目錄運行myisamchk --silent --force */*.MYI,檢查所有的MyISAM資料表,並重啟mysqld。這樣,就能確保從乾淨的狀態運行伺服器。請參見第5章:資料庫管理

使用「--log」選項啟動mysqld,並根據寫入日誌的訊息確定是否某些特殊的查詢殺死了伺服器。約95%的問題與特定的查詢有關。正常情況下,這是伺服器重啟前日誌檔案中最夠數個查詢中的1個。請參見5.11.2節,「通用查詢日誌」。如果能夠用特殊查詢重複殺死MySQL,即使在發出查詢前檢查了所有資料表的情況下也同樣,那麼您就應能確定問題,並應提交關於該問題的問題報告。請參見1.7.1.3節,「如何通報問題和問題」

嘗試提供一個測試範例,我們應能利用該範例重複問題。請參見E.1.6節,「如果出現資料表崩潰,請生成測試案例」

請在mysql-test目錄下並根據MySQL基準進行測試。請參見27.1.2節,「MySQL測試套件」。它們能相當良好地測試MySQL。您也可以為基準測試增加代碼,以模擬您的應用程式。基準測試可在原始碼分發版的sql-bench目錄下找到,對於二進制分發版,可在MySQL安裝目錄下的sql-bench目錄下找到。

嘗試使用fork_big.pl指令(它位於原始碼分發版的測試目錄下)。

如果您將MySQL配置為調試模式,如果某事出錯,可更為容易地搜集關於可能錯誤的訊息。如果將MySQL配置為調試模式,可生成1個安全的內存分配程式,可使用它發現某些錯誤。此外,它還提供了很多輸出,這類輸出與出現的問題相關。在configure上使用「--with-debug」或「--with-debug=full」選項重新配置MySQL,然後再編譯它。請參見E.1節,「調試MySQL伺服器」

確保為您的作業系統應用了最新的補丁。

mysqld使用「--skip-external-locking」選項。在某些系統上,lockd鎖定管理器不能正確工作,--skip-external-locking」選項通知mysqld不使用外部鎖定。(這意味著,您不能在相同的數據目錄上運行2mysqld伺服器,如果使用myisamchk,必須謹慎。然而,嘗試將該選項用作測試也是有益的)。

mysqld看上去正在運行但並未響應時,是否運行了mysqladmin -u root processlist?某些時候,即使您認為mysqld處於閒置狀態時,實際情況並非如此。問題可能是因為所有連接均已使用,或存在某些內部鎖定問題。即使在該情況下,mysqladmin -u root processlist通常能夠進行連接,並能提供關於當前連接數以及其狀態的有用訊息。

在運行其他查詢的同時,在單獨的窗口中運行命令mysqladmin -i 5 statusmysqladmin -i 5 -r status,以生成統計訊息。

嘗試採用下述方法:

gdb(或另一個調試器)啟動mysqld。請參見E.1.3節,「在gdb環境下調試mysqld

運行測試指令。

3個較低層面上輸出backtrace(向後跟蹤)和局部變數。在gdb中,當mysqldgdb內崩潰時,可使用下述命令完成該任務:

backtrace
info local
up
info local
up
info local

使用gdb,您還能檢查與info線程共存的線程,並切換至特定的線程N,其中,N是線程ID

嘗試用Perl指令模擬您的應用程式,強制MySQL崩潰或行為異常。

發送正常的問題報告。請參見1.7.1.3節,「如何通報問題和問題」。應比通常的報告更詳細。由於MySQL是為很多人提供服務的,它可能因僅存在於您的計算機上的某事崩潰(例如,與您的特定系統庫有關的錯誤)。

如果您遇到與包含動態長度行的資料表有關的問題,而且您僅使用VARCHAR(而不是BLOBTEXT列),可嘗試用ALTER TABLE將所有VARCHAR列更改為CHAR列。這樣,就會強制MySQL使用固定大小的行。固定大小的行佔用的空間略多,但對損壞的容忍度更高。

目前的動態行代碼在MySQL AB已使用多年,很少遇到問題,但從本質上看,動態長度行更傾向於出現錯誤,因此,不妨嘗試採用該策略以查看它是否有幫助,這不失為一個好主意。

診斷問題時不要將您的伺服器硬件排除在外。有問題的硬件能夠導致數據損壞。對硬件進行故障診斷與排除操作時,尤其應注意RAM和硬盤驅動器。

A.4.3. MySQL處理磁盤滿的方式

在本節中,介紹了MySQL響應磁盤滿錯誤的方式(如「設備上無剩餘空間」),以及響應超配額錯誤的方式(如「寫入失敗」或「達到了用戶屏蔽限制」)。

本節介紹的內容與寫入MyISAM資料表有關。它也適用於寫入二進制日誌檔案和二進制索引檔案,但對row」和「record」的應用應被視為「event」。

出現磁盤滿狀況時,MySQL將:

每分鐘檢查一次,查看是否有足夠空間寫入當前行。如果有足夠空間,將繼續,就像什麼也未發生一樣。

10分鐘將1個條目寫入日誌檔案,提醒磁盤滿狀況。

為了減輕問題,可採取下述措施:

要想繼續,僅需有足夠的磁盤空間以插入所有記錄。

要想放棄線程,必須使用mysqladmin kill。下次檢查磁盤時將放棄線程(1分鐘)。

其他線程可能會正在等待導致磁盤滿狀況的資料表。如果有數個「已鎖定」的線程,殺死正在磁盤滿狀況下等待的某一線程,以便允許其他線程繼續。

對前述行為的例外是,當您使用REPAIR TABLEOPTIMIZE TABLE時,或當索引是在LOAD DATA INFILEALTER TABLE語句後、在批操作中建立的。所有這些語句能建立大的臨時檔案,如果保留這些檔案,會導致系統其他部分出現大問題。如果在MySQL執行這類操作的同時磁盤已滿,它將刪除大的臨時檔案,並將資料表標注為崩潰。但對於ALTER TABLE例外,舊資料表保持不變。

A.4.4. MySQL將臨時檔案儲存在哪裡

MySQL使用環境變數TMPDIR的值作為保存臨時檔案的目錄的路徑名。如果未設置TMPDIRMySQL將使用系統的預設值,通常為/tmp/var/tmp/usr/tmp。如果包含臨時檔案目錄的檔案系統過小,可對mysqld使用「—tmpdir」選項,在具有足夠空間的檔案系統內指定1個目錄。

MySQL 5.1中,「—tmpdir」選項可被設置為數個路徑的列資料表,以循環方式使用。在Unix平台上,路徑用冒號字元「:」隔開,在WindowsNetWareOS/2平台上,路徑用分號字元「;」隔開。注意,為了有效分佈負載,這些路徑應位於不同的物理磁盤上,而不是位於相同磁盤的不同分區中。

如果MySQL伺服器正作為複製從伺服器使用,不應將「--tmpdir」設置為指向基於內存的檔案系統的目錄,或當伺服器主機重啟時將清空的目錄。對於複製從伺服器,需要在機器重啟時仍保留一些臨時檔案,以便能夠複製臨時資料表或執行LOAD DATA INFILE操作。如果在伺服器重啟時丟失了臨時檔案目錄下的檔案,複製將失敗。

MySQL會以隱含方式建立所有的臨時檔案。這樣,就能確保中止mysqld時會刪除所有臨時檔案。使用隱含檔案的缺點在於,在臨時檔案目錄所在的位置中,看不到佔用了檔案系統的大臨時檔案。

進行排序時(ORDER BYGROUP BY),MySQL通常會使用1個或多個臨時檔案。所需的最大磁盤空間由下述資料表達式決定:

(length of what is sorted + sizeof(row pointer))
* number of matched rows
* 2

row pointer」(行指針)的大小通常是4字節,但在以後,對於大的資料表,該值可能會增加。

對於某些SELECT查詢,MySQL還會建立臨時SQL資料表。它們不是隱含資料表,並具有SQL_*形式的名稱。

ALTER TABLE會在與原始資料表目錄相同的目錄下建立臨時資料表。

A.4.5. 如何保護或更改MySQL套接字檔案/tmp/mysql.sock

對於伺服器用來與本地客戶端進行通信的Unix套接字檔案,其預設位置是/tmp/mysql.sock。這有可能導致問題,原因在於,在某些版本的Unix上,任何人都能刪除/tmp目錄下的檔案。

在大多數Unix版本中,可對/tmp目錄進行保護,使得檔案只能被其所有這或超級用戶(根用戶)刪除。為此,以根用戶身份登錄,並使用下述命令在/tmp目錄上設置粘著位:

shell> chmod +t /tmp

通過執行ls -ld /tmp,可檢查是否設置了粘著位。如果最後一個授權字元是「t」,表明設置了粘著位。

另一種方法是改變伺服器建立Unix套接字檔案的位置。如果進行了這類操作,還應讓客戶端程式知道檔案的位置。能夠以多種不同方式指定檔案位置:

在全局或局部選項檔案中指定路徑。例如,將下述行置於檔案/etc/my.cnf中:

[mysqld]
socket=/path/to/socket
 
[client]
socket=/path/to/socket

請參見4.3.2節,「使用選項檔案」

在運行客戶端程式時,在命令行上為mysqld_safe指定--socket」選項。

MYSQL_UNIX_PORT環境變數設置為Unix套接字檔案的路徑。

重新從原始碼編譯MySQL,以使用不同的預設Unix套接字檔案位置。運行configure時,用「--with-unix-socket-path」選項定義檔案路徑。請參見2.8.2節,「典型配置選項

用下述命令連接伺服器,能夠測試新的套接字位置是否工作:

shell> mysqladmin --socket=/path/to/socket version

A.4.6. 時區問題

如果遇到與SELECT NOW()有關的問題,它返回GMT值而不是當地時間,就應通知伺服器您的當前失去。如果UNIX_TIMESTAMP()返回錯誤值,上述方式同樣適用。應為伺服器所運行的環境進行這類設置,例如,在mysqld_safemysql.server中。請參見附錄F:環境變數

也可以對mysqld_safe使用「--timezone=timezone_name」選項,為伺服器設置失去。也可以在啟動mysqld之前,通過設置TZ環境變數完成該設置。

--timezone」或TZ的允許值與系統有關。關於可接受的值,請參見作業系統文檔。

A.5. 與查詢有關的事宜

A.5.1. 搜索中的大小寫敏感性

在預設情況下,MySQL搜索不區分大小寫(但某些字元編碼始終區分大小寫,如czech)。這意味著,如果您使用col_name LIKE 'a%'進行搜索,您將獲得以Aa開始的所有列。如果打算使搜索區分大小寫,請確保操作數之一具有區分大小寫的或二進制校對。例如,如果您正在比較均適用latin1字元編碼的列和字串,可使用COLLATE操作符,使1個操作數具有latin1_general_cslatin1_bin校對特性。例如:

col_name COLLATE latin1_general_cs LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_general_cs
col_name COLLATE latin1_bin LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_bin

如果希望總是以區分大小寫的方式處理列,可使用區分大小寫的或二進制校對聲明它。請參見13.1.5節,「CREATE TABLE語法」

簡單的比較操作(>=, >, =, <, <=, 排序和分組)基於每個字元的「排序值」。具有相同排序值的字元(如『E, e,和『Ac』)將被當作相同的寫字元。

A.5.2. 使用DATE列方面的問題

DATE值的格式是'YYYY-MM-DD'按照標準的SQL,不允許其他格式。在UPDATE資料表達式以及SELECT語句的WHERE子句中應使用該格式。例如:

mysql> SELECT * FROM tbl_name WHERE date >= '2003-05-05';

為了方便,如果日期是在數值環境下使用的,MySQL會自動將日期轉換為數值(反之亦然)。它還具有相當的智能,在更新時或在與TIMESTAMPDATEDATETIME列比較日期的WHERE子句中,允許寬鬆的字串形式(寬鬆形式資料表示,任何標點字元均能用作各部分之間的分隔符。例如,'2004-08-15''2004#08#15'是等同的)。MySQL還能轉換不含任何分隔符的字串(如'20040815'),前體是它必須是有意義的日期。

使用<<==>=>、或BETWEEN操作符將DATETIMEDATETIMETIMESTAMP與常量字串進行比較時,MySQL通常會將字串轉換為內部長整數,以便進行快速比較(以及略為「寬鬆」的字串檢查)。但是,該轉換具有下述例外:

比較兩列時

DATETIMEDATETIMETIMESTAMP列與資料表達式進行比較時

使用其他比較方法時,如INSTRCMP()

對於這些例外情形,會將對像轉換為字串並執行字串比較,採用該方式進行比較。

為了保持安全,假定按字串比較字串,如果您打算比較臨時值和字串,將使用恰當的字串函數。

對於特殊日期'0000-00-00',能夠以'0000-00-00'形式保存和檢索。在MyODBC中使用'0000-00-00'日期時,對於MyODBC 2.50.12或更高版本,該日期將被自動轉換為NULL,這是因為ODBC不能處理這類日期。

由於MySQL能夠執行前面所介紹的轉換,下述語句均能正常工作:

mysql> INSERT INTO tbl_name (idate) VALUES (19970505);
mysql> INSERT INTO tbl_name (idate) VALUES ('19970505');
mysql> INSERT INTO tbl_name (idate) VALUES ('97-05-05');
mysql> INSERT INTO tbl_name (idate) VALUES ('1997.05.05');
mysql> INSERT INTO tbl_name (idate) VALUES ('1997 05 05');
mysql> INSERT INTO tbl_name (idate) VALUES ('0000-00-00');
 
mysql> SELECT idate FROM tbl_name WHERE idate >= '1997-05-05';
mysql> SELECT idate FROM tbl_name WHERE idate >= 19970505;
mysql> SELECT MOD(idate,100) FROM tbl_name WHERE idate >= 19970505;
mysql> SELECT idate FROM tbl_name WHERE idate >= '19970505';

但是,下述語句不能正常工作:

mysql> SELECT idate FROM tbl_name WHERE STRCMP(idate,'20030505')=0;

STRCMP()是一種字串函數,它能將idate轉換為'YYYY-MM-DD'格式的字串,並執行字串比較。它不能將'20030505'轉換為日期'2003-05-05'並進行日期比較。

如果您正在使用ALLOW_INVALID_DATES SQL模式,MySQL允許以僅執行給定的有限檢查方式保存日期:MySQL僅保證天位於131的範圍內,月位於112的範圍內。

這樣就使得MySQL很適合於Web應用程式,其中,您能獲得三個不同字段中的年、月、日值,也能準確保存用戶插入的值(無日期驗證)。

如果未使用NO_ZERO_IN_DATE SQL模式,「天」和「月」部分可能為0。如果您打算將生日保存在DATE列而且僅知道部分日期,它十分方便。

如果未使用NO_ZERO_DATE SQL模式,MySQL也允許您將'0000-00-00'保存為「偽日期」。在某些情況下,它比使用NULL值更方便。

如果無法將日期轉換為任何合理值,「0」將保存在DATE列中,並被檢索為'0000-00-00'。這是兼顧速度和便利性的事宜。我們認為,資料庫伺服器的職責是檢索與您保存的日期相同的日期(即使在任何情況下,數據在邏輯上不正確也同樣)。我們認為,對日期的檢查應由應用程式而不是伺服器負責。

如果您希望MySQL檢查所有日期並僅接受合法日期(除非由IGNORE覆蓋),應將sql_mode設置為"NO_ZERO_IN_DATE,NO_ZERO_DATE"

A.5.3. 與NULL值有關的問題

對於SQL的新手,NULL值的概念常常會造成混淆,他們常認為NULL是與空字串''相同的事。情況並非如此。例如,下述語句是完全不同的:

mysql> INSERT INTO my_table (phone) VALUES (NULL);
mysql> INSERT INTO my_table (phone) VALUES ('');

這兩條語句均會將值插入phone(電話)列,但第1條語句插入的是NULL值,第2條語句插入的是空字串。第1種情況的含義可被解釋為「電話號碼未知」,而第2種情況的含義可被解釋為「該人員沒有電話,因此沒有電話號碼」。

為了進行NULL處理,可使用IS NULLIS NOT NULL操作符以及IFNULL()函數。

SQL中,NULL與任何其它值的比較(即使是NULL)永遠不會為「真」。包含NULL的資料表達式總是會導出NULL值,除非在關於操作符的文檔中以及資料表達式的函數中作了其他規定。下述示範中的所有列均返回NULL

mysql> SELECT NULL, 1+NULL, CONCAT('Invisible',NULL);

如果打算搜索列值為NULL的列,不能使用expr = NULL測試。下述語句不返回任何行,這是因為,對於任何資料表達式,expr = NULL永遠不為

mysql> SELECT * FROM my_table WHERE phone = NULL;

要想搜尋NULL值,必須使用IS NULL測試。在下面的語句中,介紹了搜尋NULL電話號碼和空電話號碼的方式:

mysql> SELECT * FROM my_table WHERE phone IS NULL;
mysql> SELECT * FROM my_table WHERE phone = '';

更多訊息和示範,請參見3.3.4.6節,「使用NULL值」

如果您正在使用MyISAMInnoDBBDB、或MEMORY儲存引擎,能夠在可能具有NULL值的列上增加1條索引。如不然,必須聲明索引列為NOT NULL,而且不能將NULL插入到列中。

LOAD DATA INFILE讀取數據時,對於空的或丟失的列,將用''更新它們。如果希望在列中具有NULL值,應在數據檔案中使用\N。在某些情況下,也可以使用文字性單詞「NULL」。請參見13.2.5 LOAD DATA INFILE語法」

使用DISTINCTGROUP BYORDER BY時,所有NULL值將被視為等同的。

使用ORDER BY時,首先將顯示NULL值,如果指定了DESC按降序排列,NULL值將最後顯示。

對於聚合(累計)函數,如COUNT()MIN()SUM(),將忽略NULL值。對此的例外是COUNT(*),它將計數行而不是單獨的列值。例如,下述語句產生兩個計數。首先計數資料表中的行數,其次計數age列中的非NULL值數目:

mysql> SELECT COUNT(*), COUNT(age) FROM person;

對於某些列類型,MySQL將對NULL值進行特殊處理。如果將NULL插入TIMESTAMP列,將插入當前日期和時間。如果將NULL插入具有AUTO_INCREMENT屬性的整數列,將插入序列中的下一個編號。

A.5.4. 與列別名有關的問題

可以使用別名來引用GROUP BYORDER BYHAVING子句中的列。別名也能用於為列提供更好的名稱:
SELECT SQRT(a*b) AS root FROM tbl_name GROUP BY root HAVING root > 0;
SELECT id, COUNT(*) AS cnt FROM tbl_name GROUP BY id HAVING cnt > 0;
SELECT id AS 'Customer identity' FROM tbl_name;

標準SQL不允許在WHERE子句中已用列別名。這是因為,執行WHERE代碼時,可能尚未確定列值。例如,下述查詢是非法的:

SELECT id, COUNT(*) AS cnt FROM tbl_name WHERE cnt > 0 GROUP BY id;

執行WHERE語句以確定哪些行應被包含在GROUP BY部分中,而HAVING用於確定應使用結果集中的哪些行。

A.5.5. 非事務資料表回滾失敗

執行ROLLBACK(回滾)時,如果收到下述消息,資料表示事務中使用的1個或多個資料表不支援事務:

警告:某些更改的非事務性資料表不能被回滾。

這些非事務性資料表不受ROLLBACK語句的影響。

如果在事務中意外地混合了事務性資料表和非事務性資料表,導致該消息的最可能原因是,您認為本應是事務性的資料表實際上不是。如您試圖使用mysqld伺服器不支援的事務性儲存引擎(或用啟動選項禁止了它)建立資料表,就可能出現該情況。如果mysqld不支援儲存引擎,它將以MyISAM資料表建立資料表,這是非事務性資料表。

可使用下述語句之一檢查資料表的標類型:

SHOW TABLE STATUS LIKE 'tbl_name';
SHOW CREATE TABLE tbl_name;

請參見13.5.4.18節,「SHOW TABLE STATUS語法以及13.5.4.5節,「SHOW CREATE TABLE語法」

使用下述語句,可檢查mysqld伺服器支援的儲存引擎:

SHOW ENGINES;

也可以使用下述語句,檢查與您感興趣的儲存引擎有關的變數值:

SHOW VARIABLES LIKE 'have_%';

例如,要想確定InnoDB儲存引擎是否可用,可檢查have_innodb變數的值。

請參見13.5.4.8節,「SHOW ENGINES語法」13.5.4.21節,「SHOW VARIABLES語法」

A.5.6. 從相關資料表刪除行

如果針對related_tableDELETE語句的總長度超過1MB(系統變數max_allowed_packet的預設值),應將其分為較小的部分,並執行多個DELETE語句。如果related_column是索引列,為每條語句指定1001000related_column值,或許能獲得更快的DELETE速度。如果related_column不是索引列,速度與IN子句中的參量數目無關。

A.5.7. 解決與不匹配行有關的問題

如果有使用了很多資料表的複雜查詢,但未返回任何行,應採用下述步驟找出什麼出錯:

EXPLAIN測試查詢,以檢查是否發現某事顯然出錯。請參見7.2.1節,「EXPLAIN語法(獲取關於SELECT的訊息)

僅選擇在WHERE子句中使用的列。

從查詢中1次刪除1個資料表,直至返回了某些行為止。如果資料表很大,較好的主意是在查詢中使用LIMIT 10

對於具有與上次從查詢中刪除的資料表匹配的行的列,發出SELECT查詢。

如果將FLOATDOUBLE列與具有數值類型的數值進行比較,不能使用等式(=)比較。在大多數計算機語言中,該問題很常見,這是因為,並非所有的浮點值均能以準確的精度保存。在某些情況下,將FLOAT更改為