15章:儲存引擎和資料表類型

目錄

15.1. MyISAM儲存引擎

15.1.1. MyISAM啟動選項

15.1.2.鍵所需的空間

15.1.3. MyISAM資料表的儲存格式

15.1.4. MyISAM資料表的問題

15.2. InnoDB儲存引擎

15.2.1. InnoDB概述

15.2.2. InnoDB聯繫訊息

15.2.3. InnoDB配置

15.2.4. InnoDB啟動選項

15.2.5. 建立InnoDB資料表空間

15.2.6. 建立InnoDB資料表

15.2.7. 新增和刪除InnoDB數據和日誌檔案

15.2.8. InnoDB資料庫的備份和恢復

15.2.9. InnoDB資料庫移到另一台機器

15.2.10. InnoDB事務模型和鎖定

15.2.11. InnoDB性能調節提示

15.2.12. 多版本的實施

15.2.13. 資料表和索引結構

15.2.14.文件空間管理和磁盤I/O

15.2.15. InnoDB錯誤處理

15.2.16. InnoDB資料表的限制

15.2.17. InnoDB故障診斷和排除

15.3. MERGE儲存引擎

15.3.1. MERGE資料表 方面的問題

15.4. MEMORY(HEAP)儲存引擎

15.5. BDB(BerkeleyDB)儲存引擎

15.5.1. BDB支援的作業系統

15.5.2. 安裝BDB

15.5.3. BDB啟動選項

15.5.4. BDB資料表的特性

15.5.5. 修改BDB所需的事宜

15.5.6. BDB資料表的限制

15.5.7. 使用BDB資料表時可能 出現的錯誤

15.6. EXAMPLE儲存引擎

15.7. FEDERATED儲存引擎

15.7.1. 安裝FEDERATED儲存引擎

15.7.2. FEDERATED儲存引擎的介紹

15.7.3. 如何使用FEDERATED資料表

15.7.4. FEDERATED儲存引擎的局限

15.8. ARCHIVE儲存引擎

15.9. CSV儲存引擎

15.10.BLACKHOLE儲存引擎

MySQL支援數個儲存引擎作為對不同資料表的類型的處理器。MySQL儲存引擎包括處理事務安全資料表的引擎和處理非事務安全資料表的引擎:

·         MyISAM管理非事務資料表。它提供高速儲存和檢索,以及全文搜索能力。MyISAM在所有MySQL配置裡被支援,它是預設的儲存引擎,除非您配置MySQL預設使用另外一個引擎。

·         MEMORY儲存引擎提供「內存中」資料表。MERGE儲存引擎允許集合將被處理同樣的MyISAM資料表作為一個單獨的資料表。就像MyISAM一樣,MEMORY和MERGE儲存引擎處理非事務資料表,這兩個引擎也都被 預設包含在MySQL中。

註釋:MEMORY儲存引擎正式地被確定為HEAP引擎。

·         InnoDB和BDB儲存引擎提供事務安全資料表。BDB被包含在為支援它的作業系統發佈的MySQL-Max二進制分發版裡。InnoDB也 預設被包括在所有MySQL 5.1二進制分發版裡,您可以按照喜好通過配置MySQL來允許或禁止任一引擎。

·         EXAMPLE儲存引擎是一個“存根”引擎,它不做什麼。您可以用這個引擎建立資料表,但沒有數據被儲存於其中或從其中檢索。這個引擎的目的是服務 ,在MySQL源代碼中的一個例子,它演示說明如何開始編寫新儲存引擎。同樣,它的主要興趣是對開發者

·         NDB Cluster是被MySQL Cluster用來實現分割到多台計算機上的資料表的儲存引擎。它在MySQL-Max 5.1二進制分發版裡提供。這個儲存引擎當前只被Linux, Solaris, 和Mac OS X 支援。在未來的MySQL分發版中,我們想要新增其它平台對這個引擎的支援,包括Windows。

·         ARCHIVE儲存引擎被用來無索引地,非常小覆蓋儲存的大量數據。

·         CSV儲存引擎把數據以逗號分隔的格式儲存在文本檔案中。

·         BLACKHOLE儲存引擎接受但不儲存數據,並且檢索總是返回一個空集。

·         FEDERATED儲存引擎把數據存在遠程資料庫中。在MySQL 5.1中,它只和MySQL一起工作,使用MySQL C Client API。在未來的分發版中,我們想要讓它使用其它驅動器或客戶端連接方法連接到另外的數據源。

尋求選擇一個儲存引擎的幫助,請參閱14.4節,「選擇一個儲存引擎”

這一章講述除NDB Cluster外的每一個MySQL儲存引擎,NDB Cluster在第17章:MySQL Cluster中介紹。

當年建立一個新資料表的時候,您可以通過新增一個ENGINE 或TYPE 選項到CREATE TABLE語句來告訴MySQL您要建立什麼類型的資料表:

CREATE TABLE t (i INT) ENGINE = INNODB;
CREATE TABLE t (i INT) TYPE = MEMORY;

雖然TYPE仍然在MySQL 5.1中被支援,現在ENGINE是首選的術語。

如果您省略掉ENGINE或TYPE選項,預設的儲存引擎被使用。一般的預設是MyISAM,但您可以用--default-storage-engine或--default-table-type伺服器啟動選項來改變它,或者通過設置storage_engine或table_type系統變數來改變。

當MySQL被用MySQL配置嚮導安裝在Windows平台上,InnoDB儲存引擎替代MyISAM儲存引擎作為替代,請參閱2.3.5.1節,「介紹”

要把一個資料表從一個類型轉到另一個類型,可使用ALTER TABLE語句,這個語句指明新的類型:

ALTER TABLE t ENGINE = MYISAM;
ALTER TABLE t TYPE = BDB;

請參閱13.1.5節,「CREATE TABLE語法”13.1.2節,「ALTER TABLE語法”

如果您試著使用一個未被編譯進MySQL的儲存引擎,或者試著用一個被編譯進MySQL但沒有被激活的儲存引擎,MySQL取而代之地建立一個MyISAM類型的資料表。當您在支援不同儲存引擎的MySQL伺服器之間拷貝資料表的時候,上述的行為是很方便的。(例如,在一個複製建立中,可能您的主伺服器為增加安全而支援 事務儲存引擎,但從伺服器為更快的速度而僅使用非事務儲存引擎。)

在不可用的類型被指定時,自動用MyISAM資料表來替代,這會對MySQL的新用戶造成混淆。無論何時一個資料表被自動改變之時,產生一個警告。

MySQL總是建立一個.frm檔案來保持資料表和列的定義。資料表的索引和數據可能被儲存在一個或多個檔案裡,這取決於資料表的類型。伺服器在儲存引擎級別之上建立.frm檔案。單獨的儲存引擎建立任何需要用來管理資料表的額外檔案。

一個資料庫可以包含不同類型的資料表。

事務安全資料表(TST) 比起非事務安全資料表 (NTST)有幾大優勢:

·         更安全。即使MySQL崩潰或遇到硬件問題,要麼自動恢復,要麼從備份加事務日誌恢復,您可以取回數據。

·         您可以合併許多語句,並用COMMIT語句同時接受它們全部(如果autocommit被禁止掉)。

·         您可以執行ROLLBACK來忽略您的改變(如果autocommit被禁止掉)。

·         如果更新失敗,您的所有改變都變回原來。(用非事務安全資料表,所有發生的改變都是永久的)。

·         事務安全儲存引擎可以給那些當前用讀得到許多更新的資料表提供更好的部署。

雖然MySQL支援數個事務安全儲存引擎,為獲得最好結果,您不應該在一個事務那混合不同資料表類型。如果您混合資料表類型會發生問題,更多訊息請參閱13.4.1節,「START TRANSACTION, COMMIT和ROLLBACK Syntax”

如果您沒有指定配置值的話,InnoDB使用預設的配置值。請參閱15.2.3節,「InnoDB配置”

非事務安全資料表自身有幾個優點,因為沒有事務開支,所有優點都能出現:

·         更快

·         需要更少的磁盤空間

·         執行更新需要更少的內存

