18.2.1 mysql server has gone away錯(cuò)誤
本小節(jié)也涉及有關(guān)lost connection to server during query的錯(cuò)誤。
對(duì)mysql server has gone away錯(cuò)誤最常見(jiàn)的原因是服務(wù)器超時(shí)了并且關(guān)閉了連接。缺省地,如果沒(méi)有事情發(fā)生,服務(wù)器在 8個(gè)小時(shí)后關(guān)閉連接。你可在啟動(dòng)mysqld時(shí)通過(guò)設(shè)置wait_timeout變量改變時(shí)間限制。
你可以通過(guò)執(zhí)行mysqladmin version并且檢驗(yàn)正常運(yùn)行的時(shí)間來(lái)檢查mysql還沒(méi)死掉。
如果你有一個(gè)腳本,你只須再發(fā)出查詢讓客護(hù)進(jìn)行一次自動(dòng)的重新連接。
在這種請(qǐng)下,你通常能獲得下列錯(cuò)誤代碼(你得到的是os相關(guān)的):
cr_server_gone_error 客戶不能發(fā)送一個(gè)問(wèn)題給服務(wù)器。
cr_server_lost 當(dāng)寫服務(wù)器時(shí),客戶沒(méi)有出錯(cuò),但是它沒(méi)有得到對(duì)問(wèn)題的一個(gè)完整的答案(或任何答案)。
如果你向服務(wù)器發(fā)送不正確的或太大的查詢,你也可能得到這些錯(cuò)誤。如果mysqld得到一個(gè)太大或不正常的包,它認(rèn)為客戶出錯(cuò)了并關(guān)閉連接。如果你需要較大的查詢(例如,如果你正在處理較大的blob列),你可以使用-o max_allowed_packet=#選項(xiàng)(缺省1m)啟動(dòng)mysqld以增加查詢限制。多余的內(nèi)存按需分配,這樣mysqld只有在你發(fā)出較大差詢時(shí)或mysqld必須返回較大的結(jié)果行時(shí),才使用更多的內(nèi)存!
18.2.2 can’t connect to [local] mysql server錯(cuò)誤
一個(gè)mysql客戶可以兩種不同的方式連接mysqld服務(wù)器:unix套接字,它通過(guò)在文件系統(tǒng)中的一個(gè)文件(缺省“/tmp/mysqld.sock”)進(jìn)行連接;或tcp/ip,它通過(guò)一個(gè)端口號(hào)連接。unix套接字比tcp/ip更快,但是只有用在連接同一臺(tái)計(jì)算機(jī)上的服務(wù)器。如果你不指定主機(jī)名或如果你指定特殊的主機(jī)名localhost,使用unix套接字。
錯(cuò)誤(2002)can’t connect to ...通常意味著沒(méi)有一個(gè)mysql服務(wù)器運(yùn)行在系統(tǒng)上或當(dāng)試圖連接mysqld服務(wù)器時(shí),你正在使用一個(gè)錯(cuò)誤的套接字文件或tcp/ip端口。
由檢查(使用ps)在你的服務(wù)器上有一個(gè)名為mysqld的進(jìn)程啟動(dòng)!如果沒(méi)有任何mysqld過(guò)程,你應(yīng)該啟動(dòng)一個(gè)。見(jiàn)4.15.2 啟動(dòng)mysql服務(wù)器的問(wèn)題。
如果一個(gè)mysqld過(guò)程正在運(yùn)行,你可以通過(guò)嘗試這些不同的連接來(lái)檢查服務(wù)器(當(dāng)然,端口號(hào)和套接字路徑名可能在你的安裝中是不同的):
shell> mysqladmin version
shell> mysqladmin variables
shell> mysqladmin -h `hostname` version variables
shell> mysqladmin -h `hostname` --port=3306 version
shell> mysqladmin -h ’ip for your host’ version
shell> mysqladmin --socket=/tmp/mysql.sock version
注意hostname命令使用反引號(hào)“`”而非正引號(hào)“’”;這些導(dǎo)致hostname輸出(即,當(dāng)前主機(jī)名)被代替進(jìn)mysqladmin命令中。
這是可能造成can’t connect to local mysql server錯(cuò)誤的一些原因:
mysqld不在運(yùn)行。
你正在使用mit-pthreads的一個(gè)系統(tǒng)上運(yùn)行。如果正在運(yùn)行在一個(gè)沒(méi)有原生線程的系統(tǒng)上,mysqld使用 mit-pthreads 軟件包。見(jiàn)4.2 由mysql支持的操作系統(tǒng)。然而,mit-pthreads不支持unix套接字,因此當(dāng)與服務(wù)器連接時(shí),在這樣一個(gè)系統(tǒng)上,你總是必須明確地指定主機(jī)名。試試使用這個(gè)命令檢查到服務(wù)器的連接:
shell> mysqladmin -h `hostname` version
某人刪除了mysqld使用的unix套接字(缺省“/tmp/mysqld.sock”)。你可能有一個(gè)cron任務(wù)刪除了mysql套接字(例如,一個(gè)把舊文件從“/tmp”目錄中刪除的任務(wù))。你總是可以運(yùn)行mysqladmin version并且檢查mysqladmin正在試圖使用的套接字確實(shí)存在。在這種情況下,修復(fù)方法是刪除cron任務(wù)而不刪除“mysqld.sock 或?qū)⑻捉幼址旁谄渌胤健D隳苡眠@個(gè)命令在mysql配置時(shí)指定一個(gè)不同的套接字地點(diǎn):
shell> ./configure --with-unix-socket-path=/path/to/socket
你也可以使用--socket=/path/to/socket選項(xiàng)啟動(dòng)safe_mysqld和在啟動(dòng)你的mysql客戶前設(shè)置環(huán)境變量mysql_unix_port為套接字路徑名。你可用--socket=/path/to/socket選項(xiàng)啟動(dòng)mysqld服務(wù)器。如果你改變了服務(wù)器的套接字路徑名,你也必須通知mysql客戶關(guān)于新路徑的情況。你可以通過(guò)設(shè)置環(huán)境變量mysql_unix_port為套接字路徑名或由提供套接字路徑名作為客戶的參數(shù)做到。你可用這個(gè)命令測(cè)試套接字:
shell> mysqladmin --socket=/path/to/socket version
你正在使用 linux和線程已經(jīng)死了(核心傾倒了)。在這種情況中,你必須殺死其它mysqld線程(例如在啟動(dòng)一個(gè)新的mysql服務(wù)器之前,可以用mysql_zap腳本)。見(jiàn)18.1 如果mysql總是崩潰怎么辦。
如果你得到錯(cuò)誤can’t connect to mysql server on some_hostname,你可以嘗試下列步驟找出問(wèn)題是什么:
通過(guò)執(zhí)行telnet your-host-name tcp-ip-port-number并且按幾次回車來(lái)檢查服務(wù)器是否正常運(yùn)行。如果有一個(gè)mysql運(yùn)行在這個(gè)端口上,你應(yīng)該得到一個(gè)包含正在運(yùn)行的mysql服務(wù)器的版本號(hào)的應(yīng)答。如果你得到類似于telnet: unable to connect to remote host: connection refused的一個(gè)錯(cuò)誤,那么沒(méi)有服務(wù)器在使用的端口上運(yùn)行。
嘗試連接本地機(jī)器上的mysqld守護(hù)進(jìn)程,并用mysqladmin variables檢查mysqld被配置使用的tcp/ip端口(變量port)。
檢查你的mysqld服務(wù)器沒(méi)有用--skip-networking選項(xiàng)啟動(dòng)。
18.2.3 host ’...’ is blocked錯(cuò)誤
如果你得到象這樣的一個(gè)錯(cuò)誤:
host ’hostname’ is blocked because of many connection errors.
unblock with ’mysqladmin flush-hosts’
這意味著,mysqld已經(jīng)得到了大量(max_connect_errors)的主機(jī)’hostname’的在中途被中斷了的連接請(qǐng)求。在max_connect_errors次失敗請(qǐng)求后,mysqld認(rèn)定出錯(cuò)了(象來(lái)字一個(gè)黑客的攻擊),并且阻止該站點(diǎn)進(jìn)一步的連接,直到某人執(zhí)行命令mysqladmin flush-hosts。
缺省地,mysqld在10個(gè)連接錯(cuò)誤后阻塞一臺(tái)主機(jī)。你可以通過(guò)象這樣啟動(dòng)服務(wù)器很容易地調(diào)整它:
shell> safe_mysqld -o max_connect_errors=10000 &
注意,對(duì)給定的主機(jī),如果得到這條錯(cuò)誤消息,你應(yīng)該首先檢查該主機(jī)的tcp/ip連接有沒(méi)有問(wèn)題。如果你的tcp/ip連接不在運(yùn)行,增加max_connect_errors變量的值對(duì)你也不會(huì)有幫助!
18.2.4 too many connections錯(cuò)誤
如果在你試土連接mysql時(shí),你得到錯(cuò)誤too many connections,這意味著已經(jīng)有max_connections個(gè)客戶連接了mysqld服務(wù)器。
如果你需要比缺省(100)更多的連接,那么你應(yīng)該重啟mysqld,用更大的 max_connections 變量值。
注意,mysqld實(shí)際上允許(max_connections+1)個(gè)客戶連接。最后一個(gè)連接是為一個(gè)用process權(quán)限的用戶保留的。通過(guò)不把這個(gè)權(quán)限給一般用戶(他們不應(yīng)該需要它),有這個(gè)權(quán)限一個(gè)管理員可以登錄并且使用show processlist找出什么可能出錯(cuò)。見(jiàn)7.21 show句法(得到表,列的信息)。
18.2.5 out of memory錯(cuò)誤
如果你發(fā)出查詢并且得到類似于下面的錯(cuò)誤:
mysql: out of memory at line 42, ’malloc.c’
mysql: needed 8136 byte (8k), memory in use: 12481367 bytes (12189k)
error 2008: mysql client ran out of memory
注意,錯(cuò)誤指向了mysql客戶mysql。這個(gè)錯(cuò)誤的原因很簡(jiǎn)單,客戶沒(méi)有足夠的內(nèi)存存儲(chǔ)全部結(jié)果。
為了修正這個(gè)問(wèn)題,首先檢查你的查詢是否正確。它應(yīng)該返回這么多的行,這合理嗎?如果是這樣,你可以使用mysql --quick,它使用mysql_use_result()檢索結(jié)果集合。這將較少的負(fù)擔(dān)放在了客戶端(只是服務(wù)器更多)。
18.2.6 packet too large錯(cuò)誤
當(dāng)一個(gè)mysql客戶或mysqld服務(wù)器得到一個(gè)比max_allowed_packet個(gè)字節(jié)長(zhǎng)的包,它發(fā)出一個(gè)packet too large錯(cuò)誤并終止連接。
如果你正在使用mysql客戶,你可以通過(guò)用mysql --set-variable=max_allowed_packet=8m指定一個(gè)更大的緩沖區(qū)來(lái)啟動(dòng)客戶程序。
如果你正在使用不允許你指定最大包大小的其他客戶(例如 dbi),你需要在你啟動(dòng)服務(wù)器時(shí)設(shè)置包大小。你可以使用mysqld的命令行選項(xiàng)設(shè)置max_allowed_packet為一個(gè)更大的尺寸。例如,如果你正期望將一個(gè)全長(zhǎng)的blob存入一張表中,你將需要用--set-variable=max_allowed_packet=24m選項(xiàng)來(lái)啟動(dòng)服務(wù)器。
18.2.7 the table is full錯(cuò)誤
這個(gè)錯(cuò)誤發(fā)生在內(nèi)存臨時(shí)表變得比tmp_table_size字節(jié)大時(shí)。為了避免這個(gè)問(wèn)題,你可以使用mysqld的-o tmp_table_size=#選項(xiàng)來(lái)增加臨時(shí)表的大小,或在你發(fā)出有疑問(wèn)的查詢之前使用sql選項(xiàng)sql_big_tables。見(jiàn)7.25 set option句法。
你也可以使用--big-tables選項(xiàng)啟動(dòng)mysqld。這與為所有查詢使用sql_big_tables完全相同。18.2.8 commands out of sync in client錯(cuò)誤
如果你在你的客戶代碼中得到commands out of sync; you can’t run this command now,你正在以錯(cuò)誤的次序調(diào)用客戶函數(shù)!
這可能發(fā)生,例如,如果你正在使用mysql_use_result()并且在你已經(jīng)調(diào)用了mysql_free_result()之前試圖執(zhí)行新查詢。如果你在mysql_use_result()或mysql_store_result()之間試圖執(zhí)行返回?cái)?shù)據(jù)的2個(gè)查詢,它也可能發(fā)生。
18.2.9 ignoring user錯(cuò)誤
如果你得到下列錯(cuò)誤:
found wrong password for user: ’[email protected]_host’; ignoring user
這意味著在mysqld啟動(dòng)時(shí)或在它再次裝載權(quán)限表時(shí),它在user表中找到了一個(gè)有一個(gè)無(wú)效口令的條目。結(jié)果,條目簡(jiǎn)單地被權(quán)限系統(tǒng)忽略。
可能導(dǎo)致這個(gè)問(wèn)題的原因和修正:
你可能正在運(yùn)行一個(gè)有一個(gè)老的user表的新版本mysqld。你可以通過(guò)執(zhí)行mysqlshow mysql user看看口令字段是否少于 16個(gè)字符來(lái)檢查它。如果是這樣,你可以通過(guò)運(yùn)行scripts/add_long_password腳本改正這種情況。
用戶有一個(gè)老式的口令(8個(gè)字符長(zhǎng))并且你沒(méi)使用--old-protocol選項(xiàng)啟動(dòng)mysqld。用一個(gè)新口令更新在user表中的用戶或用--old-protocol重啟mysqld。
你沒(méi)有使用password()函數(shù)在在user表中指定了一個(gè)口令。使用mysql以一個(gè)新口令更新在user表中的用戶。確保使用password()函數(shù):
mysql> update user set password=password(’your password’)
where user=’xxx’;
18.2.10 table ’xxx’ doesn’t exist錯(cuò)誤
如果你得到錯(cuò)誤table ’xxx’ doesn’t exist或can’t find file: ’xxx’ (errno: 2),這意味著在當(dāng)前數(shù)據(jù)庫(kù)中沒(méi)有名為xxx的表存在。
注意,因?yàn)閙ysql使用目錄和文件存儲(chǔ)數(shù)據(jù)庫(kù)和表,數(shù)據(jù)庫(kù)和表名件是區(qū)分大小寫的!(在win32上,數(shù)據(jù)庫(kù)和表名不是區(qū)分大小寫的,但是在查詢中對(duì)所有表的引用必須使用相同的大小寫!)
你可以用show tables檢查你在當(dāng)前數(shù)據(jù)庫(kù)中有哪個(gè)表。見(jiàn)7.21 show句法(得到表、列的信息)。
18.3 mysql怎樣處理一個(gè)溢出的磁盤
當(dāng)出現(xiàn)一個(gè)磁盤溢出的情況時(shí),mysql做下列事情:
它每分鐘檢查一次看是否有足夠空間寫入當(dāng)前行。如果有足夠的空間,它繼續(xù)好像發(fā)生什么事情。
每6分鐘它將有關(guān)磁盤溢出的警告寫入日志文件。
為了緩和這個(gè)問(wèn)題,你可以采取下列行動(dòng):
繼續(xù),你只需釋放足夠的空閑磁盤空間以便插入所有記錄。
放棄線程,你必須發(fā)一個(gè)mysqladmin kill到線程。在下一次檢查磁盤時(shí),線程將被放棄(在1分鐘內(nèi))。
注意,其他線程可能正在等待引起“磁盤溢出”條件的表。如果你有幾個(gè)“鎖定的”的線程,殺死正在等待磁盤溢出條件的那個(gè)線程將允許其他線程繼續(xù)。
18.4 如何從一個(gè)文本文件運(yùn)行sql命令
一般地,mysql客戶被交互性地使用,象這樣:
shell> mysql database
然而,也可以把你的sql命令放在一個(gè)文件中并且告訴mysql從該文件讀取其輸入。要想這樣做,創(chuàng)造一個(gè)文本文件“text_file”,它包含你想要執(zhí)行的命令。然后如下那樣調(diào)用mysql:
shell> mysql database < text_file
你也能啟動(dòng)有一個(gè)use db_name語(yǔ)句的文本文件。在這種情況下,在命令行上指定數(shù)據(jù)庫(kù)名是不必要的:
shell> mysql < text_file
見(jiàn)12.1 不同的mysql程序概述。
18.5 mysql在哪兒存儲(chǔ)臨時(shí)文件
mysql使用tmpdir環(huán)境變量的值作為存儲(chǔ)臨時(shí)文件的目錄的路徑名。如果你沒(méi)有設(shè)置tmpdir,mysql使用系統(tǒng)缺省值,它通常是“/tmp”或“/usr/tmp”。如果包含你的臨時(shí)文件目錄的文件系統(tǒng)太小,你應(yīng)該編輯safe_mysqld設(shè)定tmpdir指向你有足夠空間的一個(gè)文件系統(tǒng)!你也可以使用mysqld的--tmpdir選項(xiàng)目設(shè)置臨時(shí)目錄。
mysql以“隱含文件”創(chuàng)建所有臨時(shí)文件。這保證了如果mysqld被終止,臨時(shí)文件也將被刪除。使用隱含文件的缺點(diǎn)是你將看不到一個(gè)大的臨時(shí)文件填滿了臨時(shí)文件目錄所在的文件系統(tǒng)。
當(dāng)排序(order by或group by)時(shí),mysql通常使用一個(gè)或兩個(gè)臨時(shí)文件。最大磁盤空間需求是:
(存儲(chǔ)東西的長(zhǎng)度 + sizeof (數(shù)據(jù)庫(kù)指針))
* 匹配的行數(shù)
* 2
sizeof(數(shù)據(jù)庫(kù)指針)通常是4,但是在未來(lái)對(duì)確實(shí)很大的表可能增加。
對(duì)一些select查詢,mysql也創(chuàng)建臨時(shí)sql表。這些沒(méi)被隱含且有“sql_*”格式的名字。
alter table和optimize table在原數(shù)據(jù)庫(kù)表的同一個(gè)目錄中創(chuàng)建一張臨時(shí)表。
18.6 怎樣保護(hù)“/tmp/mysql.sock ”不被刪除
如果你有這個(gè)問(wèn)題,事實(shí)上任何人可以刪除mysql通訊套接字“/tmp/mysql.sock”,在unix的大多數(shù)版本上,你能通過(guò)為其設(shè)置sticky(t)位來(lái)保護(hù)你的“/tmp”文件系統(tǒng)。作為root登錄并且做下列事情:
shell> chmod +t /tmp
這將保護(hù)你的“/tmp”文件系統(tǒng)使得文件僅能由他們的所有者或超級(jí)用戶(root)刪除。
你能執(zhí)行l(wèi)s -ld /tmp檢查sticky位是否被設(shè)置,如果最后一位許可位是t,該位被設(shè)置了。
18.7 access denied錯(cuò)誤
見(jiàn)6.6 權(quán)限系統(tǒng)如何工作。并且特別要看6.13 引起access denied錯(cuò)誤的原因。
18.8 怎樣作為一個(gè)一般用戶運(yùn)行mysql
mysql服務(wù)器mysqld能被任何用戶啟動(dòng)并運(yùn)行。為了將mysqld改由unix用戶user_name來(lái)運(yùn)行,你必須做下列事情:
如果它正在運(yùn)行,停止服務(wù)器(使用mysqladmin shutdown)。
改變數(shù)據(jù)庫(kù)目錄和文件以便user_name有權(quán)限讀和寫文件(你可能需要作為unix的root用戶才能做到):
shell> chown -r user_name /path/to/mysql/datadir
如果在mysql數(shù)據(jù)目錄中的目錄或文件是符號(hào)鏈接,你也將需要順著那些鏈接并改變他們指向的目錄和文件。chown -r不能跟隨符號(hào)鏈接。
以u(píng)ser_name用戶啟動(dòng)服務(wù)器,或如果你正在使用mysql 3.22或以后版本,以u(píng)nix root用戶啟動(dòng)mysqld并使用--user=user_name選項(xiàng),mysqld將在接受任何連接之前切換到以u(píng)nix user_name用戶運(yùn)行。
如果在系統(tǒng)被重新啟動(dòng)時(shí),你使用mysql.server腳本啟動(dòng)mysqld,你應(yīng)該編輯mysql.server用su以用戶user_name運(yùn)行mysqld,或使用--user選項(xiàng)調(diào)用mysqld。(不改變safe_mysqld是必要的。)
現(xiàn)在,你的mysqld進(jìn)程應(yīng)該正在作為unix用戶user_name運(yùn)行,并運(yùn)行完好。盡管有一件事情沒(méi)有變化:權(quán)限表的內(nèi)容。缺省 地(就在運(yùn)行了腳本mysql_install_db安裝的權(quán)限表后),mysql用戶root是唯一有存取mysql數(shù)據(jù)庫(kù)或創(chuàng)建或拋棄數(shù)據(jù)庫(kù)權(quán)限的用戶。除非你改變了那些權(quán)限,否則他們?nèi)匀槐3帧.?dāng)你作為一個(gè)unix用戶而不是root登錄時(shí),這不應(yīng)該阻止你作為mysql root用戶來(lái)存取mysql;只要為客戶程序指定-u root的選項(xiàng)。
注意通過(guò)在命令行上提供-u root,作為root存取mysql,與作為unix root用戶或其他unix用戶運(yùn)行mysql沒(méi)有關(guān)系。mysql的存取權(quán)限和用戶名與unix用戶名字是完全分開(kāi)的。唯一與unix用戶名有關(guān)的是,如果當(dāng)你調(diào)用一個(gè)客戶程序時(shí),你不提供一個(gè)-u選項(xiàng),客戶將試圖使用你的unix登錄名作為你的mysql用戶名進(jìn)行連接。
如果你的unix機(jī)器本身不安全,你可能應(yīng)該至少在存取表中為mysql root用戶放上一個(gè)口令。否則,在那臺(tái)機(jī)器上有一個(gè)帳號(hào)的任何用戶能運(yùn)行mysql -u root db_name并且做他喜歡做的任何事情。
18.9 怎樣重新設(shè)置一個(gè)忘記的口令
如果你忘記了mysql的root用戶的口令,你可以用下列過(guò)程恢復(fù)它。
通過(guò)發(fā)送一個(gè)kill(不是kill -9)到mysqld服務(wù)器來(lái)關(guān)閉mysqld服務(wù)器。pid 被保存在一個(gè).pid文件中,通常在mysql數(shù)據(jù)庫(kù)目錄中:
kill `cat /mysql-data-directory/hostname.pid`
你必須是一個(gè)unix root用戶或運(yùn)行服務(wù)器的相同用戶做這個(gè)。
使用--skip-grant-tables選項(xiàng)重啟mysqld。
用mysql -h hostname mysql連接mysqld服務(wù)器并且用一條grant命令改變口令。見(jiàn)7.26 grant和revoke句法。你也可以用mysqladmin -h hostname -u user password ’new password’ 進(jìn)行。
用mysqladmin -h hostname flush-privileges或用sql命令flush privileges來(lái)裝載權(quán)限表。
18.10 文件許可權(quán)限問(wèn)題
如果你有與文件許可有關(guān)的問(wèn)題,例如,如果當(dāng)你創(chuàng)建一張表時(shí),mysql發(fā)出下列錯(cuò)誤消息:
error: can’t find file: ’path/with/filename.frm’ (errcode: 13)
那么可能是在mysqld啟動(dòng)時(shí),環(huán)境變量umask可能設(shè)置不正確。缺省的umask值是0660。你可以如下啟動(dòng)safe_mysqld改變其行為:
shell> umask=384 # = 600 in octal
shell> export umask
shell> /path/to/safe_mysqld &
18.11 文件沒(méi)找到
如果你從mysql得到error ’...’ not found (errno: 23), can’t open file: ... (errno: 24)或任何其他有errno 23或errno 24的錯(cuò)誤,它意味著,你沒(méi)有為mysql分配足夠的文件描述符。你能使用perror實(shí)用程序得到錯(cuò)誤號(hào)含義是什么的描述:
shell> perror 23
file table overflow
shell> perror 24
too many open files
這里的問(wèn)題是mysqld正在試圖同時(shí)保持打開(kāi)太多的文件。你也可以告訴mysqld一次不打開(kāi)那么多的文件,或增加mysqld可得到的文件描述符數(shù)量。為了告訴mysqld一次保持打開(kāi)更少的文件,你可以通過(guò)使用safe_mysqld的-o table_cache=32選項(xiàng)(缺省值是64)使表緩沖更小。減小max_connections值也將減少打開(kāi)文件的數(shù)量(缺省值是90)。
要想改變mysqld可用的文件描述符數(shù)量,修改safe_mysqld腳本。腳本中有一條注釋了的行ulimit -n 256。你可以刪除’#’字符來(lái)去掉該行的注釋,并且改變數(shù)字256改變?yōu)閙ysqld可用的文件描述符的數(shù)量。
ulimit能增加文件描述符的數(shù)量,但是只能到操作系統(tǒng)強(qiáng)加的限制。如果你需要增加每個(gè)進(jìn)程可用的文件描述符數(shù)量的os限制,參見(jiàn)你的操作系統(tǒng)文檔。注意,如果你運(yùn)行tcsh外殼,ulimit將不工作!當(dāng)你請(qǐng)求當(dāng)前限制時(shí),tcsh也將報(bào)告不正確的值!在這種情況下,你應(yīng)該用sh啟動(dòng)safe_mysqld!
18.12 使用date列的問(wèn)題
一個(gè)date值的格式是’yyyy-mm-dd’。根據(jù)ansi sql,不允許其他格式。你應(yīng)該在update表達(dá)式和select語(yǔ)句的where子句中使用這個(gè)格式。例如:
mysql> select * from tbl_name where date >= ’1997-05-05’;
為了方便,如果日期用在數(shù)字上下文,mysql自動(dòng)變換一個(gè)日期到一個(gè)數(shù)字(并且反過(guò)來(lái)也如此)。當(dāng)更新時(shí)和將一個(gè)日期與timestamp、date或datetime列比較的一個(gè)where子句中,也是足夠靈活以允許一種“寬松”的字符串格式。(寬松格式意味著任何標(biāo)點(diǎn)字符用作在部件之間的分割符。例如,’1998-08-15’和’1998#08#15’是等價(jià)的。)mysql也能變換不包含分割符的一個(gè)字符串(例如 ’19980815’),如果它作為一個(gè)日期說(shuō)得通。特殊日期’0000-00-00’可以作為’0000-00-00’被存儲(chǔ)和檢索。當(dāng)通過(guò)myodbc使用一個(gè)’0000-00-00’日期時(shí),在myodbc 2.50.12和以上版本,它將自動(dòng)被轉(zhuǎn)換為null,因?yàn)閛dbc不能處理這種日期。
因?yàn)閙ysql實(shí)行了上述的變換,下列語(yǔ)句可以工作:
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,’19970505’)=0;
strcmp()是字符串函數(shù),因此它將idate轉(zhuǎn)換為一個(gè)字符串并且實(shí)施字符串比較。它不將’19970505’轉(zhuǎn)換為一個(gè)日期并實(shí)施日期比較。
注意,mysql不檢查日期是否正確。如果你存儲(chǔ)一個(gè)不正確的日期,例如’1998-2-31’,錯(cuò)誤的日期將被存儲(chǔ)。如果日期不能被變換到任何合理的值,在date字段中存儲(chǔ)一個(gè)0。這主要是一個(gè)速度問(wèn)題并且我們認(rèn)為檢查日期是應(yīng)用程序的責(zé)任,而不服務(wù)器。
18.13 時(shí)區(qū)問(wèn)題
如果你有一個(gè)問(wèn)題,select now()以gmt時(shí)間返回值而不是你的本地時(shí)間,你必須設(shè)定tz環(huán)境變量為你的當(dāng)前時(shí)區(qū)。這應(yīng)該在服務(wù)器運(yùn)行的環(huán)境進(jìn)行,例如在safe_mysqld或mysql.server中。
18.14 在搜索中的大小寫敏感性
缺省地,mysql搜索是大小寫不敏感的(盡管有一些字符集從來(lái)不是忽略大小寫的,例如捷克語(yǔ))。這意味著,如果你用col_name like ’a%’搜尋,你將得到所有以a或a開(kāi)始的列值。如果你想要使這個(gè)搜索大小寫敏感,使用象index(col_name, "a")=0檢查一個(gè)前綴。或如果列值必須確切是"a",使用strcmp(col_name, "a") = 0。
簡(jiǎn)單的比較操作(>=、>、= 、< 、<=、排序和聚合)是基于每個(gè)字符的“排序值”。有同樣排序值的字符(象e,e和’e)被視為相同的字符!
like比較在每個(gè)字符的大寫值上進(jìn)行(e==e 但是e<>’e)。
如果你想要一個(gè)列總是被當(dāng)作大小寫敏感的方式,聲明它為binary。見(jiàn)7.7 create table句法。
如果你使用以所謂的big5編碼的中文數(shù)據(jù),你要使所有的字符列是binary,它可行,是因?yàn)閎ig5編碼字符的排序順序基于 ascii代碼的順序。
18.15 null值問(wèn)題
null值的概念是造成sql的新手的混淆的普遍原因,他們經(jīng)常認(rèn)為null是和一個(gè)空字符串’’的一樣的東西。不是這樣的!例如,下列語(yǔ)句是完全不同的:
mysql> insert into my_table (phone) values (null);
mysql> insert into my_table (phone) values ("");
兩個(gè)語(yǔ)句把值插入到phone列,但是第一個(gè)插入一個(gè)null值而第二個(gè)插入一個(gè)空字符串。第一個(gè)的含義可以認(rèn)為是“電話號(hào)碼不知道”,而第二個(gè)則可意味著“她沒(méi)有電話”。
在sql中,null值在于任何其他值甚至null值比較時(shí)總是假的(false)。包含null的一個(gè)表達(dá)式總是產(chǎn)生一個(gè)null值,除非在包含在表達(dá)式中的運(yùn)算符和函數(shù)的文檔中指出。在下列例子,所有的列返回null:
mysql> select null,1+null,concat(’invisible’,null);
如果你想要尋找值是null的列,你不能使用=null測(cè)試。下列語(yǔ)句不返回任何行,因?yàn)閷?duì)任何表達(dá)式,expr = null是假的:
mysql> select * from my_table where phone = null;
要想尋找null值,你必須使用is null測(cè)試。下例顯示如何找出null電話號(hào)碼和空的電話號(hào)碼:
mysql> select * from my_table where phone is null;
mysql> select * from my_table where phone = "";
在mysql中,就像很多其他的sql服務(wù)器一樣,你不能索引可以有null值的列。你必須聲明這樣的列為not null,而且,你不能插入null到索引的列中。當(dāng)用load data infile讀取數(shù)據(jù)時(shí),空列用’’更新。如果你想要在一個(gè)列中有null值,你應(yīng)該在文本文件中使用/n。字面詞’null’也可以在某些情形下使用。見(jiàn)7.16 load data infile句法。當(dāng)使用order by時(shí),首先呈現(xiàn)null值。如果你用desc以降序排序,null值最后顯示。當(dāng)使用group by時(shí),所有的null值被認(rèn)為是相等的。為了有助于null的處理,你能使用is null和is not null運(yùn)算符和ifnull()函數(shù)。
對(duì)某些列類型,null值被特殊地處理。如果你將null插入表的第一個(gè)timestamp列,則插入當(dāng)前的日期和時(shí)間。如果你將null插入一個(gè)auto_increment列,則插入順序中的下一個(gè)數(shù)字。
18.16 alias問(wèn)題
你可以在group by、order by或在having部分中使用別名引用列。別名也可以用來(lái)為列取一個(gè)更好點(diǎn)的名字:
select sqrt(a*b) as rt from table_name group by rt having rt > 0;
select id,count(*) as cnt from table_name group by id having cnt > 0;
select id as "customer identity" from table_name;
注意,你的 ansi sql 不允許你在一個(gè)where子句中引用一個(gè)別名。這是因?yàn)樵趙here代碼被執(zhí)行時(shí),列值還可能沒(méi)有終結(jié)。例如下列查詢是不合法:select id,count(*) as cnt from table_name where cnt > 0 group by id;
where語(yǔ)句被執(zhí)行以確定哪些行應(yīng)該包括group by部分中,而having用來(lái)決定應(yīng)該只用結(jié)果集合中的哪些行。
18.17 從關(guān)聯(lián)的表中刪除行
因?yàn)閙ysql不支持子選擇或在delete語(yǔ)句中使用多個(gè)表,你應(yīng)該使用下列方法從2個(gè)關(guān)聯(lián)的表中刪除行:
在主表中基于某個(gè)where條件select行。
在主表中基于相同的條件delete行。
delete from related_table where related_column in (selected_rows)
如果在related_column查詢中的字符的全部數(shù)量超過(guò)1,048,576(缺省值max_allowed_packet),你應(yīng)該分成更小的部分并且執(zhí)行多個(gè)delete語(yǔ)句。如果related_column是一個(gè)索引,你每次只刪除100-1000個(gè)related_column id將可能使得delete最快。如果related_column不是一個(gè)索引,速度與in子句中參數(shù)的數(shù)量無(wú)關(guān)。
18.18 解決沒(méi)有匹配行的問(wèn)題
如果你有一個(gè)復(fù)雜的查詢,涉及多個(gè)表,但沒(méi)有返回任何行,你應(yīng)該使用下列過(guò)程查找你的詢問(wèn)有什么不對(duì):
explain測(cè)試查詢并且檢查你是否能找出顯然是錯(cuò)誤的一些東西。見(jiàn)7.22 explain句法(得到關(guān)于一個(gè)select的信息)。
僅選擇那些在where子句中使用的字段。
一次從查詢中刪除一個(gè)表,直到它返回一些行。如果表很大,對(duì)查詢使用limit 10是一個(gè)好主意。
對(duì)應(yīng)該已經(jīng)匹配一行的列做一個(gè)select,針對(duì)從詢問(wèn)中做后被刪除的表。
如果你將float或double列與有小數(shù)的數(shù)字進(jìn)行比較,你不能使用=!。這個(gè)問(wèn)題在大多數(shù)計(jì)算機(jī)語(yǔ)言是常見(jiàn)的,因?yàn)楦↑c(diǎn)值不是準(zhǔn)確的值。
mysql> select * from table_name where float_column=3.5;
->
mysql> select * from table_name where float_column between 3.45 and 3.55;
在大多數(shù)情況下,將float改成一個(gè)double將修正它!
如果你仍然不能發(fā)現(xiàn)錯(cuò)誤是什么,創(chuàng)建一個(gè)最小的可運(yùn)行mysql test < query.sql的測(cè)試來(lái)顯示你的問(wèn)題。你可以用mysqldump --quick database tables > query.sql創(chuàng)建一個(gè)測(cè)試文件,在一個(gè)編輯器編輯文件,刪除一些插入行(如果有太多這些語(yǔ)句)并且在文件末尾加入你的選擇語(yǔ)句。測(cè)試你仍然有問(wèn)題,可以這樣做:
shell> mysqladmin create test2
shell> mysql test2 < query.sql
使用mysqlbug的郵寄測(cè)試文件到[email protected]。
18.19 與alter table有關(guān)的問(wèn)題
如果alter table死于這樣一個(gè)錯(cuò)誤:
error on rename of ’./database/name.frm’ to ’./database/b-a.frm’ (errcode: 17)
問(wèn)題可能是mysql在前一個(gè)alter table中已經(jīng)崩潰并且留下了一個(gè)名為“a-xxx”或“b-xxx”的老的數(shù)據(jù)庫(kù)表。在這種情況下,到mysql數(shù)據(jù)目錄中并刪除所有名字以a-或b-開(kāi)始的文件。(你可以把他們移到別的地方而不是刪除他們)。
alter table工作方式是:
以要求的改變創(chuàng)建一個(gè)名為“a-xxx”的新表。
從老表把所有行拷貝到“a-xxx”。
老表被改名為“b-xxx”。
“a-xxx”被改名為你的老表的名字。
“b-xxx”被刪除。
如果某些改名操作出錯(cuò),mysql試圖還原改變。如果出錯(cuò)嚴(yán)重(當(dāng)然,這不應(yīng)該發(fā)生。),mysql可能留下了老表為“b-xxx”但是一個(gè)簡(jiǎn)單改名就應(yīng)該恢復(fù)你的數(shù)據(jù)。
18.20 怎樣改變一張表中列的順序
sql的要點(diǎn)是中抽象應(yīng)用程序以避免數(shù)據(jù)存儲(chǔ)格式。你應(yīng)該總是以你想要檢索數(shù)據(jù)的意愿指定順序。例如:
select col_name1, col_name2, col_name3 from tbl_name;
將以col_name1、col_name2、col_name3的順序返回列,而:
select col_name1, col_name3, col_name2 from tbl_name;
將以col_name1、col_name3、col_name2的順序返回列。
在一個(gè)應(yīng)用程序中,你應(yīng)該決不基于他們的位置使用select * 檢索列,因?yàn)楸环祷氐牧械捻樞蛴肋h(yuǎn)不能保證;對(duì)你的數(shù)據(jù)庫(kù)的一個(gè)簡(jiǎn)單改變可能導(dǎo)致你的應(yīng)用程序相當(dāng)有戲劇性地失敗。
不管怎樣,如果你想要改變列的順序,你可以這樣做:
以正確的列順序創(chuàng)建一張新表。
執(zhí)行insert into new_table select fields-in-new_table-order from old_table.
刪除或改名old_table。
alter table new_table rename old_table。