7.6 磁盤(pán)
- 磁盤(pán)搜索是性能的很大瓶頸。這個(gè)問(wèn)題在數(shù)據(jù)大量增長(zhǎng)以至于無(wú)法使用有效的緩存時(shí)尤為明顯?;蚨嗷蛏匐S即訪問(wèn)大數(shù)據(jù)庫(kù)時(shí),就必然會(huì)有至少一次磁盤(pán)搜索來(lái)讀數(shù)據(jù),兩次磁盤(pán)搜索來(lái)寫(xiě)數(shù)據(jù)。最小化這個(gè)問(wèn)題的辦法就是降低磁盤(pán)搜索次數(shù)。
- 增加有效磁盤(pán)馬達(dá)數(shù)量(這能減少搜索時(shí)的開(kāi)銷)或者將不同的文件鏈接到不同的磁盤(pán)上又或者分盤(pán):
- 使用符號(hào)鏈接
意思是,把MyISAM
表的索引文件和/或數(shù)據(jù)文件從數(shù)據(jù)目錄下通常的地方鏈接到其他磁盤(pán)上(這也是分盤(pán))。如果這個(gè)磁盤(pán)沒(méi)有其他用途的話,這對(duì)讀寫(xiě)次數(shù)都比較好。詳情請(qǐng)看"7.6.1 Using Symbolic Links"。
- 分盤(pán)
如果有好幾個(gè)磁盤(pán),就把第一個(gè)區(qū)塊放在第一個(gè)磁盤(pán),把第二個(gè)區(qū)塊放在第二個(gè)磁盤(pán),以此類推。這意味著正常的數(shù)據(jù)大小比分盤(pán)后的數(shù)據(jù)小(或者完全一樣),這能獲得更好性能。分盤(pán)完全依賴于操作系統(tǒng)以及分盤(pán)的大小,因此要用不同的分盤(pán)大小基準(zhǔn)測(cè)試應(yīng)用程序。詳情請(qǐng)看"7.1.5 Using Your Own Benchmarks"?;鶞?zhǔn)測(cè)試的速度的不同完全依賴于分盤(pán)大小。依賴分盤(pán)設(shè)置參數(shù)以及磁盤(pán)數(shù)量,會(huì)得到大量不同的測(cè)量結(jié)果。必須隨機(jī)或者順序選擇優(yōu)化方法。
- 使用符號(hào)鏈接
- 可能會(huì)為了可靠性采用 RAID 0+1,這時(shí),就必須用 2*N 個(gè)驅(qū)動(dòng)去來(lái)保存 N 個(gè)驅(qū)動(dòng)器上的數(shù)據(jù)。如果有足夠的內(nèi)存這可能是最好的方法。不過(guò),這也需要使用卷管理軟件來(lái)有效地管理數(shù)據(jù)。
- 另一個(gè)好辦法是RAID的級(jí)別根據(jù)數(shù)據(jù)的重要性而定。例如,把能重新生成的有點(diǎn)重要的數(shù)據(jù)保存在RAID 0磁盤(pán)上,把很重要的數(shù)據(jù)如主機(jī)信息日志等保存在RAID 0+1或者RAID N磁盤(pán)上。RAID N在有很多個(gè)寫(xiě)入時(shí)可能會(huì)有問(wèn)題,因?yàn)闀?huì)同時(shí)請(qǐng)求更新同一個(gè)字節(jié)位。
- 在Linux上,可以用
hdparm
來(lái)配置磁盤(pán)接口以獲得更好的性能(在負(fù)載下高達(dá)100%也不是不可能的)。以下hdparm
配置選項(xiàng)對(duì)MySQL就很合適,對(duì)其他應(yīng)用程序可能也不錯(cuò):hdparm -m 16 -d 1
注意,當(dāng)使用這個(gè)命令之后性能和可靠性會(huì)依賴硬件,因此我們強(qiáng)烈建議在使用
hdparm
后一定要做測(cè)試。請(qǐng)查閱hdparm
的手冊(cè)。如果沒(méi)有正確使用hdparm
,則可能導(dǎo)致文件系統(tǒng)沖突,所以在試驗(yàn)之前備份一下。 - 還可以在數(shù)據(jù)庫(kù)使用的文件系統(tǒng)上設(shè)置其參數(shù):如果無(wú)需知道文件的最后訪問(wèn)時(shí)間(這對(duì)數(shù)據(jù)庫(kù)系統(tǒng)沒(méi)用),則在掛載文件系統(tǒng)時(shí)使用
-o noatime
選項(xiàng)。這就會(huì)略過(guò)更新文件系統(tǒng)節(jié)點(diǎn)的最后訪問(wèn)時(shí)間,也就減少了磁盤(pán)搜索。在很多操作系統(tǒng)上,可以在掛載文件系統(tǒng)是使用-o async
選項(xiàng)以異步更新它。如果你的機(jī)器相當(dāng)?shù)姆€(wěn)定,這會(huì)帶來(lái)性能提升但可靠性并沒(méi)犧牲多少(默認(rèn)只能在Linux上這樣用)。
7.6.1 使用符號(hào)鏈接
可以把數(shù)據(jù)表或者數(shù)據(jù)庫(kù)移動(dòng)到別的目錄下,然后用符號(hào)鏈接到新的位置來(lái)代替。你可能想這么做,例如,想要把表分布到不同的磁盤(pán)上以提高系統(tǒng)速度,就把它們移動(dòng)到有更多剩余空間的磁盤(pán)上。
建議只是把數(shù)據(jù)庫(kù)鏈接到其他磁盤(pán)上,數(shù)據(jù)表的鏈接是最后的選擇。
7.6.1.1 在 Unix 上符號(hào)鏈接數(shù)據(jù)庫(kù)
在Unix上,給數(shù)據(jù)庫(kù)做符號(hào)鏈接的方法是先在其他磁盤(pán)上創(chuàng)建一個(gè)目錄,然后再把它鏈接到MySQL數(shù)據(jù)文件目錄下。
shell> mkdir /dr1/databases/testshell> ln -s /dr1/databases/test /path/to/datadir
MySQL不支持把一個(gè)目錄鏈接成多個(gè)數(shù)據(jù)庫(kù)。只要沒(méi)有在數(shù)據(jù)庫(kù)間做符號(hào)鏈接,那么它就沒(méi)問(wèn)題。假使在MySQL數(shù)據(jù)文件目錄下已經(jīng)有一個(gè)數(shù)據(jù)庫(kù) db1
了,然后把 db1
鏈接到 db2
:
shell> cd /path/to/datadirshell> ln -s db1 db2
現(xiàn)在,在 db1
中的表 tbl_a
,也會(huì)在 db2
中出現(xiàn)。如果有一個(gè)客戶端要更新 db1.tbl_a
而另一個(gè)要更新 db1.tbl_a
,這時(shí)就會(huì)出問(wèn)題了。
如果確實(shí)需要這么做,那么就修改一個(gè)源文件。要修改的文件根據(jù)MySQL版本不同而不同。MySQL 4.0或更新,在 `mysys/my_symlink.c' 文件中找到以下語(yǔ)句:
if (!(MyFlags & MY_RESOLVE_LINK) ||(!lstat(filename,&stat_buff) && S_ISLNK(stat_buff.st_mode)))
MySQL 4.0以前,在 `mysys/mf_format.c' 文件中找到如下語(yǔ)句:
if (flag & 32 || (!lstat(to,&stat_buff) && S_ISLNK(stat_buff.st_mode)))
然后把這個(gè)語(yǔ)句改成:
if (1)
在Windows上,在編譯MySQL時(shí)使用選項(xiàng) -DUSE_SYMDIR
就能內(nèi)置支持目錄符號(hào)鏈接。這可以讓你把不同的數(shù)據(jù)庫(kù)放到不同的磁盤(pán)上,詳情請(qǐng)看"7.6.1.3 Using Symbolic Links for Databases on Windows"。
7.6.1.2 在 Unix 上符號(hào)鏈接數(shù)據(jù)表
在MySQL 4.0以前,除非特別小心否則不要鏈接數(shù)據(jù)表。有一個(gè)問(wèn)題是,當(dāng)在一個(gè)符號(hào)鏈接表上執(zhí)行 ALTER TABLE
, REPAIR TABLE
, 或 OPTIMIZE TABLE
時(shí),符號(hào)鏈接就會(huì)被刪除然后替換成原來(lái)的文件。這是因?yàn)閳?zhí)行這些語(yǔ)句時(shí),需要在數(shù)據(jù)庫(kù)目錄下創(chuàng)建臨時(shí)文件,然后在操作完成后把臨時(shí)文件替換到原來(lái)的文件中去。
最好不要在不能很好支持 realpath()
調(diào)用的操作系統(tǒng)上鏈接數(shù)據(jù)表(不過(guò)至少Linux和Solaris支持 realpath()
)。執(zhí)行 SHOW VARIABLES LIKE 'have_symlink'
語(yǔ)句來(lái)檢查你的系統(tǒng)是否支持符號(hào)鏈接。
在MySQL 4.0,MyISAM
表完全支持符號(hào)鏈接。而其他表類型如果也做符號(hào)鏈接的話,則很可能在執(zhí)行語(yǔ)句前會(huì)碰到一些奇怪的問(wèn)題。
MySQL 4.0中的 MyISAM
表符號(hào)鏈接以如下方式工作:
- 在數(shù)據(jù)目錄下,總是有表定義文件,以及數(shù)據(jù)文件,以及索引文件。數(shù)據(jù)和索引文件可以被移動(dòng)到任何處然后用符號(hào)鏈接代替,但是表定義文件不可以。
- 可以分別把數(shù)據(jù)和索引文件鏈接到不同目錄下。
- 在
mysqld
沒(méi)有運(yùn)行時(shí)可以用命令行ln -s
手工完成符號(hào)鏈接。如果用SQL,可以在CREATE TABLE
時(shí)使用選項(xiàng)DATA DIRECTORY
和INDEX DIRECTORY
告訴服務(wù)器使用符號(hào)鏈接。詳情請(qǐng)看"14.2.6CREATE TABLE
Syntax"。 myisamchk
不會(huì)替換符號(hào)鏈接的數(shù)據(jù)或索引文件。它直接在符號(hào)鏈接指向的文件上操作。任何臨時(shí)文件都創(chuàng)建在數(shù)據(jù)或索引文件所在的目錄下。- 當(dāng)刪除一個(gè)符號(hào)鏈接的表后,鏈接表及其指向的表都會(huì)被刪除。這就是為什么不能以
root
身份運(yùn)行mysqld
的原因,同樣地,不要允許用戶有權(quán)寫(xiě)MySQL數(shù)據(jù)庫(kù)目錄。 - 如果用
ALTER TABLE ... RENAME
語(yǔ)句重命名一個(gè)表且沒(méi)有把它移動(dòng)到其他數(shù)據(jù)庫(kù)下,那么在數(shù)據(jù)庫(kù)目錄下的文件就被改名了,相應(yīng)地,它指向的數(shù)據(jù)或索引文件也改名了。 - 如果用
ALTER TABLE ... RENAME
語(yǔ)句把表移動(dòng)到其他數(shù)據(jù)庫(kù)下,則這個(gè)表就移動(dòng)到其他數(shù)據(jù)庫(kù)目錄下。舊的鏈接及其所指向的文件都被刪掉。換言之,新的表就不再被符號(hào)鏈接了。 - 如果沒(méi)有使用符號(hào)鏈接,那么就給
mysqld
增加選項(xiàng)--skip-symbolic-links
確保無(wú)人能刪除或重命名數(shù)據(jù)文件目錄以外的文件。
在MySQL 4.0.15以前, SHOW CREATE TABLE
語(yǔ)句不會(huì)報(bào)告一個(gè)表是否有符號(hào)鏈接。mysqldump
也一樣,它是用 SHOW CREATE TABLE
來(lái)產(chǎn)生 CREATE TABLE
語(yǔ)句的。
表符號(hào)鏈接操作還不支持:
ALTER TABLE
操作會(huì)忽略DATA DIRECTORY
和INDEX DIRECTORY
表選項(xiàng)。BACKUP TABLE
和RESTORE TABLE
也沒(méi)考慮符號(hào)鏈接。- `.frm` 文件肯定不能被符號(hào)鏈接(在前面提到,索引及數(shù)據(jù)文件可以被符號(hào)鏈接)。企圖這么做(比如用同義)的話就會(huì)導(dǎo)致一些錯(cuò)誤。假設(shè)有在數(shù)據(jù)庫(kù)目錄下有一個(gè)數(shù)據(jù)庫(kù)
db1
,庫(kù)里有一個(gè)表tbl1
,在db1
目錄下把tbl2
符號(hào)鏈接到tbl1
:shell> cd /path/to/datadir/db1 shell> ln -s tbl1.frm tbl2.frm shell> ln -s tbl1.MYD tbl2.MYD shell> ln -s tbl1.MYI tbl2.MYI
現(xiàn)在如果有一個(gè)線程讀取
db1.tbl1
而另一個(gè)線程更新db1.tbl2
時(shí)就有問(wèn)題了:- 查詢緩存就會(huì)被愚弄了(它認(rèn)為
tbl1
沒(méi)有被更新,因此返回out-of-data結(jié)果)。 - 在
tbl2
上執(zhí)行ALTER
語(yǔ)句也會(huì)失敗。
- 查詢緩存就會(huì)被愚弄了(它認(rèn)為
7.6.1.3 在 Windows 上符號(hào)鏈接數(shù)據(jù)庫(kù)
從MySQL 3.23.16開(kāi)始,Windows上支持用 -DUSE_SYMDIR
選項(xiàng)編譯 mysqld-max
和 mysql-max-nt
服務(wù)器。這就可以通過(guò)符號(hào)鏈接把一個(gè)數(shù)據(jù)庫(kù)放在其他磁盤(pán)上。這跟在Unix上做符號(hào)鏈接相似,只是設(shè)置過(guò)程不大一樣而已。
從MySQL 4.0開(kāi)始,默認(rèn)支持符號(hào)鏈接。如果不需要,用 skip-symbolic-links
選項(xiàng)關(guān)閉它。
[mysqld]skip-symbolic-links
在MySQL 4.0以前,默認(rèn)不支持符號(hào)鏈接。想要支持它,就要在 `my.cnf' 或 `my.ini' 文件中增加如下內(nèi)容:
[mysqld]symbolic-links
在Windows上,在MySQL數(shù)據(jù)文件目錄下創(chuàng)建一個(gè)包含目標(biāo)目錄路徑的文件來(lái)做符號(hào)鏈接。這個(gè)文件的名字叫 `db_name.sym`,db_name 是數(shù)據(jù)庫(kù)的名字。
假設(shè)MySQL數(shù)據(jù)文件目錄是 `C:\mysql\data',現(xiàn)在想要把數(shù)據(jù)庫(kù) foo
放在 `D:\data\foo` 目錄下。按以下方法設(shè)置:
- 確認(rèn) `D:\data\foo` 目錄存在,如果有必要就創(chuàng)建它。如果在數(shù)據(jù)文件目錄下已經(jīng)存在一個(gè)數(shù)據(jù)庫(kù)目錄名為 `foo`,那么就把它移動(dòng)到下 `D:\data`。否則,符號(hào)鏈接就不生效。移動(dòng)數(shù)據(jù)庫(kù)的時(shí)候最好不要運(yùn)行服務(wù)器,以避免可能出現(xiàn)的問(wèn)題。
- 創(chuàng)建一個(gè)文件 `C:\mysql\data\foo.sym`,它的內(nèi)容是路徑
D:\data\foo\
。
之后,數(shù)據(jù)庫(kù) foo
下的所有表都會(huì)創(chuàng)建到
`D:\data\foo` 下。注意,如果在MySQL數(shù)據(jù)文件目錄下已經(jīng)存在該數(shù)據(jù)庫(kù)目錄,那么就不會(huì)使用符號(hào)鏈接了。