您可以在同一個語句中合併事務安全和非事務安全資料表來獲得兩者最好的情況。儘管如此,在autocommit被禁止掉的事務裡,變換到非事務安全資料表依舊即時提交,並且不會被回滾。

15.1. MyISAM儲存引擎

15.1.1. MyISAM啟動選項

15.1.2.鍵需要的空間

15.1.3. MyISAM資料表儲存格式

15.1.4. MyISAM資料表的問題

MyISAM是 預設儲存引擎。它基於更老的ISAM代碼,但有很多有用的延伸。(注意MySQL 5.1不支援ISAM)。

每個MyISAM在磁盤上儲存成三個檔案。第一個檔案的名字以資料表的名字開始,延伸名指出檔案類型。.frm檔案儲存資料表定義。數據檔案的延伸名為.MYD (MYData)。索引檔案的延伸名是.MYI (MYIndex)。

要明確資料表示您想要用一個MyISAM資料表格,請用ENGINE資料表選項指出來:

CREATE TABLE t (i INT) ENGINE = MYISAM;

註釋:老版本的MySQL使用TYPE而不是ENGINE(例如,TYPE = MYISAM)。MySQL 5.1為向下兼容而支援這個語法,但TYPE現在被輕視,而ENGINE是首先的用法。

一般地,ENGINE選項是不必要的;除非預設已經被改變了,MyISAM是預設儲存引擎。

您可以用myisamchk工具來檢查或修復MyISAM資料表。請參閱5.9.5.6節,「使用myisamchk做崩潰恢復”。您也可以用myisampack來壓縮MyISAM資料表,讓它們占更少的空間。請參閱8.2節,「myisampack,產生壓縮、只讀的MyISAM資料表”

如下是MyISAM儲存引擎的一些特徵:

·         所有數據值先儲存低字節。這使得數據機和作業系統分離。二進制輕便性的唯一要求是機器使用補碼(如最近20年的機器有的一樣)和IEEE浮點格式(在主流機器中也完全是主導的)。唯一不支援二進制相容性的機器是嵌入式系統。這些系統有時使用特殊的處理器。

先儲存數據低字節並不嚴重地影響速度;數據行中的字節一般是未聯合的,從一個方向讀未聯合的字節並不比從反向讀更佔用更多的資源。伺服器上的獲取列值的代碼與其它代碼相比並不顯得時間緊。

·        大檔案(達63位檔案長度)在支援大檔案的檔案系統和作業系統上被支援。

·         當把刪除和更新及插入混合的時候,動態尺寸的行更少碎片。這要通過合併相鄰被刪除的塊,以及若下一個塊被刪除,就延伸到下一塊來自動完成。

·         每個MyISAM資料表最大索引數是64。 這可以通過重新編譯來改變。每個索引最大的列數是16個。

·         最大的鍵長度是1000字節。這也可以通過編譯來改變。對於鍵長度超過250字節的情況,一個超過1024字節的的鍵塊被用上。

·         BLOB和TEXT列可以被索引。

·         NULL值被允許在索引的列中。這個占每個鍵的0-1個字節。

·         所有數字鍵值以高字節為先被儲存以允許一個更高地索引壓縮。

·        當記錄以排好序的順序插入(就像您使用一個AUTO_INCREMENT列之時),索引樹被劈開以便高節點僅包含一個鍵。這改善了索引樹的空間利用率。

·         每資料表一個AUTO_INCREMEN列的內部處理。MyISAM為INSERT和UPDATE操作自動更新這一列。這使得AUTO_INCREMENT列更快(至少10%)。在序列頂的值被刪除之後就不能再利用。(當AUTO_INCREMENT列被定義為多列索引的最後一列,可以出現重使用從序列頂部刪除的值的情況 )。AUTO_INCREMENT值可用ALTER TABLE或myisamch來重置。

·         如果數據檔案中間的資料表沒有自由塊了,在其它線程從資料表讀的同時,您可以INSERT新行到資料表中。(這被認識為並發操作 )。自由塊的出現是作為刪除行的結果,或者是用比當前內容多的數據對動態長度行更新的結果。當所有自由塊被用完(填滿),未來的插入又變成並發。

·         您可以把數據檔案和索引檔案放在不同目錄,用DATA DIRECTORY和INDEX DIRECTORY選項CREATE TABLE以獲得更高的速度,請參閱13.1.5節,「CREATE TABLE語法”

·         每個字元列可以又不同的字元編碼,請參閱第10章 :「字元編碼支援」

·         在MyISAM索引檔案裡又一個標誌,它表明資料表是否被正確關閉。如果用--myisam-recover選項啟動mysqld,MyISAM資料表在打開得時候被自動檢查,如果被資料表被不恰當地關閉,就修復資料表。

·         如果您用--update-state選項運行myisamchk,它標注資料表為已檢查。myisamchk --fast只檢查那些沒有這個標誌的資料表。

·         myisamchk --analyze為部分鍵儲存統計訊息,也為整個鍵儲存統計訊息。

·         myisampack可以打包BLOB和VARCHAR列。

MyISAM也支援下列特徵:

·         支援true VARCHAR類型;VARCHAR列以儲存在2個字節中的長度來開始。

·         有VARCHAR的資料表可以有固定或動態記錄長度。

·         VARCHAR和CHAR列可以多達64KB。

·         一個被搞亂的已計算索引對可對UNIQUE來使用。這允許您在資料表內任何列的合併上有UNIQUE。(儘管如此,您不能在一個UNIQUE已計算索引上搜索)。

對MyISAM儲存引擎,有一個更詳細的論壇在http://forums.mysql.com/list.php?21

15.1.1MyISAM啟動選項

下列對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來前綴壓縮數字。當數字被以高字節優先儲存之時,若您有許多具有同一前綴的整數 鍵,上述方法是有幫助的。

15.1.3MyISAM資料表的儲存格式

15.1.3.1. 靜態(固定長度)資料表特徵

15.1.3.2. 動態資料表特徵

15.1.3.3. 已壓縮資料表特徵

MyISAM支援三種不同儲存格式。其中兩個(固定格式和動態格式)根據正使用的列的類型來自動選擇。第三個,即已壓縮格式,只能使用myisampack工具來建立。

當您CREATE或ALTER一個沒有BLOB或TEXT列的資料表,您可以用ROW_FORMAT資料表選項強製表的格式為FIXED或DYNAMIC。這 會導致CHAR和VARCHAR列因FIXED格式變成CHAR,或因DYNAMIC格式變成VARCHAR。

通過用ALTER TABLE指定ROW_FORMAT={COMPRESSED | DEFAULT},您可以壓縮或解壓縮資料表,請參閱13.1.5節,「CREATE TABLE語法”

15.1.3.1. 靜態(固定長度)資料表特徵

靜態格式是MyISAM資料表的預設儲存格式。當資料表不包含變數長度列(VARCHAR, BLOB, 或TEXT)時,使用這個格式。每一行用固定字節數儲存。

MyISAM的三種儲存格式中,靜態格式就最簡單也是最安全的(至少對於崩潰而言)。靜態格式也是最快的on-disk格式。快速來自於數據檔案中的行在磁盤上被找到的容易方式:當按照索引中的行號搜尋一個行時,用行長度乘以行號。同樣,當掃瞄一個資料表的 時候,很容易用每個磁盤讀操作讀一定數量的記錄。

當MySQL伺服器正往一個固定格式MyISAM檔案寫的時候,如果計算機崩潰了,安全是顯然的。在這種情況下,myisamchk可以容易地決定每行從哪裡開始到哪裡結束,所以它通常可以收回所有記錄,除了寫了一部分的記錄。注意,基於數據行,MyISAM資料表索引可以一直被重新構建。

靜態格式資料表的一般特徵:

·         CHAR列對列寬度是空間填補的。

·         非常快。

·         容易緩存。

·         崩潰後容易重建,因為記錄位於固定位置。

·         重新組織是不必要的,除非您刪除巨量的記錄並且希望為作業系統騰出磁盤空間。為此,可使用OPTIMIZE TABLE或者myisamchk -r

