如果您有想要轉換為 InnoDB
以獲得更好的可靠性和可擴展性的 MyISAM
表格,請在轉換之前查看以下準則和提示。
在先前 MySQL 版本中建立的分割 MyISAM
表格與 MySQL 8.4 不相容。此類表格必須在升級之前準備好,方法是移除分割或將其轉換為 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。從安全性的角度來看,這允許您發出ROLLBACK
陳述式,以便在您在 mysql 命令列或應用程式中的例外處理常式中犯錯時,復原遺失或損壞的資料。autocommit=1
適用於在執行一系列查詢以產生報告或分析統計資料時的InnoDB
資料表。在這種情況下,沒有與COMMIT
或ROLLBACK
相關的 I/O 損失,而InnoDB
可以自動最佳化唯讀工作負載。如果您進行一系列相關的變更,請在最後使用單一的
COMMIT
一次完成所有變更。例如,如果您將相關資訊片段插入多個資料表,請在進行所有變更後執行單一的COMMIT
。或者,如果您執行許多連續的INSERT
陳述式,請在載入所有資料後執行單一的COMMIT
;如果您正在執行數百萬個INSERT
陳述式,或許可以透過每十萬或百萬筆記錄發出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
表格會隱式地在file-per-table 表空間中建立。與 InnoDB
系統表空間相比,file-per-table 表空間允許在表格被截斷或刪除時,讓作業系統回收磁碟空間。File-per-table 表空間也支援 DYNAMIC 和 COMPRESSED 列格式,以及相關功能,例如表格壓縮、針對長度可變的欄位進行高效的頁外儲存,以及大型索引前綴。更多資訊請參閱第 17.6.3.2 節,「File-Per-Table 表空間」。
您也可以將 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
表格中建立多個臨時資料副本,建議您在 file-per-table 表空間中建立這些表格,以便在您刪除表格時回收磁碟空間。當 innodb_file_per_table
設定選項啟用時(預設為啟用),新建立的 InnoDB
表格會隱式地在 file-per-table 表空間中建立。
無論您是直接轉換 MyISAM
表格還是建立複製的 InnoDB
表格,請確保您有足夠的磁碟空間來容納該過程中的新舊表格。InnoDB
表格比 MyISAM
表格需要更多的磁碟空間。如果 ALTER TABLE
操作耗盡空間,它將開始回滾,如果受限於磁碟,則可能需要數小時。對於插入操作,InnoDB
使用插入緩衝區將二級索引記錄批次合併到索引中。這樣可以節省大量的磁碟 I/O。對於回滾,沒有使用此類機制,回滾可能比插入花費的時間多 30 倍。
在發生失控回滾的情況下,如果您的資料庫中沒有重要資料,建議您終止資料庫進程,而不是等待數百萬次的磁碟 I/O 操作完成。如需完整的程序,請參閱 第 17.20.3 節,「強制 InnoDB 復原」。
PRIMARY KEY
子句是影響 MySQL 查詢效能以及表格和索引空間使用率的關鍵因素。主鍵唯一識別表格中的資料列。表格中的每個資料列都應具有主鍵值,並且沒有兩個資料列可以具有相同的主鍵值。
以下是主鍵的準則,接著是更詳細的說明。
為每個表格宣告一個
PRIMARY KEY
。通常,它是您在查詢單個資料列時,在WHERE
子句中參考的最重要的欄位。在原始
CREATE TABLE
陳述式中宣告PRIMARY KEY
子句,而不是稍後透過ALTER TABLE
陳述式新增。仔細選擇欄位及其資料類型。優先選擇數字欄位,而不是字元或字串欄位。
如果沒有其他穩定、唯一、非空、數字欄位可使用,請考慮使用自動遞增欄位。
如果對主鍵欄位的值是否會變更存有任何疑問,自動遞增欄位也是一個不錯的選擇。變更主鍵欄位的值是一項耗費資源的操作,可能會涉及重新排列表格和每個二級索引中的資料。
考慮為任何尚未具有主鍵的表格新增 主鍵。根據表格的最大預期大小,使用最小的實用數字類型。這可以使每個資料列稍微緊湊一些,對於大型表格,可以節省大量空間。如果表格具有任何二級索引,空間節省效果會倍增,因為主鍵值會在每個二級索引項目中重複。除了減少磁碟上的資料大小外,較小的主鍵也可以讓更多的資料放入緩衝池中,從而加快所有類型的操作並提高並發性。
如果表格的主鍵已在較長的欄位(例如 VARCHAR
)上,請考慮新增一個新的未簽署 AUTO_INCREMENT
欄位,並將主鍵切換到該欄位,即使該欄位未在查詢中被引用。此設計變更可以節省二級索引中的大量空間。您可以將先前的主鍵欄位指定為 UNIQUE NOT NULL
,以強制執行與 PRIMARY KEY
子句相同的限制,也就是防止在所有這些欄位中出現重複或空值。
如果將相關資訊分散在多個表格中,則每個表格通常都使用相同的欄位作為其主鍵。例如,人事資料庫可能有多個表格,每個表格的主鍵都是員工編號。銷售資料庫可能有一些表格的主鍵是客戶編號,其他表格的主鍵是訂單編號。因為使用主鍵的查詢非常快,所以您可以為此類表格建構有效的聯結查詢。
如果您完全省略 PRIMARY KEY
子句,MySQL 會為您建立一個隱藏的主鍵。它是一個 6 位元組的值,可能比您需要的更長,因此會浪費空間。因為它是隱藏的,所以您無法在查詢中參考它。
InnoDB
的可靠性和可擴充性功能比同等的 MyISAM
表格需要更多的磁碟儲存空間。您可以稍微變更欄位和索引定義,以獲得更好的空間利用率、減少處理結果集時的 I/O 和記憶體消耗,以及更好的查詢最佳化計畫,有效利用索引查詢。
如果您為主鍵設定了數字 ID 欄位,請使用該值與任何其他表格中的相關值交叉參考,尤其是對於聯結查詢。例如,與其接受國家/地區名稱作為輸入並執行查詢來搜尋相同的名稱,不如執行一次查詢以確定國家/地區 ID,然後執行其他查詢(或單個聯結查詢)以在多個表格中查詢相關資訊。與其將客戶或目錄項目編號儲存為一串數字(可能佔用多個位元組),不如將其轉換為數字 ID 以便儲存和查詢。一個 4 位元組未簽署的 INT
欄位可以索引超過 40 億個項目(以美國的 10 億含義而言:1000 百萬)。有關不同整數類型的範圍,請參閱第 13.1.2 節,「整數類型(精確值)- INTEGER、INT、SMALLINT、TINYINT、MEDIUMINT、BIGINT」。