目錄
當您遇到問題時,首先要做的是找出導致問題的程式和設備部件:
· 如果遇到下述徵兆之一,或許是因為硬件問題(如內存、主板、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日誌檔案」。
· 如果您不認為存在硬件問題,應嘗試找出導致問題的原因。請使用top、ps、任務管理器或類似程式,以檢查哪個程式佔用了所有CPU時間或鎖定了機器。
· 使用top、df或類似程式檢查是否內存不夠、磁盤空間不足、檔案描述符缺乏、或其他關鍵資源缺少。
· 如果問題是失去控制的程序,應嘗試殺死它。如果殺不死程序,或許是因為作業系統中存在問題。
如果在檢查了所有其他可能性之後,並得出結論問題是由MySQL伺服器或MySQL客戶端導致的,應建立提供給我方的郵件列資料表或支援團隊的問題報告。在問題報告中,請詳細描述系統的行為,以及您認為發生了什麼情況。+3.
還應闡明為什麼您認為是MySQL導致了問題。請考慮本章介紹的所有情況。準確闡明當您檢查系統時問題是如何出現的。對於程式和日誌檔案的任何輸出和錯誤消息,請使用「複製和粘貼」方法。
盡量詳細描述不工作的程式,以及您所見到的所有徵兆。我們過去收到過很多僅說明「系統不工作」的問題報告。這不會為我們提供有助於解決問題的訊息。
如果程式失敗,瞭解下述訊息總是有用的:
· 有嫌疑的程式是否出現了分段故障(是否轉儲內核)?
· 程式是否佔用了所有可用的CPU時間?用top.進行檢查。讓程式運行一段時間,或許能簡單地評估某些事是否是計算密集性的。
· 如果問題是因mysqld伺服器導致的,使用mysqladmin -u root ping或mysqladmin -u root processlist是否能獲得伺服器的響應?
· 當您嘗試連接到MySQL伺服器(例如,mysql)時,客戶端程式給出的訊息是什麼?客戶端是否堵塞?是否獲得了來自程式的任何輸出?
發送問題報告時,請遵循1.7.1.2節,「請教問題或通報問題」中給出的說明。
本節列出了用戶運行MySQL伺服器時常會遇到的一些錯誤。儘管問題是在您嘗試運行客戶端時出現的,但對很多問題的解決方案來說,需要更改MySQL伺服器的配置。
Unix平台上的MySQL客戶端能夠以兩種不同的方式連接到mysqld伺服器:通過檔案系統中的檔案(預設為/tmp/mysql.sock)使用Unix套接字進行連接,或通過端口號使用TCP/IP進行連接。Unix套接字檔案的連接速度比TCP/IP快,但僅能在與相同計算機上的伺服器相連時使用。如果未指定指定主機名或指定了特殊的主機名localhost,將使用Unix套接字。
如果MySQL伺服器運行在Windows 9x或Me上,僅能通過TCP/IP進行連接。如伺服器運行在Windows NT、2000、XP或2003上,而且使用--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線程(例如,使用kill或mysql_zap指令)。請參見A.4.2節,「如果MySQL依然崩潰,應作些什麼」。
9. 伺服器或客戶端程式不具有訪問包含Unix套接字檔案的目錄或套接字檔案本身的恰當權限。在該情況下,必須更改目錄或套接字檔案的訪問權限,以便伺服器或客戶端程式能夠訪問它們,或用–socket選項重啟mysqld,在該選項中指定伺服器能建立、而且客戶端可訪問的目錄下的套接字檔案名。
如果遇到錯誤消息「無法連接到some_host上的MySQL伺服器」,可嘗試採取下述步驟以找出問題所在:
· 執行「telnet some_host 3306」並按兩次回車鍵,檢查伺服器是否運行在該主機上(3306是預設的MySQL端口號。如果您的伺服器正在監聽不同的端口,請更改該值)。如果有1個MySQL伺服器正在運行並監聽該端口,您應收到包含伺服器版本號的回應。如果遇到錯誤,如「telnet:無法連接到遠程主機:拒絕連接」,資料表示在該定端口上沒有運行的伺服器。
· 如果伺服器正運行在本地主機上,請使用Unix套接字檔案,並使用mysqladmin -h localhost variables進行連接。驗證伺服器監聽的TCP/IP端口號(它是port變數的值)。
· 確保您的mysqld伺服器未用--skip-networking選項啟動。如果使用了該選項,將無法使用TCP/IP連接到它。
· 檢查並確認不存在屏蔽了對MySQL訪問的防火牆。需要配置諸如ZoneAlarm和Windows XP個人防火牆等應用程式,以允許對MySQL伺服器的外部訪問。
預設情況下,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
它用於設置為任何用戶提供的臨時端口數。有效範圍介於5000和65534之間(十進制)。預設值為0x1388(5000,十進制)。
· 在「編輯」菜單上點擊「新增值」,然後增加下述註冊值:
· Value Name: TcpTimedWaitDelay
· Data Type: REG_DWORD
· Value: 30
它用於設置關閉之前將TCP端口連接保持在TIME_WAIT狀態的秒數。有效範圍介於0秒和300秒之間。預設值為0x78(120秒)。
· 退出註冊資料表編輯器。
· 重新引導機器。
註釋:撤銷上述設置十分簡單,就像刪除您建立的註冊資料表一樣。
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');
也可以使用UPDATE和FLUSH 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;
對於查詢顯示的每個帳號記錄,請使用Host和User值,並使用OLD_PASSWORD()函數以及SET PASSWORD或UPDATE之一指定密碼,如前面所介紹的那樣。
註釋:在早期的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中的密碼哈希處理」。
shell> mysql -u user_name -p
Enter password:
在某些系統上,當您在選項檔案或命令行上指定時,您可能會發現密碼能夠工作,但是當您在「Enter password:」提示下以交互方式輸入密碼時,您可能會發現輸入的密碼不工作。當系統所提供的用於讀取密碼的庫將密碼值限定在少數字元時(典型情況下為8個),就會出現該問題。這是與系統庫有關的問題,與MySQL無關。要想處理該問題,可將MySQL密碼更改為由8個字元或更少字元構成的值,或將密碼置於選項檔案中。
如果遇到下述錯誤,資料表示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變數的值不會有任何好處。
當您試圖連接到mysqld伺服器時遇到「過多連接」錯誤,這資料表示所有可用的連接均已被其他客戶端使用。
允許的連接數由max_connections系統變數控制。預設值為100。如果需要支援更多的連接,應使用該變數的較大值重啟mysqld。
mysqld實際上允許max_connections+1個客戶端進行連接。額外的連接保留給具有SUPER權限的帳號。通過為系統管理員而不是普通用戶授予SUPER權限(普通用戶不應具有該權限),系統管理員能夠連接到伺服器,並使用SHOW PROCESSLIST來診斷問題,即使已連接的無特權客戶端數已達到最大值也同樣。請參見13.5.4.16節,「SHOW PROCESSLIST語法」。
MySQL能支援的最大連接數取決於給定平台上線程庫的質量。Linux或Solaris應能支援500-1000個並發連接,具體情況取決於RAM容量,以及客戶端正在作什麼。MySQL AB提供的靜態Linux庫能支援高達4000個連接。
如果使用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函數來檢索結果集,這類函數能夠降低客戶端上的負載(但會加重伺服器上的負載)。
在本節中,還介紹了出現查詢錯誤期間,與丟失了伺服器連接有關的事宜。
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結構中的再連接標誌等於1,MySQL也不會執行自動再連接並再次發出查詢,這是因為它不知道伺服器是否收到原始查詢。
對此的解決方式是:如果自上一次查詢以來經過了較長時間,在連接上執行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節,「通信錯誤和失效連接」。
通信訊息包是發送至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。
對於連接問題,伺服器錯誤日誌是有用的資訊來源。請參見5.11.1節,「錯誤日誌」。如果伺服器是用「--log-warnings」選項啟動的,在錯誤日誌中可能會發現下述消息:
010301 14:38:23 Aborted connection 854 to db: 'users' user: 'josh'
如果「Aborted connections」(放棄連接)消息出現在錯誤日誌中,可能的原因是:
1. 客戶端程式在退出之前未使用mysql_close()。
2. 客戶端的空閒時間超過wait_timeout或interactive_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伺服器不可用」。
資料表已滿錯誤出現的方式有數種:
· 您正在使用低於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檔案的作業系統上使用ISAM或MyISAM資料表,數據檔案或索引檔案達到了該限制值。
· 您正在使用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;
僅應為具有BLOB或TEXT列的資料表指定AVG_ROW_LENGTH。在該情況下,MySQL不能僅根據行數最佳化所需的空間。
如果對某些查詢遇到下述類型的錯誤,它意味著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:磁盤上無剩餘空間。
如果遇到下述錯誤,資料表示當啟動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';
如果遇到下述錯誤之一,通常意味著當前資料庫中不存在具有給定名稱的資料表:
資料表'tbl_name'不存在
無法找到檔案:'tbl_name' (errno: 2)
在某些情況下,資料表或許存在,但未正確引用它:
· 由於MySQL使用目錄和檔案來保存資料庫和資料表,如果它們位於區分檔案名大小寫的檔案系統上,資料庫和資料表名也區分檔案大小寫。
· 即使對於不區分大小寫的檔案系統,如Windows,在查詢內對給定資料表的所有引用必須使用相同的大小寫。
可以使用SHOW TABLES檢查位於當前資料庫中的資料表。請參見13.5.4節,「SHOW語法」。
如果存在字元編碼問題,可能會遇到下述錯誤:
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. 將字元編碼定義檔案複製到客戶端預期的位置。
如果遇到「ERROR '...'未發現(errno: 23)」,「無法打開檔案:... (errno: 24)」,或來自MySQL的具有errno 23或errno 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_safe或mysqld時才能覆蓋它(請記住,在該情況下,還需使用「--user」選項啟動伺服器,以便在啟動後不再以根用戶身份繼續運行)。如果需要增加作業系統限制的對各程序可用檔案描述符的數目,請參閱系統文檔。
註釋:如果運行tcsh shell,ulimit不工作!請求當前限制值時,tcsh還能通報不正確的值。在該情況下,應使用sh啟動mysqld_safe。
當您連結到應用程式以使用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種方法之前,應確保沒有使用動態庫的其它程式。
在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節,「安裝後的設置和測試」。
如果遇到與檔案授權有關的問題,可能數啟動mysqld時UMASK環境變數設置得不正確。例如,當您建立資料表時,MySQL可能會發出下述錯誤消息:
ERROR: 無法找到檔案:'path/with/filename.frm' (Errcode: 13)
UMASK的預設值是0660。通過下述方式啟動mysqld_safe,可改變該情況:
shell> UMASK=384 # = 600 in octal
shell> export UMASK
shell> mysqld_safe &
在預設情況下,MySQL用0700的授權建立資料庫和RAID目錄。您可以通過設置UMASK_DIR變數更改該行為。如果您設置了它的值,將使用組合的UMASK和UMASK_DIR值建立新目錄。例如,如果您打算為所有新的目錄授予組訪問權限,可:
shell> UMASK_DIR=504 # = 770 in octal
shell> export UMASK_DIR
shell> mysqld_safe &
在MySQL 3.23.25和更高版本中,如果是以0開始的,MySQL將認為UMASK和UMASK_DIR的值均採用八進制形式。
如果您從未為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」。
應能使用新密碼進行連接。
正式發佈之前,每個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不使用外部鎖定。(這意味著,您不能在相同的數據目錄上運行2個mysqld伺服器,如果使用myisamchk,必須謹慎。然而,嘗試將該選項用作測試也是有益的)。
當mysqld看上去正在運行但並未響應時,是否運行了mysqladmin -u root processlist?某些時候,即使您認為mysqld處於閒置狀態時,實際情況並非如此。問題可能是因為所有連接均已使用,或存在某些內部鎖定問題。即使在該情況下,mysqladmin -u root processlist通常能夠進行連接,並能提供關於當前連接數以及其狀態的有用訊息。
在運行其他查詢的同時,在單獨的窗口中運行命令mysqladmin -i 5 status或mysqladmin -i 5 -r status,以生成統計訊息。
嘗試採用下述方法:
從gdb(或另一個調試器)啟動mysqld。請參見E.1.3節,「在gdb環境下調試mysqld」。
運行測試指令。
在3個較低層面上輸出backtrace(向後跟蹤)和局部變數。在gdb中,當mysqld在gdb內崩潰時,可使用下述命令完成該任務:
backtrace
info local
up
info local
up
info local
使用gdb,您還能檢查與info線程共存的線程,並切換至特定的線程N,其中,N是線程ID。
嘗試用Perl指令模擬您的應用程式,強制MySQL崩潰或行為異常。
發送正常的問題報告。請參見1.7.1.3節,「如何通報問題和問題」。應比通常的報告更詳細。由於MySQL是為很多人提供服務的,它可能因僅存在於您的計算機上的某事崩潰(例如,與您的特定系統庫有關的錯誤)。
如果您遇到與包含動態長度行的資料表有關的問題,而且您僅使用VARCHAR列(而不是BLOB或TEXT列),可嘗試用ALTER TABLE將所有VARCHAR列更改為CHAR列。這樣,就會強制MySQL使用固定大小的行。固定大小的行佔用的空間略多,但對損壞的容忍度更高。
目前的動態行代碼在MySQL AB已使用多年,很少遇到問題,但從本質上看,動態長度行更傾向於出現錯誤,因此,不妨嘗試採用該策略以查看它是否有幫助,這不失為一個好主意。
診斷問題時不要將您的伺服器硬件排除在外。有問題的硬件能夠導致數據損壞。對硬件進行故障診斷與排除操作時,尤其應注意RAM和硬盤驅動器。
在本節中,介紹了MySQL響應磁盤滿錯誤的方式(如「設備上無剩餘空間」),以及響應超配額錯誤的方式(如「寫入失敗」或「達到了用戶屏蔽限制」)。
本節介紹的內容與寫入MyISAM資料表有關。它也適用於寫入二進制日誌檔案和二進制索引檔案,但對「row」和「record」的應用應被視為「event」。
出現磁盤滿狀況時,MySQL將:
每分鐘檢查一次,查看是否有足夠空間寫入當前行。如果有足夠空間,將繼續,就像什麼也未發生一樣。
每10分鐘將1個條目寫入日誌檔案,提醒磁盤滿狀況。
為了減輕問題,可採取下述措施:
要想繼續,僅需有足夠的磁盤空間以插入所有記錄。
要想放棄線程,必須使用mysqladmin kill。下次檢查磁盤時將放棄線程(1分鐘)。
其他線程可能會正在等待導致磁盤滿狀況的資料表。如果有數個「已鎖定」的線程,殺死正在磁盤滿狀況下等待的某一線程,以便允許其他線程繼續。
對前述行為的例外是,當您使用REPAIR TABLE或OPTIMIZE TABLE時,或當索引是在LOAD DATA INFILE或ALTER TABLE語句後、在批操作中建立的。所有這些語句能建立大的臨時檔案,如果保留這些檔案,會導致系統其他部分出現大問題。如果在MySQL執行這類操作的同時磁盤已滿,它將刪除大的臨時檔案,並將資料表標注為崩潰。但對於ALTER TABLE例外,舊資料表保持不變。
MySQL使用環境變數TMPDIR的值作為保存臨時檔案的目錄的路徑名。如果未設置TMPDIR,MySQL將使用系統的預設值,通常為/tmp、/var/tmp或/usr/tmp。如果包含臨時檔案目錄的檔案系統過小,可對mysqld使用「—tmpdir」選項,在具有足夠空間的檔案系統內指定1個目錄。
在MySQL 5.1中,「—tmpdir」選項可被設置為數個路徑的列資料表,以循環方式使用。在Unix平台上,路徑用冒號字元「:」隔開,在Windows、NetWare和OS/2平台上,路徑用分號字元「;」隔開。注意,為了有效分佈負載,這些路徑應位於不同的物理磁盤上,而不是位於相同磁盤的不同分區中。
如果MySQL伺服器正作為複製從伺服器使用,不應將「--tmpdir」設置為指向基於內存的檔案系統的目錄,或當伺服器主機重啟時將清空的目錄。對於複製從伺服器,需要在機器重啟時仍保留一些臨時檔案,以便能夠複製臨時資料表或執行LOAD DATA INFILE操作。如果在伺服器重啟時丟失了臨時檔案目錄下的檔案,複製將失敗。
MySQL會以隱含方式建立所有的臨時檔案。這樣,就能確保中止mysqld時會刪除所有臨時檔案。使用隱含檔案的缺點在於,在臨時檔案目錄所在的位置中,看不到佔用了檔案系統的大臨時檔案。
進行排序時(ORDER BY或GROUP 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會在與原始資料表目錄相同的目錄下建立臨時資料表。
對於伺服器用來與本地客戶端進行通信的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
在預設情況下,MySQL搜索不區分大小寫(但某些字元編碼始終區分大小寫,如czech)。這意味著,如果您使用col_name LIKE 'a%'進行搜索,您將獲得以A或a開始的所有列。如果打算使搜索區分大小寫,請確保操作數之一具有區分大小寫的或二進制校對。例如,如果您正在比較均適用latin1字元編碼的列和字串,可使用COLLATE操作符,使1個操作數具有latin1_general_cs或latin1_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』)將被當作相同的寫字元。
DATE值的格式是'YYYY-MM-DD'。按照標準的SQL,不允許其他格式。在UPDATE資料表達式以及SELECT語句的WHERE子句中應使用該格式。例如:
mysql> SELECT * FROM tbl_name WHERE date >= '2003-05-05';
為了方便,如果日期是在數值環境下使用的,MySQL會自動將日期轉換為數值(反之亦然)。它還具有相當的智能,在更新時或在與TIMESTAMP、DATE或DATETIME列比較日期的WHERE子句中,允許「寬鬆的」字串形式(「寬鬆形式」資料表示,任何標點字元均能用作各部分之間的分隔符。例如,'2004-08-15'和'2004#08#15'是等同的)。MySQL還能轉換不含任何分隔符的字串(如'20040815'),前體是它必須是有意義的日期。
使用<、<=、=、>=、>、或BETWEEN操作符將DATE、TIME、DATETIME或TIMESTAMP與常量字串進行比較時,MySQL通常會將字串轉換為內部長整數,以便進行快速比較(以及略為「寬鬆」的字串檢查)。但是,該轉換具有下述例外:
比較兩列時
將DATE、TIME、DATETIME或TIMESTAMP列與資料表達式進行比較時
使用其他比較方法時,如IN或STRCMP()。
對於這些例外情形,會將對像轉換為字串並執行字串比較,採用該方式進行比較。
為了保持安全,假定按字串比較字串,如果您打算比較臨時值和字串,將使用恰當的字串函數。
對於特殊日期'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僅保證天位於1~31的範圍內,月位於1~12的範圍內。
這樣就使得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"。
對於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 NULL和IS 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值」。
如果您正在使用MyISAM、InnoDB、BDB、或MEMORY儲存引擎,能夠在可能具有NULL值的列上增加1條索引。如不然,必須聲明索引列為NOT NULL,而且不能將NULL插入到列中。
用LOAD DATA INFILE讀取數據時,對於空的或丟失的列,將用''更新它們。如果希望在列中具有NULL值,應在數據檔案中使用\N。在某些情況下,也可以使用文字性單詞「NULL」。請參見13.2.5 「LOAD DATA INFILE語法」。
使用DISTINCT、GROUP BY或ORDER 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屬性的整數列,將插入序列中的下一個編號。
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用於確定應使用結果集中的哪些行。
執行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語法」。
如果有使用了很多資料表的複雜查詢,但未返回任何行,應採用下述步驟找出什麼出錯:
用EXPLAIN測試查詢,以檢查是否發現某事顯然出錯。請參見7.2.1節,「EXPLAIN語法(獲取關於SELECT的訊息)」。
僅選擇在WHERE子句中使用的列。
從查詢中1次刪除1個資料表,直至返回了某些行為止。如果資料表很大,較好的主意是在查詢中使用LIMIT 10。
對於具有與上次從查詢中刪除的資料表匹配的行的列,發出SELECT查詢。
如果將FLOAT或DOUBLE列與具有數值類型的數值進行比較,不能使用等式(=)比較。在大多數計算機語言中,該問題很常見,這是因為,並非所有的浮點值均能以準確的精度保存。在某些情況下,將FLOAT更改為DOUBLE可更正該問題。請參見A.5.8節,「與浮點比較有關的問題」。
如果仍不能找出問題之所在,請建立能與顯示問題的「mysql test < query.sql」一起運行的最小測試。通過使用mysqldump --quick db_name tbl_name_1 ... tbl_name_n > query.sql轉儲資料表,可建立測試檔案。在編輯器中打開檔案,刪除某些插入的行(如果有超出演示問題所需的行),並在檔案末尾新增SELECT語句。
通過執行下述命令,驗證測試檔案能演示問題:
shell> mysqladmin create test2
shell> mysql test2 < query.sql
使用mysqlbug將測試檔案張貼到喲娜通用MySQL郵件列資料表。請參見1.7.1.1節,「The MySQL郵件列資料表」。
浮點數有時會導致混淆,這是因為它們無法以準確值保存在計算機體系結構中。您在屏幕上所看到的值通常不是數值的準確值。對於FLOAT和DOUBLE列類型,情況就是如此。DECIMAL列能保存具有準確精度的值,這是因為它們是由字串資料表示的。
在下面的示範中,介紹了使用DOUBLE時的問題:
mysql> CREATE TABLE t1 (i INT, d1 DOUBLE, d2 DOUBLE);
mysql> INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00),
-> (2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40),
-> (2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00),
-> (4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00),
-> (5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20),
-> (6, 0.00, 0.00), (6, -51.40, 0.00);
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b
-> FROM t1 GROUP BY i HAVING a <> b;
+------+-------+------+
| i | a | b |
+------+-------+------+
| 1 | 21.4 | 21.4 |
| 2 | 76.8 | 76.8 |
| 3 | 7.4 | 7.4 |
| 4 | 15.4 | 15.4 |
| 5 | 7.2 | 7.2 |
| 6 | -51.4 | 0 |
+------+-------+------+
結果是正確的。儘管前5個記錄看上去不應能進行比較測試(a和b的值看上去沒有什麼不同),但它們能進行比較,這是因為顯示的數值間的差異在十分位左右,具體情況取決於計算機的體系結構。
如果列d1和d2定義為DECIMAL而不是DOUBLE,SELECT查詢的結果僅包含1行,即上面顯示的最後1行。
MySQL採用了基於開銷的最佳化器,以確定處理查詢的最解方式。在很多情況下,MySQL能夠計算最佳的可能查詢計劃,但在某些情況下,MySQL沒有關於數據的足夠訊息,不得不就數據進行「有教養」的估測。
當MySQL未能做「正確的」事時,可使用下述工具來幫助MySQL:
使用EXPLAIN語句獲取關於MySQL如何處理查詢的訊息。要想使用它,可在SELECT語句前新增關鍵字EXPLAIN:
mysql> EXPLAIN SELECT * FROM t1, t2 WHERE t1.i = t2.i;
關於EXPLAIN的詳細討論,請參見7.2.1節,「EXPLAIN語法(獲取關於SELECT的訊息)」。
使用ANALYZE TABLE tbl_name,為已掃瞄的資料表更新鍵分配。請參見13.5.2.1節,「ANALYZE TABLE語法」。
為已掃瞄的資料表使用FORCE INDEX,通知MySQL:與使用給定的索引相比,資料表掃瞄開銷昂貴。請參見13.2.7節,「SELECT語法」。
SELECT * FROM t1, t2 FORCE INDEX (index_for_column)
WHERE t1.col_name=t2.col_name;
USE INDEX和IGNORE INDEX也有一定的幫助。
關於全局和資料表級別的STRAIGHT_JOIN。請參見13.2.7節,「SELECT語法」。
您可以調節全局或線程類系統變數。例如,用「--max-seeks-for-key=1000」選項啟動mysqld,或使用「SET max_seeks_for_key=1000」來通知最佳化器:假定任何資料表掃瞄均不會導致1000個以上的鍵搜索。請參見5.3.3節,「伺服器系統變數」。
ALTER TABLE將資料表更改為當前字元編碼。如果在執行ALTER TABLE操作期間遇到重複鍵錯誤,原因在於新的字元編碼將2個鍵映射到了相同值,或是資料表已損壞。在後一種情況下,應在資料表上運行REPAIR TABLE。
如果ALTER TABLE失敗並給出下述錯誤,問題可能是因為在ALTER TABLE操作的早期階段出現MySQL崩潰,沒有名為A-xxx或B-xxx的舊資料表:
Error on rename of './database/name.frm'
to './database/B-xxx.frm' (Errcode: 17)
在該情況下,進入MySQL數據目錄,並刪除其名稱為以A-或B-開始的所有檔案(或許您希望將它們移動到其他地方而不是刪除它們)。
ALTER TABLE的工作方式如下:
如果在重命名操作中出錯,MySQL將嘗試撤銷更改。如果錯誤很嚴重(儘管這不應出現),MySQL會將舊資料表保留為B-xxx。簡單地在系統級別上重命名資料表檔案,應能使數據復原。
如果在事務性資料表上使用ALTER TABLE,或正在使用Windows或OS/2作業系統,如果已在資料表上執行了LOCK TABLE操作,ALTER TABLE將對資料表執行解鎖操作。這是因為InnoDB和這類作業系統不能撤銷正在使用的資料表。
首先,請考慮是否的確需要更改資料表中的列順序。SQL的核心要點是從數據儲存格式獲取應用。總應指定檢索數據的順序。在下面的第1條語句中,以col_name1、col_name2、col_name3順序返回列;在第2條語句中,以col_name1、col_name3、col_name2順序返回列:
mysql> SELECT col_name1, col_name2, col_name3 FROM tbl_name;
mysql> SELECT col_name1, col_name3, col_name2 FROM tbl_name;
如果決定更改資料表列的順序,可執行下述操作:
mysql> INSERT INTO new_table
-> SELECT columns-in-new-order FROM old_table;
mysql> ALTER TABLE new_table RENAME old_table;
SELECT *十分適合於測試查詢。但是,在應用程式中,永遠不要依賴SELECT *的使用,不要依賴根據其位置檢索列。如果新增、移動或刪除了列,所返回的列的順序和位置不會保持相同。對資料表結構的簡單更改也會導致應用程式失敗。
下面介紹了對使用TEMPORARY資料表的限制:
mysql> SELECT * FROM temp_table, temp_table AS t2;
錯誤1137:不能再次打開資料表:'temp_table'
mysql> ALTER TABLE orig_name RENAME new_name;
在本節中,列出了當前MySQL版本中的已知事宜。
關於平台相關事宜的更多訊息,請參見2.12節,「具體作業系統相關的注意事項」和附錄E:移植到其他系統中的安裝和移植說明。
下面列出了已知問題,更正它們具有較高的優先級:
001207 22:07:56 bdb: log_flush: LSN past current end-of-log
如果以特定的方式設計查詢,使得數據更改是非決定性(通常不推薦,即使在複製之外也同樣),主伺服器和從伺服器上的數據將變得不同。
例如:
- 將0或NULL值插入AUTO_INCREMENT列中的CREATE ... SELECT或INSERT ... SELECT語句。
- DELETE,如果從具有ON DELETE CASCADE屬性的外部鍵的資料表中刪除行。
- REPLACE ... SELECT、INSERT IGNORE ... SELECT,如果在插入的數據中具有重複鍵。
當且僅當前述查詢沒有保證決定行順序的ORDER BY子句時。
例如,對於不具有ORDER BY的INSERT ... SELECT,SELECT可能會以不同的順序返回行(它會導致具有不同等級的行,從而導致AUTO_INCREMENT列中的不同數值),具體情況取決於最佳化器在主伺服器和從伺服器上所作的選擇。
在主伺服器和從伺服器上,查詢將進行不同的最佳化,僅當:
- 使用不同的儲存引擎在主伺服器上而不是從伺服器上保存資料表。(能夠在主伺服器和從伺服器上使用不同的儲存引擎。例如,如果從伺服器具有較少的可用磁盤空間,可以在主伺服器上使用InnoDB,但在 從伺服器桑使用MyISAM)。
- 在主伺服器和從伺服器上,MySQL緩衝區大小是不同的(key_buffer_size等)。
- 在主伺服器和從伺服器上運行不同的MySQL版本,版本間的最佳化器代碼也不同。
該問題也會影響使用mysqlbinlog|mysql的資料庫恢復。
避免該問題的最簡單方法是,為前述的非決定性查詢增加ORDER BY子句,以確保總是以相同的順序保存或更改行。
在將來的MySQL版本中,需要時,我們將自動增加ORDER BY子句。
下面列出了已知的事宜,這些事宜將在恰當的時候更正:
mysql> UPDATE tbl_name SET KEY=KEY+1,KEY=KEY+1;
mysql> SELECT * FROM temp_table, temp_table AS t2;
錯誤1137:不能再次打開資料表:'temp_table'
例如:
SELECT DISTINCT mp3id FROM band_downloads
WHERE userid = 9 ORDER BY id DESC;
以及
SELECT DISTINCT band_downloads.mp3id
FROM band_downloads,band_mp3
WHERE band_downloads.userid = 9
AND band_mp3.id = band_downloads.mp3id
ORDER BY band_downloads.id DESC;
在第2種情況下,使用MySQL伺服器3.23.x,可在結果集中獲得2個等同行(這是因為,隱藏ID列中的值可能不同)。
注意,在結果集中,僅對不含ORDER BY列的查詢才會出現該情況。
這是MySQL參考手冊的翻譯版本,關於MySQL參考手冊,請訪問dev.mysql.com。原始參考手冊為英文版,與英文版參考手冊相比,本翻譯版可能不是最新的。