·         通常比動態格式資料表需要更多的磁盤空間。

15.1.3.2. 動態資料表特徵

如果一個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來移除。

15.1.3.3. 已壓縮資料表特徵

已壓縮儲存格式是由myisampack工具建立的只讀格式。

所有MySQL分發版裡都預設包括myisampack。已壓縮資料表可以用myisamchk來解壓縮。

已壓縮資料表有下列特徵:

·         已壓縮資料表佔據非常小的磁盤空間。這最小化了磁盤用量,當使用緩慢的磁盤(如CD-ROM)之時,這是很有用的。

·         每個記錄是被單獨壓縮的,所以只有非常小的訪問開支。依據資料表中最大的記錄,一個記錄的頭在每個資料表中佔據1到3個字節。每個 列被不同地壓縮。通常每個列有一個不同的Huffman樹。一些壓縮類型如下:

o        後綴空間壓縮。

-        前綴空間壓縮。

-        零值的數用一個位來儲存。

-        如果在一個整型列中的值有一個小的範圍,列被用最小可能的類型來儲存。比如,一個BIGINT列(8字節),如果所有它的值在-128到127範圍內,它可以被儲存為TINYINT列(1字節)

-        如果一個 列僅有一小組可能的值,列的類型被轉化成ENUM。

-        一個 列可以使用先前壓縮類型的任意合併。

·         可以處理固定長度或動態長度記錄。

15.1.4MyISAM資料表 方面的問題

15.1.4.1. 損壞的MyISAM資料表

15.1.4.2. 未被適當關閉的資料表的問題

MySQL用來儲存數據的檔案格式已經被廣泛測試過,但總是有導致數據資料表變得損壞的環境。

15.1.4.1. 損壞的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節,「如果出現資料表崩潰,請生成測試案例”

15.1.4.2. 未被適當關閉的資料表的問題

每個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 --recovermyisamchk --update-state修改,同時被mysqld使用。

·         多個mysqld伺服器正使用資料表,並且一個伺服器在一個資料表上執行REPAIR TABLE或CHECK TABLE,同時該資料表也被另一個伺服器使用。在這個結構中,使用CHECK TABLE是安全的,雖然您可能從其它伺服器上得到警告。儘管如此,REPAIR TABLE應該被避免,因為當一個伺服器用一個新的數據檔案替代舊的之時,這並沒有發送信號到其它伺服器上。

總的來說,在多伺服器之間分享一個數據目錄是一個壞主意。請參閱5.12節,「在同一個機器上運行多個MySQL伺服器” 獲得更多地討論

15.2. InnoDB儲存引擎

15.2.1. InnoDB概述

15.2.2. InnoDB聯繫訊息

15.2.3. InnoDB配置

15.2.4. InnoDB啟動選項

15.2.5. 建立InnoDB資料表空間

15.2.6. 建立InnoDB資料表

15.2.7. 新增和刪除InnoDB數據和日誌檔案

15.2.8. InnoDB資料庫的備份和恢復atabase

15.2.9. InnoDB資料庫移到另一台機器上

15.2.10. InnoDB事務模型和鎖定

15.2.11. InnoDB性能調節提示

15.2.12. 多版本的實施

15.2.13. 資料表和索引結構

15.2.14.文件空間管理和磁盤I/O

15.2.15. InnoDB錯誤處理

15.2.16. InnoDB資料表的限制

15.2.17. InnoDB故障診斷和排除

15.2.1InnoDB概述

InnoDB給MySQL提供 了具有提交,回滾和崩潰恢復能力的事務安全(ACID兼容)儲存引擎。InnoDB鎖定在行級並且也在SELECT語句提供一個Oracle風格一致的非鎖定讀。這些特色增加 了多用戶部署和性能。沒有在InnoDB中擴大鎖定的需要,因為在InnoDB中行級鎖定適合非常小的空間。InnoDB也支援FOREIGN KEY強制。在SQL查詢中,您可以自由地將InnoDB類型的資料表與其它MySQL的資料表的類型混合起來,甚至在同一個查詢中也可以混合。

InnoDB是為處理巨大數據量時的最大性能設計。它的CPU效率可能是任何其它基於磁盤的關係資料庫引擎所不能匹敵的。

InnoDB儲存引擎被完全與MySQL伺服器整合,InnoDB儲存引擎為在主內存中緩存數據和索引而維持它自己的緩衝池。InnoDB儲存它的資料表&索引在一個資料表空間中,資料表空間可以包含數個檔案(或原始磁盤分區)。這與MyISAM資料表不同,比如在MyISAM資料表中每個資料表被存在分離的檔案中。InnoDB 資料表可以是任何尺寸,即使在檔案尺寸被限制為2GB的作業系統上。

InnoDB預設地被包含在MySQL二進制分發中。Windows Essentials installer使InnoDB成為Windows上MySQL的 預設資料表。

InnoDB被用來在眾多需要高性能的大型資料庫站點上產生。著名的Internet新聞站點Slashdot.org運行在InnoDB上。Mytrix, Inc.在InnoDB上儲存超過1TB的數據,還有一些其它站點在InnoDB上處理平均每秒800次插入/更新的負荷。

InnoDB在和MySQL一樣在同一個GNU GPL證書,第2版(1991年6月版)下發行。更多有關MySQL證書的訊息,請參閱http://www.mysql.com/company/legal/licensing/

關於InnoDB儲存引擎,在http://forums.mysql.com/list.php?22有一個詳細的論壇。

15.2.2InnoDB聯繫訊息

InnoDB引擎的廠家的聯繫訊息,Innobase Oy的聯繫方式如下:

Web site: http://www.innodb.com/
Email: <sales@innodb.com>
Phone: +358-9-6969 3250 (office)
       +358-40-5617367 (mobile)
 
Innobase Oy Inc.
World Trade Center Helsinki
Aleksanterinkatu 17
P.O.Box 800
00101 Helsinki
Finland

15.2.3InnoDB配置

InnoDB儲存引擎是預設地被允許的。如果您不想用InnoDB資料表,您可以新增skip-innodb選項到MySQL選項檔案。

被InnoDB儲存引擎管理的兩個重要的基於磁盤的資源是InnoDB資料表空間數據檔案和它的日誌檔案。

如果您指定無InnoDB配置選項,MySQL將在MySQL數據目錄下建立一個名為ibdata1的10MB大小的自動延伸數據檔案,以及兩個名為ib_logfile0和ib_logfile1的5MB大小的日誌檔案。

註釋:InnoDB給MySQL提供具有提交, 回滾和崩潰恢復能力的事務安全(ACID兼容)儲存引擎。如果擬運行的作業系統和硬件不能如廣告說的那樣運行,InnoDB就不能實現如上能力。許多作業系統或磁盤子系統可能為改善性能而延遲或記錄寫操作。在一些作業系統上,就是系統使用(fsync()) 也要等著,直到所有未寫入已被刷新檔案的數據在被刷新到穩定內存之前可以確實返回了。因為這個,作業系統崩潰或掉電可能損壞當前提交的數據,或者在最壞的 情況,因為寫操作已被記錄了,甚至破壞了資料庫。如果數據完整性對您很重要,您應該在用任何程式於生產中之前做一些“pull-the-plug”測試。Mac OS X 10.3 及以後版本,InnoDB使用一個特別的fcntl()檔案 刷新方法。在Linux下,建議禁止回寫緩存。

在ATAPI硬盤上,一個類似hdparm -W0 /dev/hda命令可能起作用。小心某些驅動器或者磁盤控制器可能不能禁止回寫緩存。

註釋:要獲得好的性能,您應該如下面例子所討論那樣,明確提供InnoDB參數。自然地,您應該編輯設置來適合您的硬件和要求。

要建立InnoDB資料表空間檔案,在my.cnf選項檔案裡的[mysqld]節裡使用innodb_data_file_path選項。在Windows上,您可以替代地使用my.ini檔案。innodb_data_file_path的值應該為一個或多個 數據檔案規格的列資料表。如果您命名一個以上的數據檔案,用 分號(‘;’)分隔它們:

