如果您有 MyISAM
表格想要轉換為 InnoDB
以獲得更好的可靠性和可擴展性,請在轉換之前查看以下指南和提示。
在先前版本的 MySQL 中建立的分割 MyISAM
表格與 MySQL 9.0 不相容。此類表格必須在升級之前準備好,方法是移除分割,或將其轉換為 InnoDB
。有關更多資訊,請參閱第 26.6.2 節「與儲存引擎相關的分割限制」。
當您從 MyISAM
表格轉換時,請降低 key_buffer_size
設定選項的值,以釋放不再需要快取結果的記憶體。增加 innodb_buffer_pool_size
設定選項的值,該選項執行類似的角色,為 InnoDB
表格分配快取記憶體。InnoDB
緩衝池會快取表格資料和索引資料,加速查詢的查找,並將查詢結果保留在記憶體中以供重複使用。有關緩衝池大小設定的指南,請參閱第 10.12.3.1 節「MySQL 如何使用記憶體」。
由於 MyISAM
表格不支援交易,您可能不太注意 autocommit
設定選項以及 COMMIT
和 ROLLBACK
陳述式。這些關鍵字很重要,可讓多個工作階段同時讀取和寫入 InnoDB
表格,在寫入密集型工作負載中提供顯著的可擴展性優勢。
當交易開啟時,系統會保留交易開始時看到的資料快照,如果系統在閒置交易持續執行的同時插入、更新和刪除數百萬列,可能會造成大量額外負荷。因此,請注意避免執行時間過長的交易
如果您使用 mysql 工作階段進行互動式實驗,請務必在完成時
COMMIT
(以完成變更) 或ROLLBACK
(以還原變更)。請關閉互動式工作階段,不要讓它們長時間開啟,以避免意外地讓交易長時間保持開啟狀態。ROLLBACK
是一個相對昂貴的操作,因為INSERT
、UPDATE
和DELETE
操作會在COMMIT
之前寫入InnoDB
表格,預期大多數變更都會成功提交,而回滾則很少發生。當實驗大量資料時,請避免對大量資料列進行變更,然後回滾這些變更。當使用一系列
INSERT
陳述式載入大量資料時,請定期COMMIT
結果,以避免交易持續數小時。在資料倉儲的典型載入操作中,如果發生錯誤,請截斷表格(使用TRUNCATE TABLE
),並從頭開始,而不是執行ROLLBACK
。
前面的提示可以節省在過長交易期間可能浪費的記憶體和磁碟空間。當交易比應有的時間短時,問題是過多的 I/O。每次 COMMIT
時,MySQL 都會確保每個變更都安全地記錄到磁碟,這會涉及一些 I/O。
對於
InnoDB
表格上的大多數操作,您應該使用設定autocommit=0
。從效率的角度來看,這可以避免在您發出大量連續的INSERT
、UPDATE
或DELETE
陳述式時,發生不必要的 I/O。從安全的角度來看,如果您在 mysql 命令列中,或在應用程式的例外處理常式中犯錯,這可讓您發出ROLLBACK
陳述式來復原遺失或損毀的資料。當執行一系列查詢以產生報表或分析統計資料時,
InnoDB
表格適合使用autocommit=1
。在這種情況下,沒有與COMMIT
或ROLLBACK
相關的 I/O 效能損失,而且InnoDB
可以自動最佳化唯讀工作負載。如果您進行一系列相關的變更,請在結尾使用單一
COMMIT
來完成所有變更。例如,如果您將相關的資訊片段插入多個表格中,請在進行所有變更後執行單一COMMIT
。或者,如果您執行許多連續的INSERT
陳述式,請在載入所有資料後執行單一COMMIT
;如果您要執行數百萬個INSERT
陳述式,也許可以透過每 1 萬或 10 萬筆記錄發出COMMIT
來分割大型交易,這樣交易就不會變得太大。請記住,即使是
SELECT
陳述式也會開啟交易,因此在互動式 mysql 工作階段中執行一些報表或偵錯查詢之後,請發出COMMIT
或關閉 mysql 工作階段。
如需相關資訊,請參閱第 17.7.2.2 節「autocommit、Commit 和 Rollback」。
您可能會在 MySQL 錯誤記錄中,或 SHOW ENGINE INNODB STATUS
的輸出中,看到提到「死鎖」的警告訊息。死鎖對於 InnoDB
表格來說並不是嚴重的問題,而且通常不需要任何更正措施。當兩個交易開始修改多個表格時,如果以不同的順序存取表格,它們可能會進入每個交易都在等待對方,而兩者都無法繼續的狀態。當啟用死鎖偵測(預設)時,MySQL 會立即偵測到此情況,並取消(回滾)「較小」的交易,允許另一個交易繼續進行。如果使用 innodb_deadlock_detect
設定選項停用死鎖偵測,則 InnoDB
會依賴 innodb_lock_wait_timeout
設定,在發生死鎖時回滾交易。
無論哪種方式,您的應用程式都需要錯誤處理邏輯來重新啟動因死鎖而被強制取消的交易。當您重新發出與之前相同的 SQL 陳述式時,原始的時序問題不再適用。另一個交易已經完成,您的交易可以繼續,或者另一個交易仍在進行中,而您的交易會等到它完成。
如果不斷發生死鎖警告,您可能會檢查應用程式程式碼,以一致的方式重新排序 SQL 操作,或縮短交易。您可以啟用 innodb_print_all_deadlocks
選項進行測試,以查看 MySQL 錯誤記錄中的所有死鎖警告,而不僅僅是 SHOW ENGINE INNODB STATUS
輸出中的最後一個警告。
如需更多資訊,請參閱第 17.7.5 節「InnoDB 中的死鎖」。
為了從 InnoDB
表格獲得最佳效能,您可以調整一些與儲存配置相關的參數。
當您轉換大型、經常存取且包含重要資料的 MyISAM
表格時,請研究並考慮 innodb_file_per_table
和 innodb_page_size
變數,以及 ROW_FORMAT
和 KEY_BLOCK_SIZE
子句的 CREATE TABLE
陳述式。
在您的初始實驗中,最重要的設定是 innodb_file_per_table
。當啟用此設定(這是預設值)時,新的 InnoDB
表格會在每個表格一個檔案的表格空間中隱式建立。與 InnoDB
系統表格空間相比,每個表格一個檔案的表格空間允許在表格截斷或刪除時,由作業系統回收磁碟空間。每個表格一個檔案的表格空間也支援 DYNAMIC 和 COMPRESSED 列格式,以及相關功能,例如表格壓縮、長度可變長欄的有效頁外儲存,以及大型索引前置詞。如需更多資訊,請參閱第 17.6.3.2 節「每個表格一個檔案的表格空間」。
您也可以將 InnoDB
表格儲存在共用的一般表格空間中,該空間支援多個表格和所有列格式。如需更多資訊,請參閱第 17.6.3.3 節「一般表格空間」。
您可以建立一個 InnoDB
表格,該表格是 MyISAM 表格的複製品,而不是使用 ALTER TABLE
執行轉換,以便在切換之前並排測試新舊表格。
建立一個具有相同欄和索引定義的空白 InnoDB
表格。使用 SHOW CREATE TABLE
查看要使用的完整 table_name
\GCREATE TABLE
陳述式。將 ENGINE
子句變更為 ENGINE=INNODB
。
若要將大量資料傳輸到先前章節所述建立的空的 InnoDB
資料表中,請使用 INSERT INTO
語法插入資料列。innodb_table
SELECT * FROM myisam_table
ORDER BY primary_key_columns
您也可以在插入資料後,再為 InnoDB
資料表建立索引。過去,為 InnoDB
建立新的次要索引是很慢的操作,但現在您可以在資料載入後再建立索引,索引建立步驟的額外負擔相對較小。
如果次要鍵上有 UNIQUE
限制,您可以在匯入操作期間暫時關閉唯一性檢查,以加快資料表匯入速度。
SET unique_checks=0;
... import operation ...
SET unique_checks=1;
對於大型資料表,這可以節省磁碟 I/O,因為 InnoDB
可以使用其變更緩衝區,以批次方式寫入次要索引記錄。請務必確認資料中沒有重複的鍵。unique_checks
允許但並未強制儲存引擎忽略重複的鍵。
為了更好地控制插入過程,您可以分批插入大型資料表。
INSERT INTO newtable SELECT * FROM oldtable
WHERE yourkey > something AND yourkey <= somethingelse;
插入所有記錄後,您可以重新命名資料表。
在轉換大型資料表期間,請增加 InnoDB
緩衝池的大小,以減少磁碟 I/O。通常,建議的緩衝池大小為系統記憶體的 50% 至 75%。您也可以增加 InnoDB
記錄檔的大小。
如果您打算在轉換過程中製作多個 InnoDB
資料表的臨時副本,建議您在每個資料表的表空間中建立資料表,以便在刪除資料表時回收磁碟空間。當啟用 innodb_file_per_table
設定選項(預設值)時,新建立的 InnoDB
資料表會隱含地在每個資料表的表空間中建立。
無論您是直接轉換 MyISAM
資料表,還是建立複製的 InnoDB
資料表,都請確保您有足夠的磁碟空間,可以在過程中同時容納舊的和新的資料表。InnoDB
資料表比 MyISAM
資料表需要更多的磁碟空間。如果 ALTER TABLE
操作空間不足,它會開始回滾,如果受限於磁碟 I/O,可能需要數小時。對於插入操作,InnoDB
會使用插入緩衝區將次要索引記錄合併到批次索引中。這可以節省大量的磁碟 I/O。對於回滾,則沒有使用此機制,並且回滾可能比插入花費的時間長 30 倍。
在發生失控回滾的情況下,如果您的資料庫中沒有有價值的資料,建議您終止資料庫程序,而不是等待數百萬個磁碟 I/O 操作完成。如需完整的程序,請參閱第 17.20.3 節「強制執行 InnoDB 復原」。
PRIMARY KEY
子句是影響 MySQL 查詢效能以及資料表和索引空間使用的關鍵因素。主鍵唯一識別資料表中的資料列。資料表中的每一列都應具有主鍵值,且沒有兩列可以具有相同的主鍵值。
以下是主鍵的準則,後面會提供更詳細的解釋。
為每個資料表宣告一個
PRIMARY KEY
。通常,它是您在尋找單一資料列時,WHERE
子句中參考的最重要資料行。在原始的
CREATE TABLE
語法中宣告PRIMARY KEY
子句,而不是稍後透過ALTER TABLE
語法新增。請仔細選擇資料行及其資料類型。優先選擇數值資料行,而不是字元或字串資料行。
如果沒有其他穩定、唯一、非 Null 的數值資料行可供使用,請考慮使用自動遞增資料行。
如果有任何疑問,主鍵資料行的值是否可能變更,自動遞增資料行也是不錯的選擇。變更主鍵資料行的值是一項耗費資源的操作,可能涉及重新排列資料表內和每個次要索引中的資料。
考慮將主鍵新增到任何尚未有主鍵的資料表。根據資料表的最大預計大小,使用最小的實用數值類型。這可以使每一列稍微更精簡,從而為大型資料表節省大量空間。如果資料表有任何次要索引,則空間節省量會成倍增加,因為主鍵值會在每個次要索引項目中重複。除了減少磁碟上的資料大小之外,較小的主鍵還可以讓更多資料放入緩衝池,從而加快所有類型的操作並提高並行性。
如果資料表在較長的資料行(例如 VARCHAR
)上已具有主鍵,請考慮新增新的無符號 AUTO_INCREMENT
資料行,並將主鍵切換到該資料行,即使該資料行未在查詢中參考也一樣。這種設計變更可以在次要索引中節省大量空間。您可以將先前的主鍵資料行指定為 UNIQUE NOT NULL
,以強制執行與 PRIMARY KEY
子句相同的限制,也就是防止所有這些資料行出現重複或 Null 值。
如果您將相關資訊分散到多個資料表中,通常每個資料表都會使用相同的資料行作為其主鍵。例如,人事資料庫可能有多個資料表,每個資料表的主鍵都是員工編號。銷售資料庫可能有些資料表的主鍵是客戶編號,其他資料表的主鍵則是訂單編號。因為使用主鍵進行查找的速度非常快,所以您可以為這類資料表建構有效率的聯結查詢。
如果您完全省略 PRIMARY KEY
子句,MySQL 會為您建立一個看不見的主鍵。它是一個 6 位元組的值,可能比您需要的長,因此會浪費空間。因為它是隱藏的,所以您無法在查詢中參考它。
InnoDB
的可靠性和可擴展性功能比同等的 MyISAM
資料表需要更多的磁碟儲存空間。您可以稍微變更資料行和索引定義,以更好地利用空間、減少處理結果集的 I/O 和記憶體消耗,以及最佳化查詢規劃,有效利用索引查找。
如果您為主鍵設定數值 ID 資料行,請使用該值與任何其他資料表中的相關值進行交叉參考,特別是針對聯結查詢。例如,與其接受國家/地區名稱作為輸入並執行查詢來搜尋相同的名稱,不如執行一次查詢來確定國家/地區 ID,然後執行其他查詢(或單一聯結查詢)來搜尋多個資料表中的相關資訊。與其將客戶或目錄項目編號儲存為一串數字(可能佔用多個位元組),不如將其轉換為數值 ID 以進行儲存和查詢。一個 4 位元組無符號INT
資料行可以索引超過 40 億個項目 (以美國的「十億」來說:10 億)。如需不同整數類型的範圍,請參閱第 13.1.2 節「整數類型 (精確值) - INTEGER、INT、SMALLINT、TINYINT、MEDIUMINT、BIGINT」。