簡介
要明確表示你想要用一個MyISAM表格,請用ENGINE表選項指出來:
CREATE TABLE t (i INT) ENGINE = MYISAM;
注釋:老版本的MySQL使用TYPE而不是ENGINE(例如,TYPE = MYISAM)。MySQL 5.1為向下兼容而支持這個語法,但TYPE現在被輕視,而ENGINE是首先的用法。
一般地,ENGINE選項是不必要的;除非默認已經被改變了,InnoDB是默認存儲引擎(Mysql 5.1後)。
你可以用myisamchk工具來檢查或修復MyISAM表。請參閱MySQL 5.1參考手冊5.9.5.6節,“使用myisamchk做崩潰恢復”。你也可以用myisampack來壓縮MyISAM表,讓它們占更少的空間。請參閱MySQL 5.1參考手冊8.2節,“myisampack,產生壓縮、唯讀的MyISAM表”。
特徵
MyISAM存儲引擎的一些特徵
1. 所有數據值先存儲低位元組。這使得數據機和作業系統分離。二進制輕便性的唯一要求是機器使用補碼(如最近20年的機器有的一樣)和IEEE浮點格式(在主流機器中也完全是主導的)。唯一不支持二進制兼容性的機器是嵌入式系統。這些系統有時使用特殊的處理器。
先存儲數據低位元組並不嚴重地影響速度;數據行中的位元組一般是未聯合的,從一個方向讀未聯合的位元組並不比從反向讀更占用更多的資源。伺服器上的獲取列值的代碼與其它代碼相比並不顯得時間緊。
2.大檔案(達63位檔案長度)在支持大檔案的檔案系統和作業系統上被支持。
3. 當把刪除和更新及插入混合的時候,動態尺寸的行更少碎片。這要通過合併相鄰被刪除的塊,以及若下一個塊被刪除,就擴展到下一塊來自動完成。
7. NULL值被允許在索引的列中。這個占每個鍵的0-1個位元組。
8. 所有數字鍵值以高位元組為先被存儲以允許一個更高地索引壓縮。
9. 當記錄以排好序的順序插入(就像你使用一個AUTO_INCREMENT列之時),索引樹被劈開以便高節點僅包含一個鍵。這改善了索引樹的空間利用率。
10.每表一個AUTO_INCREMENT列的內部處理。MyISAM為INSERT和UPDATE操作自動更新這一列。這使得AUTO_INCREMENT列更快(至少10%)。在序列頂的值被刪除之後就不能再利用。(當AUTO_INCREMENT列被定義為多列索引的最後一列,可以出現重使用從序列頂部刪除的值的情況)。AUTO_INCREMENT值可用ALTER TABLE或myisamch來重置。
11. 如果數據檔案中間的表沒有自由塊了,在其它執行緒從表讀的同時,你可以INSERT新行到表中。(這被認識為並發操作)。自由塊的出現是作為刪除行的結果,或者是用比當前內容多的數據對動態長度行更新的結果。當所有自由塊被用完(填滿),未來的插入又變成並發。
12.你可以把數據檔案和索引檔案放在不同目錄,用DATA DIRECTORY和INDEX DIRECTORY選項CREATE TABLE以獲得更高的速度,請參閱13.1.5節,“CREATE TABLE語法”。
a.每個字元列可以有不同的字元集,請參閱第10章:“字元集支持”。
b.在MyISAM索引檔案里有一個標誌,它表明表是否被正確關閉。如果用--myisam-recover選項啟動mysqld,MyISAM表在打開得時候被自動檢查,如果被表被不恰當地關閉,就修復表。
c.如果你用--update-state選項運行myisamchk,它標註表為已檢查。myisamchk --fast只檢查那些沒有這個標誌的表。
d. myisamchk --analyze為部分鍵存儲統計信息,也為整個鍵存儲統計信息。
e. myisampack可以打包BLOB和VARCHAR列。
MyISAM也支持下列特徵
1.支持true VARCHAR類型;VARCHAR列以存儲在2個位元組中的長度來開始。
2.有VARCHAR的表可以有固定或動態記錄長度。
3. VARCHAR和CHAR列可以多達64KB。
4. 一個被搞亂的已計算索引對可對UNIQUE來使用。這允許你在表內任何列的合併上有UNIQUE。(儘管如此,你不能在一個UNIQUE已計算索引上搜尋)。
對MyISAM存儲引擎,有一個更詳細的論壇在
15.1.1. MyISAM啟動選項
下列對mysqld 的選項可用來改變MyISAM表的行為:
· --myisam-recover=mode
設定為崩潰MyISAM表自動恢復的模式。
· --delay-key-write=ALL
對任何MyISAM表的寫操作之間不要刷新鍵緩衝區。
注釋:如果你要這么做。當表在使用中之時,你應該不使用來自另一個程式的MyISAM表(比如從另一個MySQL伺服器或用myisamchk)。這么做會導致索引被破壞。
對使用--delay-key-write的表,使用--external-locking沒有幫助。
請參閱5.3.1節,“mysqld命令行選項”。
下列系統變數影響MyISAM表的行為:
· bulk_insert_buffer_size
用在塊插入最佳化中的樹緩衝區的大小。注釋:這是一個per thread的限制。
· (OBSOLETE) myisam_max_extra_sort_file_size
這個參數已經不在MySQL中使用。
· myisam_max_sort_file_size
如果臨時檔案會變得超過索引,不要使用快速排序索引方法來創建一個索引。注釋:這個參數以位元組的形式給出。
· myisam_sort_buffer_size
設定恢復表之時使用的緩衝區的尺寸。
請參閱5.3.3節,“伺服器系統變數”。
如果用--myisam-recover選項啟動mysqld,自動恢復被激活。在這種情況下,當伺服器打開一個MyISAM表之時,伺服器會檢查是否表被標註為崩潰,或者表的打開計數變數是否不為0且你正用--skip-external-locking運行伺服器。如果這些條件的任何一個為真,下列情況發生:
· 表被查錯。
· 如果伺服器發現一個錯誤,它試著做快速表修復(排序且不重新創建數據檔案)。
· 如果修復因為數據檔案中的一個錯誤而失敗(例如,一個重複鍵錯誤),伺服器會再次嘗試修復,這一次重建數據檔案。
· 如果修復仍然失敗,伺服器用舊修複選項方法再重試一次修復(一行接一行地寫,不排序)。這個方法應該能修復任何類型的錯誤,並且需要很低的磁碟空間。
如果恢復不能夠從先前完成的語句里恢復所有行,而且你不能在--myisam-recover選項值指定FORCE,自動修復會終止,並在錯誤日誌里寫一條錯誤信息:
Error: Couldn't repair table: test.g00pages
如果你指定FORCE,取而代之地,類似這樣的一個警告被給出:
Warning: Found 344 of 354 rows when repairing ./test/g00pages
注釋:如果自動恢復值包括BACKUP,恢復進程創建檔案並用tbl_name-datetime.BAK形式取名。你應該有一個cron腳本,它自動把這些檔案從資料庫目錄移到備份媒質上。
15.1.2.鍵所需的空間
MyISAM表使用B型樹索引。你可以粗略地計算索引檔案的大小為(key_length+4)/0.67, 加上所有的鍵之和。當所有鍵以排序的順序插入並且表沒有任何壓縮的鍵之時,以上估計是對最壞的情況的。
字元串索引是被空間壓縮的。如果第一個字元串索引部分是字元串,它也被加前綴壓縮。如果字元串列有許多拖曳空間,或字元串列是一個總是不用完全長度的VARCHAR列,空間壓縮使得索引檔案比最壞情況時的數值要小。前綴壓縮被用在以字元串開始的鍵上。如果有許多具有同一前綴的字元串,前綴壓縮是有幫助的。
在MyISAM表,你也可以在創建表的時候通過指定PACK_KEYS=1來前綴壓縮數字。當數字被以高位元組優先存儲之時,若你有許多具有同一前綴的整數鍵,上述方法是有幫助的。
存儲格式
MyISAM支持三種不同存儲格式。
其中兩個(固定格式和動態格式)根據正使用的列的類型來自動選擇。第三個,即已壓縮格式,只能使用myisampack工具來創建。
當你CREATE或ALTER一個沒有BLOB或TEXT列的表,你可以用ROW_FORMAT表選項強制表的格式為FIXED或DYNAMIC。這會導致CHAR和VARCHAR列因FIXED格式變成CHAR,或因DYNAMIC格式變成VARCHAR。
靜態表
(固定長度)
靜態格式是MyISAM表的默認存儲格式。當表不包含變數長度列(VARCHAR, BLOB, 或TEXT)時,使用這個格式。每一行用固定位元組數存儲。
MyISAM的三種存儲格式中,靜態格式就最簡單也是最安全的(至少對於崩潰而言)。靜態格式也是最快的on-disk格式。快速來自於數據檔案中的行在磁碟上被找到的容易方式:當按照索引中的行號查找一個行時,用行長度乘以行號。同樣,當掃描一個表的時候,很容易用每個磁碟讀操作讀一定數量的記錄。
當MySQL伺服器正往一個固定格式MyISAM檔案寫的時候,如果計算機崩潰了,安全是顯然的。在這種情況下,myisamchk可以容易地決定每行從哪裡開始到哪裡結束,所以它通常可以收回所有記錄,除了寫了一部分的記錄。注意,基於數據行,MyISAM表索引可以一直被重新構建。
靜態格式表的一般特徵:
· CHAR列對列寬度是空間填補的。
· 非常快。
· 容易快取。
· 崩潰後容易重建,因為記錄位於固定位置。
· 重新組織是不必要的,除非你刪除巨量的記錄並且希望為作業系統騰出磁碟空間。為此,可使用OPTIMIZE TABLE或者myisamchk -r。
· 通常比動態格式表需要更多的磁碟空間。
動態表
如果一個MyISAM表包含任何可變長度列(VARCHAR, BLOB或TEXTDynamic),或者如果一個表被用ROW_FORMAT=DYNAMIC選項來創建,動態存儲格式被使用。
這個格式更為複雜一點,因為每行有一個表明行有多長的頭。當一個記錄因為更新的結果被變得更長,該記錄也可以在超過一個位置處結束。
你可以使用OPTIMIZE TABLE或myisamchk來對一個表整理碎片。如果在一個表中有你頻繁訪問或改變的固定長度列,表中也有一些可變長度列,僅為避免碎片而把這些可變長度列移到其它表可能是一個好主意。
動態格式表的一般特徵:
· 除了長度少於4的列外,所有的字元串列是動態的。
· 在每個記錄前面是一個點陣圖,該點陣圖表明哪一列包含空字元串(對於字元串列)或者0(對於數字列)。注意,這並不包括包含NULL值的列。如果一個字元列在拖曳空間移除後長度為零,或者一個數字列為零值,這都在點陣圖中標註了且列不被保存到磁碟。 非空字元串被存為一個長度位元組加字元串的內容。
· 通常比固定長度表需要更少的磁碟空間。
· 每個記錄僅使用必需大小的空間。儘管如此,如果一個記錄變大,它就按需要被分開成多片,造成記錄碎片的後果。比如,你用擴展行長度的信息更新一行,該行就變得有碎片。在這種情況下,你可以時不時運行OPTIMIZE TABLE或myisamchk -r來改善性能。可使用myisamchk -ei來獲取表的統計數據。
· 動態格式表在崩潰後要比靜態格式表更難重建,因為一個記錄可能被分為多個碎片且連結(碎片)可能被丟失。
· 動態尺寸記錄期望的行長度用下列表達式來計算:
· 3
· + (number of columns + 7) / 8
· + (number of char columns)
· + (packed size of numeric columns)
· + (length of strings)
· + (number of NULL columns + 7) / 8
對每個連結需要額外的6位元組。在一個更新導致一個記錄的擴大之時,一個動態記錄被連結了。每個新連結至少是20位元組,所以下一個擴大可能在同樣的連結里進行。如果不是,則另一個連結將被建立。你可以使用myisamchk -ed來找出連結的數目。所有的連結可以用myisamchk -r來移除。
已壓縮表
已壓縮存儲格式是由myisampack工具創建的唯讀格式。
所有MySQL分發版里都默認包括myisampack。已壓縮表可以用myisamchk來解壓縮。
已壓縮表有下列特徵:
· 已壓縮表占據非常小的磁碟空間。這最小化了磁碟用量,當使用緩慢的磁碟(如CD-ROM)之時,這是很有用的。
· 每個記錄是被單獨壓縮的,所以只有非常小的訪問開支。依據表中最大的記錄,一個記錄的頭在每個表中占據1到3個位元組。每個列被不同地壓縮。通常每個列有一個不同的Huffman樹。一些壓縮類型如下:
o 後綴空間壓縮。
- 前綴空間壓縮。
- 零值的數用一個位來存儲。
- 如果在一個整型列中的值有一個小的範圍,列被用最小可能的類型來存儲。比如,一個BIGINT列(8位元組),如果所有它的值在-128到127範圍內,它可以被存儲為TINYINT列(1位元組)
- 如果一個列僅有一小組可能的值,列的類型被轉化成ENUM。
- 一個列可以使用先前壓縮類型的任意合併。
· 可以處理固定長度或動態長度記錄。
問題
MySQL用來存儲數據的檔案格式已經被廣泛測試過,但總是有導致數據表變得損壞的環境。
損壞的MyISAM表
即使MyISAM表格式非常可靠(SQL語句對表做的所有改變在語句返回之前被寫下),如果下列任何事件發生,你依然可以獲得損壞的表:
· mysqld進程在寫中間被殺掉。
· 發生未預期的計算機關閉(例如,計算機被關閉)。
· 硬體故障。
· 你可以同時在正被伺服器修改的表上使用外部程式(如myisamchk)。
· MySQL或MyISAM代碼的軟體缺陷。
一個損壞的表的典型症狀如下:
· 當在從表中選擇數據之時,你得到如下錯誤:
· Incorrect key file for table: '...'. Try to repair it
· 查詢不能在表中找到行或返回不完全的數據。
你可以用CHECK TABLE statement語句來檢查MyISAM表的健康,並用REPAIR TABLE修復一個損壞的MyISAM表。當mysqld不運行之時,你也可以用myisamchk命令檢查或修理一個表。請參閱13.5.2.3節,“CHECK TABLE語法”, 13.5.2.6節,“REPAIR TABLE語法”,和5.9.5節,“myisamchk — MyISAM表維護工具”。
如果你的表變得頻繁損壞,你應該試著確定為什麼會這樣的原因。要明白的最重要的事是表變得損壞是不是因為伺服器崩潰的結果。你可以在錯誤日誌中查找最近的restarted mysqld訊息來早期驗證這個。如果存在這樣一個訊息,則表損壞是伺服器死掉的一個結果是很有可能的。否則,損壞可能在正常操作中發生。這是一個缺陷。你應該試著創建一個展示這個問題的可重複生成的測試案例。請參閱A.4.2節,“如果MySQL保持崩潰,該怎么做” 及E.1.6節,“如果出現表崩潰,請生成測試案例”。
未被適當關閉的表的問題
每個MyISAM索引檔案(.MYI)在頭有一個計數器,它可以被用來檢查一個表是否被恰當地關閉。如果你從CHECK TABLE或myisamchk得到下列警告,意味著這個計數器已經不同步了:
clients are using or haven't closed the table properly
這個警告並不是完全意味著表已被破壞,但你至少應該檢查表。
計數器的工作方式如下:
· 表在MySQL中第一次被更新,索引檔案頭的計數器加一。
· 在未來的更新中,計數器不被改變。
· 當表的最後實例被關閉(因為一個操作FLUSH TABLE或因為在表緩衝區中沒有空間)之時,若表已經在任何點被更新,則計數器減一。
· 當你修理或檢查表並且發現表完好之時,計數器被重置為零。
· 要避免與其它可能檢查表的進程進行事務的問題,若計數器為零,在關閉時計數器不減一。
換句話來說,計數器只有在下列情況會不同步:
· MyISAM表不隨第一次發出的LOCK TABLES和FLUSH TABLES被複製。
· MySQL在一次更新和最後關閉之間崩潰(注意,表可能依然完好,因為MySQL總是在每個語句之間為每件事發出寫操作)。
· 一個表被myisamchk --recover或myisamchk --update-state修改,同時被mysqld使用。
· 多個mysqld伺服器正使用表,並且一個伺服器在一個表上執行REPAIR TABLE或CHECK TABLE,同時該表也被另一個伺服器使用。在這個結構中,使用CHECK TABLE是安全的,雖然你可能從其它伺服器上得到警告。儘管如此,REPAIR TABLE應該被避免,因為當一個伺服器用一個新的數據檔案替代舊的之時,這並沒有傳送信號到其它伺服器上。
總的來說,在多伺服器之間分享一個數據目錄是一個壞主意。