innodb_data_file_path=datafile_spec1[;datafile_spec2]...

例如:把明確建立的具有相同特徵的資料表空間作為預設設置的設置操作如下:

[mysqld]
innodb_data_file_path=ibdata1:10M:autoextend

這個設置配置一個可延伸大小的尺寸為10MB的單獨檔案,名為ibdata1。沒有給出檔案的位置,所以預設的是在MySQL的數據目錄內。

尺寸大小用M或者G後綴來指定說明單位是MB或者GB。

一個資料表空間,它在數據目錄裡包含一個名為ibdata1的固定尺寸50MB的數據檔案和一個名為ibdata2大小為50MB的自動延伸檔案,其可以 像這樣被配置:

[mysqld]
innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend

一個指定數據檔案的完全後綴包括檔案名,它的尺寸和數個可選屬性:

file_name:file_size[:autoextend[:max:max_file_size]]

autoextend屬性和後面跟著的屬性只可被用來對innodb_data_file_path行裡最後一個數據檔案。

如果您對最後的數據檔案指定autoextend選項。如果數據檔案耗盡了資料表空間中的自由空間,InnoDB就延伸數據檔案。延伸的幅度是每次8MB。

如果磁盤已滿,您可能想要把其它數據新增到另一個硬盤上。重新配置一個已存在資料表空間的指令見15.2.7節,「新增和刪除InnoDB數據和日誌檔案”

InnoDB並不感知最大檔案尺寸,所以要小心檔案系統,在那上面最大的檔案尺寸是2GB。要為一個自動延伸數據檔案指定最大尺寸,請使用max屬性。下列配置允許ibdata1漲到極限的500MB:

[mysqld]
innodb_data_file_path=ibdata1:10M:autoextend:max:500M

InnoDB預設地在MySQL數據目錄建立資料表空間檔案。要明確指定一個位置,請使用innodb_data_home_dir選項。比如,要使用兩個名為ibdata1和ibdata2的檔案,但是要把他們建立到/ibdata, 像如下一樣配置InnoDB:

[mysqld]
innodb_data_home_dir = /ibdata
innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend

註釋:InnoDB不建立目錄,所以在啟動伺服器之前請確認/ibdata目錄的確存在。這對您配置的任何日誌檔案目錄來說也是真實的。使用Unix或DOS的mkdir命令來建立任何必需的目錄。

通過把innodb_data_home_dir的值原原本本地部署到數據檔案名,並在需要的地方新增斜槓或反斜槓,InnoDB為每個數據檔案形成目錄路徑。如果innodb_data_home_dir選項根本沒有在my.cnf中提到, 預設值是“dot”目錄 ./,這意思是MySQL數據目錄。

如果您指定innodb_data_home_dir為一個空字串,您可以為列在innodb_data_file_path值裡的數據檔案指定絕對路徑。下面的例子等價於前面那個例子:

[mysqld]
innodb_data_home_dir =
innodb_data_file_path=/ibdata/ibdata1:50M;/ibdata/ibdata2:50M:autoextend

一個簡單的my.cnf例子。假設您有一台配備128MB內存和一個硬盤的計算機。下面的例子顯示在my.cnf或my.ini裡對InnoDB可能的配置參數,包括autoextend屬性。

這個例子適合大多數在Unix和Windows上,不想分配InnoDB數據檔案和日誌檔案到數個磁盤上的用戶。它在MySQL數據目錄建立一個自動延伸數據檔案ibdata1和兩個日誌檔案ib_logfile0及ib_logfile1。同樣,InnoD在數據目錄裡自動建立的小型檔案InnoDB日誌檔案ib_arch_log_0000000000也結束。

[mysqld]
# You can write your other MySQL server options here
# ...
# Data files must be able to hold your data and indexes.
# Make sure that you have enough free disk space.
innodb_data_file_path = ibdata1:10M:autoextend
#
# Set buffer pool size to 50-80% of your computer's memory
set-variable = innodb_buffer_pool_size=70M
set-variable = innodb_additional_mem_pool_size=10M
#
# Set the log file size to about 25% of the buffer pool size
set-variable = innodb_log_file_size=20M
set-variable = innodb_log_buffer_size=8M
#
innodb_flush_log_at_trx_commit=1

請確認MySQL伺服器有適當的權限在數據目錄裡建立檔案。更一般地,伺服器必須對任何它需要建立數據檔案或日誌檔案的目錄有訪問權限。

注意,在一些檔案系統上,數據檔案必需小於2GB。數據檔案的合併尺寸必須至少10MB。

當您第一次建立一個InnoDB資料表空間,最好從命令行來啟動MySQL伺服器。InnoDB然後把資料庫建立的訊息打印到屏幕,所以您可以看見正在發生什麼。比如,在Windows上,如果mysqld-max位於C:\mysql\bin,您可以如下來啟動它:

C:\> C:\mysql\bin\mysqld-max --console

如果您不發送伺服器輸出到屏幕上,請檢查伺服器的錯誤日誌來看在啟動過程中InnoDB打印了什麼。

請參閱15.2.5節,「建立InnoDB資料表空間”,以獲得InnoDB顯示的訊息看起來應該 像什麼的例子。

Windows上如何指定選項? 在Windows上選項檔案的規則如下:

·         只應該建立一個my.cnf或檔案。

·         my.cnf檔案應該被放在C盤根目錄。

·         my.ini檔案應該被放置在WINDIR目錄;例如C:\WINDOWS或C:\WINNT。您可以在Windows控制台的命令提示符使用SET命令來打印WINDIR的值:

·                C:\> SET WINDIR
·                windir=C:\WINNT

·         如果您的PC在C盤不是啟動盤的地方使用啟動裝載機,您唯一的選擇是使用my.ini檔案。

·         如果您使用安裝和配置嚮導安裝的MySQL,my.ini檔案被放在MySQL的安裝目錄。請參閱2.3.5.14節,「my.ini檔案的位置”

Unix上在哪裡指定選項? 在Unix上,mysqld從下列檔案,如果它們存在的話。以下列的順序讀取選項:

·         /etc/my.cnf

全局選項。

·         $MYSQL_HOME/my.cnf

伺服器專用選項。

·         defaults-extra-file

--defaults-extra-file選項指定的檔案。

·         ~/.my.cnf

用戶專用選項。

MYSQL_HOME代資料表環境變數,它內含著到包含伺服器專用my.cnf檔案的目錄的路徑。

如果您確信mysqld只從指定檔案讀取選項,您可以在啟動伺服器之時在命令行使用--defaults-option作為第一個選項:

mysqld --defaults-file=your_path_to_my_cnf

一個高級的my.cnf例子。假設您有一台Linux計算機,有2GB內存和三個60GB硬盤(在目錄路徑/, /dr2和/dr3)。下列例子顯示 了在my.cnf裡對InnoDB可能的配置參數。

[mysqld]
# You can write your other MySQL server options here
# ...
innodb_data_home_dir =
#
# Data files must be able to hold your data and indexes
innodb_data_file_path = /ibdata/ibdata1:2000M;/dr2/ibdata/ibdata2:2000M:autoextend
#
# Set buffer pool size to 50-80% of your computer's memory,
# but make sure on Linux x86 total memory usage is < 2GB
innodb_buffer_pool_size=1G
innodb_additional_mem_pool_size=20M
innodb_log_group_home_dir = /dr3/iblogs
#
innodb_log_files_in_group = 2
#
# Set the log file size to about 25% of the buffer pool size
innodb_log_file_size=250M
innodb_log_buffer_size=8M
#
innodb_flush_log_at_trx_commit=1
innodb_lock_wait_timeout=50
#
# Uncomment the next lines if you want to use them
#innodb_thread_concurrency=5

注意,該例子把兩個數據檔案放在不同磁盤上。InnoDB開始用第一個數據檔案填充資料表空間。在一些情況下,如果所有數據不被放置在同一物理磁盤上,這樣將改善資料庫的性能。把日誌檔案放在與數據檔案不同的磁盤上對性能是經常很有好處的。您也可以使用原始磁盤分區(原始設備)作為InnoDB數據檔案,這樣可以加速I/O。請參閱15.2.14.2節,「為資料表空間使用原始設備”

警告:在32位GNU/Linux x86上,您必須要小心不要設置過高的內存用量。glibc可能允許程序堆積線上程堆棧上發展,它會造成您的伺服器崩潰。如果下列資料表達式的值接近或者超過2GB,系統會面臨危機:

innodb_buffer_pool_size
+ key_buffer_size
+ max_connections*(sort_buffer_size+read_buffer_size+binlog_cache_size)
+ max_connections*2MB

每個線程使用一個堆棧(通常是2MB,但在MySQL AB二進制分發版裡只有256KB)並且在最壞的情況下也使用sort_buffer_size + read_buffer_size附加內存。

您可以自己編譯MySQL,在32位Windows上使用高達64GB物理內存。請參閱15.2.4節,「InnoDB啟動選項”裡對innodb_buffer_pool_awe_mem_mb的描述。

如何調整其它mysqld伺服器參數?下列值是典型的,且適用於多數用戶:

[mysqld]
skip-external-locking
max_connections=200
read_buffer_size=1M
sort_buffer_size=1M
#
# Set key_buffer to 5 - 50% of your RAM depending on how much
# you use MyISAM tables, but keep key_buffer_size + InnoDB
# buffer pool size < 80% of your RAM
key_buffer_size=value

15.2.4InnoDB啟動選項

這一節敘述InnoDB相關的伺服器選項,所有這些選項可以以--opt_name=value的形式在命令行或在選項檔案裡被指定。

·         innodb_additional_mem_pool_size

InnoDB用來儲存數據目錄訊息&其它內部數據結構的內存池的大小。您應用程式裡的資料表越多,您需要在這裡分配越多的內存。如果InnoDB用光了這個池內的內存,InnoDB開始從作業系統分配內存,並且往MySQL錯誤日誌寫警告訊息。 預設值是1MB。

·         innodb_autoextend_increment

當自動延伸資料表空間被填滿之時,為延伸而增加的尺寸(MB為單位)。 預設值是8。這個選項可以在運行時作為全局系統變數而改變。

·         innodb_buffer_pool_awe_mem_mb

如果緩衝池被放在32位Windows的AWE內存裡,這個參數就是緩衝池的大小(MB為單位)。(僅在32位Windows上相關)如果您的32位Windows作業系統使用所謂的“地址窗口延伸(AWE)”支援超過4GB內存,您可以用這個參數把InnoDB緩衝池分配進AWE物理內存。這個參數最大的可能值是64000。如果這個參數被指定了,innodb_buffer_pool_size是在32位地址空間的mysqld內的窗口,InnoDB把那個AWE內存映射上去。對innodb_buffer_pool_size參數,一個比較好的值是500MB。

·         innodb_buffer_pool_size

InnoDB用來緩存它的數據和索引的內存緩衝區的大小。您把這個值設得越高,訪問資料表中數據需要得磁盤I/O越少。在一個專用的資料庫伺服器上,您可以設置這個參數達機器物理內存大小的80%。儘管如此,還是不要把它設置得太大,因為對物理內存的競爭可能在作業系統上導致內存調度。

·         innodb_checksums

InnoDB在所有對磁盤的頁面讀取上使用校驗和驗證以確保額外容錯防止硬件損壞或數據檔案。儘管如此,在一些少見的情況下(比如運行標準檢查之時)這個額外的安全特徵是不必要的。在這些情況下,這個選項( 預設是允許的)可以用--skip-innodb-checksums來關閉。

·         innodb_data_file_path

到單獨數據檔案和它們尺寸的路徑。通過把innodb_data_home_dir連接到這裡指定的每個路徑,到每個數據檔案的完整目錄路徑可被獲得。檔案大小通過給尺寸值尾加M或G以MB或者GB(1024MB)為單位被指定。檔案尺寸的和至少是10MB。在一些作業系統上,檔案必須小於2GB。如果您沒有指定innodb_data_file_path,開始的預設行為是建立一個單獨的大小10MB名為ibdata1的自延伸數據檔案。在那些支援大檔案的作業系統上,您可以設置檔案大小超過4GB。您也可以使用原始磁盤分區作為數據檔案,請參閱15.2.14.2節,「為資料表空間使用原始設備”

·         innodb_data_home_dir

目錄路徑對所有InnoDB數據檔案的共同部分。如果您不設置這個值, 預設是MySQL數據目錄。您也可以指定這個值為一個空字串,在這種情況下,您可以在innodb_data_file_path中使用絕對檔案路徑。

·         innodb_doublewrite

預設地,InnoDB儲存所有數據兩次,第一次儲存到doublewrite緩衝,然後儲存到確實的數據檔案。這個選項可以被用來禁止這個功能。類似於innodb_checksums,這個選項 預設是允許的;因為標準檢查或在對頂級性能的需要超過對數據完整性或可能故障的關注之時,這個選項用--skip-innodb-doublewrite來關閉。

·         innodb_fast_shutdown

如果您把這個參數設置為0,InnoDB在關閉之前做一個完全淨化和一個插入緩衝合併。這些操作要花幾分鐘時間,設置在極端情況下要幾個小時。如果您設置這個參數為1,InnoDB在關閉之時跳過這些操作。 預設值為1。如果您設置這個值為2 (在Netware無此值), InnoDB將刷新它的日誌然後冷關機,彷彿MySQL崩潰一樣。已提交的事務不會被丟失,但在下一次啟動之時會做一個崩潰恢復。

·         innodb_file_io_threads

InnoDB中檔案I/O線程的數量。正常地,這個參數是用 預設的,預設值是4,但是大數值對Windows磁盤I/O有益。在Unix上,增加這個數沒有效果,InnoDB總是使用預設值。

·         innodb_file_per_table

這個選項致使InnoDB用自己的.ibd檔案為儲存數據和索引建立每一個新資料表,而不是在共享資料表空間中建立。請參閱15.2.6.6節,「使用Per-Table資料表空間”

·         innodb_flush_log_at_trx_commit

當innodb_flush_log_at_trx_commit被 設置為0,日誌緩衝每秒一次地被寫到日誌檔案,並且對日誌檔案做到磁盤操作的刷新,但是在一個事務提交不做任何操作。當這個值為1(預設值)之時,在每個事務提交時,日誌緩衝被寫到日誌檔案,對日誌檔案做到磁盤操作的 刷新。當設置為2之時,在每個提交,日誌緩衝被寫到檔案,但不對日誌檔案做到磁盤操作的刷新。儘管如此,在對日誌檔案的刷新在值為2的情況也每秒發生一次。我們必須注意到,因為程序安排問題,每秒一次的 刷新不是100%保證每秒都發生。您可以通過設置這個值不為1來獲得較好的性能,但隨之您會在一次崩潰中損失二分之一價值的事務。如果您設置這個值為0,那麼任何mysqld程序的崩潰會刪除崩潰前最後一秒的事務,如果您設置這個值為2,那麼只有作業系統崩潰或掉電才會刪除最後一秒的事務。儘管如此,InnoDB的崩潰恢復不受影響,而且因為這樣崩潰恢復開始作用而不考慮這個值。注意,許多作業系統和一些磁盤硬件會欺騙 刷新到磁盤操作。儘管刷新沒有進行,您可以告訴mysqld刷新已經進行。即使設置這個值為1,事務的持久程度不被保證,且在最壞情況下掉電甚至會破壞InnoDB資料庫。在SCSI磁盤控制器中,或在磁盤自身中,使用有後備電池的磁盤緩存會加速檔案 刷新並且使得操作更安全。您也可以試著使用Unix命令hdparm來在硬件緩存中禁止磁盤寫緩存,或使用其它一些對硬件提供商專用的命令。這個選項的 預設值是1。

·         innodb_flush_method

這個選項只在Unix系統上有效。如果這個選項被設置為fdatasync (預設值),InnoDB使用fsync()來刷新數據和日誌檔案。如果被設置為O_DSYNC,InnoDB使用O_SYNC來打開並刷新日誌檔案,但使用fsync()來 刷新數據檔案。如果O_DIRECT被指定了(在一些GNU/Linux版本商可用),InnoDB使用O_DIRECT來打開數據檔案,並使用fsync()來刷新數據和日誌檔案。注意,InnoDB使用fsync()來替代fdatasync(),並且它 預設不使用O_DSYNC,因為這個值在許多Unix變種上已經發生問題。

·         innodb_force_recovery

警告:這個選項僅在一個緊急情況下被定義,當時您想要從損壞的資料庫轉儲資料表。可能的值為從1到6。這些值的意思在15.2.8.1節,「強制恢復”中敘述。作為一個安全措施,當這個選項值大於零之時,InnoDB阻止用戶修改數據。

·         innodb_lock_wait_timeout

InnoDB事務在被回滾之前可以等待一個鎖定的超時秒數。InnoDB在它自己的 鎖定資料表中自動檢測事務死鎖並且回滾事務。InnoDB用LOCK TABLES語句注意到鎖定設置。預設值是50秒。

為在一個複製建立中最大可能的持久程度和連貫性,您應該在主伺服器上的my.cnf檔案裡使用innodb_flush_log_at_trx_commit=1和sync-binlog=1。

·         innodb_locks_unsafe_for_binlog

這個選項在InnoDB搜索和索引掃瞄中關閉下一鍵鎖定。這個選項的 預設值是假(false)。

正常地,InnoDB使用一個被稱為next-key locking的算法。當搜索或掃瞄一個資料表索引之時,InnoDB以這樣一種方式實行行級鎖定,它對任何遇到的索引記錄設置共享的或獨佔的鎖定。因此,行級鎖定實際是索引記錄鎖定。InnoDB對索引記錄設置的鎖定也影響被鎖定索引記錄之前的“gap”。如果一個用戶對某一索引內的記錄R又共享的或獨佔的鎖定,另一個用戶不能立即在R之前以索引的順序插入一個新的索引記錄。這個選項導致InnoDB不在搜索或索引掃瞄中使用下一 鍵鎖定。下一鍵鎖定仍然被用來確保外部鍵強制及重複鍵核查。注意,使用這個選項可能會導致一些詭異的問題:假設您想要用值大於100的標識符從子資料表裡讀取並鎖定所有的子記錄,同時 向隨後在選定的行更新一些列:

SELECT * FROM child WHERE id > 100 FOR UPDATE;

假設在id列有一個索引。查詢從id大於100的第一個記錄開始掃瞄索引。如果在索引記錄上的鎖定不把在間隙處生成的插入排除鎖定,同時一個新行被插進資料表中。如果您在同一個事務之內執行同樣的SELECT,您會在查詢返回的結果包裡看到一個新行。這也意味著,如果新條目被加進資料庫,InnoDB不保證連續性;儘管如此, 對應連續性仍被保證。因此,如果這個選項被使用,InnoDB在大多數孤立級別保證READ COMMITTED。

這個選項甚至更不安全。InnoDB在一個UPDATE或DELETE中只鎖定它更新或刪除的行。這大大減少了死鎖的可能性,但是可以發生死鎖。注意,即使在當類似的操作影響不同行時的情況下,這個選項仍然不允許諸如UPDATE這樣的操作壓倒相似選項(比如另一個UPDATE)。考慮下列例子:

CREATE TABLE A(A INT NOT NULL, B INT);
INSERT INTO A VALUES (1,2),(2,3),(3,2),(4,3),(5,2);
COMMIT;

如果一個連接執行一個查詢:

SET AUTOCOMMIT = 0;
UPDATE A SET B = 5 WHERE B = 3;

並且其它連接跟著第一個連接執行其它查詢:

SET AUTOCOMMIT = 0;
UPDATE A SET B = 4 WHERE B = 2;

接著查詢2要等查詢1的提交或回滾,因為查詢1對行(2,3)有一個獨佔的鎖定,並且查詢2在掃瞄行的同時也試著對它不能鎖定的同一個行(2,3)採取一個獨佔的鎖定。這是因為當innodb_locks_unsafe_for_binlog選項被使用之時,查詢2首先對一個行採取一個獨佔的鎖定,然後確定是否這個行屬於結果包,並且如果不屬於,就釋放不必要的鎖定。

因此,查詢1按如下執行:

x-lock(1,2)
unlock(1,2)
x-lock(2,3)
update(2,3) to (2,5)
x-lock(3,2)
unlock(3,2)
x-lock(4,3)
update(4,3) to (4,5)
x-lock(5,2)
unlock(5,2)

並且查詢2按如下執行:

x-lock(1,2)
update(1,2) to (1,4)
x-lock(2,3) - 等待查詢1提交或回滾

·         innodb_log_arch_dir

如果我們使用日誌檔案,被完整寫入的日誌檔案所在的目錄也被歸檔。這個參數值如果被使用了,應該被設置得與innodb_log_group_home_dir一樣。儘管如此,它不是必需的。

·         innodb_log_archive

這個值當前被設為0。因為MySQL使用它自己的日誌檔案從備份來恢復,所以當前沒有必要來歸檔InnoDB日誌檔案。這個選項的 預設值是0。

·         innodb_log_buffer_size

InnoDB用來往磁盤上的日誌檔案寫操作的緩衝區的大小。明智的值是從1MB到8MB。 預設的是1MB。一個大的日誌緩衝允許大型事務運行而不需要在事務提交之前往磁盤寫日誌。因此,如果您有大型事務,使日誌緩衝區更大以節約磁盤I/O。

·         innodb_log_file_size

在日誌組裡每個日誌檔案的大小。在32位計算機上日誌檔案的合併大小必須少於4GB。 預設是5MB。明智的值從1MB到N分之一緩衝池大小,其中N是組裡日誌檔案的數目。值越大,在緩衝池越少需要檢查點刷新行為,以節約磁盤I/O。但更大的日誌檔案也意味這在崩潰時恢復得更慢。

·         innodb_log_files_in_group

在日誌組裡日誌檔案的數目。InnoDB以循環方式寫進檔案。預設是2(推薦)。

·         innodb_log_group_home_dir

到InnoDB日誌檔案的目錄路徑。它必須有和innodb_log_arch_dir一樣的值。如果您不指定任何InnoDB日誌參數, 預設的是在MySQL數據目錄裡建立兩個5MB大小名為ib_logfile0和ib_logfile1的檔案。

·         innodb_max_dirty_pages_pct

這是一個範圍從0到100的整數。預設是90。InnoDB中的主線程試著從緩衝池寫頁面,使得髒頁(沒有被寫的頁面)的百分比不超過這個值。如果您有SUPER權限,這個百分比可以在伺服器運行時按下面來改變:

SET GLOBAL innodb_max_dirty_pages_pct = value;

·         innodb_max_purge_lag

這個選項控制在淨化操作被滯後之時,如何延遲INSERT, UPDATE和DELETE操作。(請參閱15.2.12節,「多版本的實施”)。這個參數的 預設值是零,意為無延遲。這個選項可以在運行時作為全局系統變數而被改變。

InnoDB事務系統維持一個事務列資料表,該列資料表有被UPDATE或DELETE操作標誌為刪除的索引記錄。讓這個列資料表的長度為purge_lag。當purge_lag超過innodb_max_purge_lag之時,每個INSERT, UPDATE和DELETE操作延遲 ((purge_lag/innodb_max_purge_lag)*10)-5毫秒。在淨化批處理的開始,延遲每隔10秒計算。如果因為一個舊的可以看到行被淨化的一致的讀查看, 刪除操作不被延遲。

對有問題的工作量,典型設置可能是1百萬,假設我們的事務很小,只有100字節大小,我們就可以允許在我們的資料表之中有100MB未淨化的行。

·         innodb_mirrored_log_groups

我們為資料庫保持的日誌組內同樣拷貝的數量。當前這個值應該被設為1。

·         innodb_open_files

在InnoDB中,這個選項僅與您使用多資料表空間時有關。它指定InnoDB一次可以保持打開的.ibd檔案的最大數目。最小值是10。 預設值300。

對.ibd檔案的檔案描述符是僅對InnoDB的。它們獨立於那些由--open-files-limit伺服器選項指定的描述符,且不影響資料表緩存的操作。

·         innodb_status_file

這個選項讓InnoDB為週期的SHOW INNODB STATUS輸出建立一個檔案<datadir>/innodb_status.<pid>

·         innodb_support_xa

當被設置為ON或者1(預設地),這個變數允許InnoDB支援在XA事務中的 雙向提交。允許innodb_support_xa導致一個額外的對事務準備的磁盤刷新。如果您對使用XA並不關心,您可以通過設置這個選項為OFF或0來禁止這個變數,以減少磁盤 刷新的次數並獲得更好的InnoDB性能。

·         innodb_table_locks

InnoDB重視LOCK TABLES,直到所有其它線程已經釋放他們所有對資料表的鎖定,MySQL才從LOCK TABLE .. WRITE返回。預設值是1,這意為LOCK TABLES讓InnoDB內部鎖定一個資料表。在使用AUTOCOMMIT=1的應用裡,InnoDB的內部資料表鎖定會導致死鎖。您可以在my.cnf檔案(Windows上是my.ini檔案)裡設置innodb_table_locks=0 來 消除這個問題。

·         innodb_thread_concurrency

InnoDB試著在InnoDB內保持作業系統線程的數量少於或等於這個參數給出的限制。如果有性能問題,並且SHOW INNODB STATUS顯示許多線程在等待信號,可以讓線程“thrashing” ,並且設置這個參數更小或更大。如果您的計算機有多個處理器和磁盤,您可以試著這個值更大以更好地利用計算機的資源。一個推薦的值是系統上處理器和磁盤的個數之和。值為500或比500大會禁止 使用並發檢查。預設值是20,並且如果設置大於或等於20,並發檢查將被禁止。

·         innodb_status_file

這個選項讓InnoDB為週期的SHOW INNODB STATUS輸出建立一個檔案<datadir>/innodb_status.<pid>

15.2.5. 建立InnoDB資料表空間

15.2.5.1. 處理InnoDB初始化問題

假設您已經安裝了MySQL,並且已經編輯了選項檔案,使得它包含必要的InnoDB配置參數。在啟動MySQL之前,您應該驗證您為InnoDB數據檔案和日誌檔案指定的目錄是否存在,並且MySQL有訪問這些目錄的權限。InnoDB不能建立目錄,只能建立檔案。也檢查您有足夠的空間來放數據和日誌檔案。

當建立InnoDB資料庫時,最好從命令提示符運行MySQL伺服器mysqld, 而不要從mysqld_safe包裝或作為Windows的服務來運行。當您從命令提示符運行,您可看見mysqld打印什麼以及發生了什麼。在Unix上,只需要使用mysqld。在Windows上,使用--console選項。

當在選項檔案裡初始地配置InnoDB後,開始啟動MySQL伺服器之時,InnoDB建立一個數據檔案和日誌檔案。InnoDB打印如下一些東西:

InnoDB: The first specified datafile /home/heikki/data/ibdata1
did not exist:
InnoDB: a new database to be created!
InnoDB: Setting file /home/heikki/data/ibdata1 size to 134217728
InnoDB: Database physically writes the file full: wait...
InnoDB: datafile /home/heikki/data/ibdata2 did not exist:
new to be created
InnoDB: Setting file /home/heikki/data/ibdata2 size to 262144000
InnoDB: Database physically writes the file full: wait...
InnoDB: Log file /home/heikki/data/logs/ib_logfile0 did not exist:
new to be created
InnoDB: Setting log file /home/heikki/data/logs/ib_logfile0 size
to 5242880
InnoDB: Log file /home/heikki/data/logs/ib_logfile1 did not exist:
new to be created
InnoDB: Setting log file /home/heikki/data/logs/ib_logfile1 size
to 5242880
InnoDB: Doublewrite buffer not found: creating new
InnoDB: Doublewrite buffer created
InnoDB: Creating foreign key constraint system tables
InnoDB: Foreign key constraint system tables created
InnoDB: Started
mysqld: ready for connections

一個新的InnoDB資料庫被建立了。您可以用mysql這樣通常的MySQL客戶端程式連接到MySQL伺服器。當您用mysqladmin shutdown關閉MySQL伺服器之時,輸出類似如下:

010321 18:33:34  mysqld: Normal shutdown
010321 18:33:34  mysqld: Shutdown Complete
InnoDB: Starting shutdown...
InnoDB: Shutdown completed

您可以看數據檔案和日誌檔案,並且您可以看見檔案被建立。日誌目錄也包含一個名為ib_arch_log_0000000000的小檔案。這個檔案是資料庫被建立的結果,資料庫被建立之後InnoDB切斷日誌歸檔。當MySQL再次啟動之時,數據檔案&日誌檔案已經被建立,所以輸出更簡潔:

InnoDB: Started
mysqld: ready for connections

您可以新增innodb_file_per_table選項到my.cnf檔案,並且讓InnoDB儲存每一個資料表到MySQL資料庫目錄裡自己的.ibd檔案。請參閱15.2.6.6節,「使用Per-Table資料表空間”

15.2.5.1. 處理InnoDB初始化問題

如果InnoDB在一個檔案操作中打印一個作業系統錯誤,通常問題是如下中的一個:

·         您沒有建立一個InnoDB數據檔案目錄或InnoDB日誌目錄。

·         mysqld沒有訪問這些目錄的權限 以建立檔案。

·         mysqld不能恰當地讀取my.cnf或my.ini選項檔案,因此不能看到您指定的選項。

·         磁盤已滿,或者超出磁盤配額。

·         您已經建立一個子目錄,它的名字與您指定的數據檔案相同。

·         在innodb_data_home_dir或innodb_data_file_path有一個語法錯誤。

當InnoDB試著初始化它的資料表空間或日誌檔案之時,如果出錯了,您應該刪除InnoDB建立的所有檔案。這意味著是所有ibdata檔案和所有ib_logfiles檔案。萬一您建立了一些InnoDB資料表,為這些資料表也從MySQL資料庫目錄刪除相應的.frm檔案(如果您使用多重資料表空間的話,也刪除任何.ibd檔案)。然後您可以試著再次建立InnoDB資料庫。最好是從命令提示符啟動MySQL伺服器 ,以便您可以查看發生了什麼。

15.2.6. 建立InnoDB資料表

15.2.6.1. 如何在InnoDB用不同API來使用事務

15.2.6.2. 轉換MyISAM資料表到InnoDB

15.2.6.3. AUTO_INCREMENT列如何在InnoDB中工作

15.2.6.4.外鍵約束

15.2.6.5. InnoDBMySQL複製

15.2.6.6. 使用Per-Table資料表空間

假如您用mysql test命令啟動MySQL客戶端。要建立一個InnoDB資料表,您必須在資料表建立SQL語句中指定ENGINE = InnoDB或者TYPE = InnoDB選項:

CREATE TABLE customers (a INT, b CHAR (20), INDEX (a)) ENGINE=InnoDB;
CREATE TABLE customers (a INT, b CHAR (20), INDEX (a)) TYPE=InnoDB;

SQL語句在資料表空間的列上建立一個資料表和索引,資料表空間包含您在my.cnf指定的數據檔案。此外,MySQL在MySQL資料庫目錄下的test目錄裡建立一個名為customers.frm的檔案。內部地,InnoDB為'test/customers'資料表往自己的數據目錄新增一個條目。這意味這您可以在其它資料庫建立一個具有相同名字customers的資料表,資料表的名字不會與InnoDB內的衝突。

您可以對任何InnoDB資料表,通過使用SHOW TABLE STATUS語句,查詢在InnoDB資料表空間內空閒空間的數量。資料表空間內空閒空間的數量出現在SHOW TABLE STATUS的輸出結果內的Comment節裡。例如:

SHOW TABLE STATUS FROM test LIKE 'customers'

注意,統計的SHOW只給出關於InnoDB資料表的大概情況。它們被用於SQL最佳化。可是,資料表和索引保留的大小,以字節為單位是準確的。

15.2.6.1. 如何在InnoDB中用不同的API來使用事務

預設地,每個連接到MySQL伺服器的客戶端開始之時是允許自動提交模式的,這個模式自動提交您運行的每個SQL語句。要使用多語句事務,您可以用SQL語句SET AUTOCOMMIT = 0禁止自動提交,並且用COMMIT和ROLLBACK來提交或回滾您的事務。 如果您想要autocommit保持打開狀態,可以在START TRANSACTION與COMMIT或ROLLBACK之間封裝您的事務。下列的例子演示兩個事務。第一個是被提交的,第二個是被 回滾的:

shell> mysql test
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 5 to server version: 3.23.50-log
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> CREATE TABLE CUSTOMER (A INT, B CHAR (20), INDEX (A))
    -> ENGINE=InnoDB;
Query OK, 0 rows affected (0.00 sec)
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO CUSTOMER VALUES (10, 'Heikki');
Query OK, 1 row affected (0.00 sec)
mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)
mysql> SET AUTOCOMMIT=0;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO CUSTOMER VALUES (15, 'John');
Query OK, 1 row affected (0.00 sec)
mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM CUSTOMER;
+------+--------+
| A    | B      |
+------+--------+
|   10 | Heikki |
+------+--------+
1 row in set (0.00 sec)
mysql>

在類似PHP, Perl DBI/DBD, JDBC, ODBC, 或者MySQL的標準C使用接口這樣的API上,您能夠以字串形式發送事務控制語句,如COMMIT,到MySQL伺服器,就像其它任何的SQL語句 那樣,諸如SELECT或INSERT。一些API也提供單獨的專門的事務提交和回滾函數或者方法。

15.2.6.2. 轉換MyISAM資料表到InnoDB

要點:您不應該在mysql資料庫(比如,user或者host)裡把MySQL系統資料表轉換為InnoDB類型。系統資料表總是MyISAM型。

如果您想要所有(非系統)資料表都被建立成InnoDB資料表,您可以簡單地把default-table-type=innodb行新增到my.cnf或my.ini檔案的[mysqld]節裡。

InnoDB對MyISAM儲存引擎採用的單獨索引建立方法沒有做專門的最佳化。因此,它不值得導出或導入資料表以及隨後建立索引。改變一個資料表為InnoDB型最快的辦法就是直接插入進一個InnoDB資料表。即,使用ALTER TABLE ... ENGINE=INNODB,或用相同的定義建立一個空InnoDB資料表,並且用INSERT INTO ... SELECT * FROM ...插入行。

如果您對第二個鍵有UNIQUE約束,您可以在導入階段設置:SET UNIQUE_CHECKS=0,以臨時關掉唯一性檢查好加速資料表的導入。對於大資料表,這節省了大量的磁盤I/O,因為InnoDB隨後可以使用它的插入緩衝區來第二個索引記錄作為一批來寫入。

為獲得對插入程序的更好控制,分段插入大資料表可能比較好:

INSERT INTO newtable SELECT * FROM oldtable
   WHERE yourkey > something AND yourkey <= somethingelse;

所有記錄已經本插入之後,您可以重命名資料表。

在大資料表的轉換中,您應該增加InnoDB緩衝池的大小來減少磁盤I/O。儘管如此,不要使用超過80%的內部內存。您也可以增加InnoDB日誌檔案和日誌檔案的大小。

確信您沒有填滿資料表空間:InnoDB資料表比MyISAM資料表需要大得多的磁盤空間。如果一個ALTER TABLE耗盡了空間,它就開始一個 回滾,並且如果它是磁盤綁定的,回滾可能要幾個小時。對於插入,InnoDB使用插入緩衝區來以成批地合併第二個索引記錄到索引中。那樣節省了大量磁盤I/O。在回滾中,沒有使用這樣的機制,而回滾要花比插入長30倍的時間來完成。

在失控的回滾情況下,如果您在資料庫中沒有有價值的數據,比較明智的是殺掉資料庫程序而不是等幾百萬個磁盤I/O被完成。 完整的過程,請參閱15.2.8.1節,「強制恢復”

15.2.6.3. AUTO_INCREMENT列在InnoDB裡如何工作

如果您為一個資料表指定AUTO_INCREMENT列,在數據詞典裡的InnoDB資料表句柄包含一個名為自動增長計數器的計數器,它被用在為該 列賦新值。自動增長計數器僅被儲存在主內存中,而不是存在磁盤上。

InnoDB使用下列算法來為包含一個名為ai_col的AUTO_INCREMENT列的資料表T初始化自動增長計數器:伺服器啟動之後,當一個用戶對資料表T做插入之時,InnoDB執行等價如下語句的動作:

SELECT MAX(ai_col) FROM T FOR UPDATE;

語句取回的值逐次加一,並被賦給列和自動增長計數器。如果資料表是空的,值1被賦予該列。如果自動增長計數器沒有被初始化,而且用戶使用為資料表T顯示輸出的SHOW TABLE STATUS語句,則計數器被初始化(但不是增加計數)並被儲存以供隨後的插入使用。注意,在這個初始化中,我們對資料表做一個正常的獨佔鎖定,這個鎖持續到事務的結束。

InnoDB對為新建立資料表的初始化自動增長計數器允許同樣的過程。

注意,如果用戶在INSERT中為AUTO_INCREMENT列指定NULL或者0,InnoDB處理行,就彷彿值還沒有被指定,且為它生成一個新值。

自動增長計數器被初始化之後,如果用戶插入一個明確指定該列值的行,而且該值大於當前計數器值,則計數器被設置為指定 列值。如果沒有明確指定一個值,InnoDB給計數器增加一,並且賦新值給該列。

當訪問自動增長計數器之時,InnoDB使用專用的資料表級的AUTO-INC鎖定,該鎖持續到當前SQL語句的結束而不是到業務的結束。 引入了專用鎖釋放策略,來為對一個含AUTO_INCREMENT列的資料表的插入改善部署。兩個事務不能同時對同一資料表有AUTO-INC鎖定。

注意,如果您回滾從計數器獲得數的事務,您可能會在賦給AUTO_INCREMENT列的值的序列中發現間隙。

如果用戶給列賦一個賦值,或者,如果值大過可被以指定整數格式儲存的最大整數,自動增長機制的行為不被定義。

在CREATE TABLE和ALTER TABLE語句中,InnoDB支援AUTO_INCREMENT = n 資料表選項來設置計數器初始值或變更當前計數器值。因在本節早先討論的原因,這個選項的影響在伺服器重啟後就無效了。

15.2.6.4.外部鍵約束

InnoDB也支援外部鍵約束。InnoDB中對外部鍵約束定義的語法看起來如下:

[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)
    REFERENCES tbl_name (index_col_name, ...)
    [ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION}]
    [ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION}]

外部鍵定義服從下列情況:

·         所有tables必須是InnoDB型,它們不能是臨時資料表。

·         在引用資料表中,必須有一個索引,外部鍵列以同樣的順序被列在其中作為第一列。這樣一個索引如果不存在,它必須在 引用資料表裡被自動建立。

·         在引用資料表中,必須有一個索引,被引用的列以同樣的順序被列在其中作為第一列。

·         不支援對外部鍵列的索引前綴。這樣的後果之一是BLOB和TEXT列不被包括在一個外部鍵中,這是因為對這些列的索引必須總是包含一個前綴長度。

·         如果CONSTRAINTsymbol被給出,它在資料庫裡必須是唯一的。如果它沒有被給出,InnoDB自動建立這個名字。

InnoDB拒絕任何試著在子資料表建立一個外部鍵值而不匹配在父資料表中的候選鍵值的INSERT或UPDATE操作。一個父資料表有一些匹配的行 的子資料表,InnoDB對任何試圖更新或刪除該父資料表中候選鍵值的UPDATE或DELETE操作有所動作,這個動作取決於用FOREIGN KEY子句的ON UPDATE和ON DETETE子句指定的referential action。當用戶試圖從一個父資料表刪除或更新一行之時,且在子資料表中有一個或