最常見的情況是,InnoDB 資料儲存和壓縮中描述的內部最佳化可確保系統使用壓縮資料正常運作。然而,由於壓縮效率取決於資料的性質,您可以做出會影響壓縮表格效能的決策
使用本節中的指南來協助做出這些架構和設定選擇。當您準備好進行長期測試並將壓縮表格投入生產時,請參閱第 17.9.1.4 節,「在執行階段監控 InnoDB 表格壓縮」,了解如何在實際情況下驗證這些選擇的有效性。
何時使用壓縮
一般而言,壓縮最適用於包含相當多字串欄位的表格,且讀取資料的頻率遠高於寫入的頻率。由於沒有絕對的方法可以預測壓縮是否對特定情況有利,請務必在具有代表性的配置上,使用特定的工作負載和資料集進行測試。在決定要壓縮哪些表格時,請考慮以下因素。
資料特性與壓縮
資料本身性質是決定壓縮在減少資料檔案大小方面效率的關鍵因素。請回想一下,壓縮的原理是識別資料區塊中重複的位元組字串。完全隨機的資料是最糟的情況。典型的資料通常具有重複的值,因此壓縮效果很好。字串通常可以很好地壓縮,無論是定義在 CHAR
、VARCHAR
、TEXT
或 BLOB
欄位中。另一方面,主要包含二進制資料(整數或浮點數)或先前已壓縮的資料(例如JPEG或PNG影像)的表格,通常可能無法很好地壓縮,效果不大甚至完全沒有效果。
您可以選擇是否為每個 InnoDB 表格啟用壓縮。表格及其所有索引都使用相同的(壓縮)頁面大小。可能包含表格所有欄位資料的主鍵(叢集)索引,比次要索引的壓縮效果更好。對於那些具有長資料列的情況,使用壓縮可能會導致長欄位值被儲存為「頁外」,如DYNAMIC 資料列格式中所述。那些溢出頁面可能可以很好地壓縮。考量這些因素,對於許多應用程式而言,有些表格比其他表格的壓縮效果更好,您可能會發現只有壓縮部分的表格才能讓工作負載獲得最佳效能。
若要判斷是否要壓縮特定表格,請進行實驗。您可以透過在未壓縮表格的 .ibd 檔案副本上,使用實作 LZ77 壓縮的公用程式(例如 gzip
或 WinZip)來粗略估計資料的壓縮效率。您從 MySQL 壓縮表格獲得的壓縮效果會比從基於檔案的壓縮工具獲得的壓縮效果差,因為 MySQL 會根據 頁面大小(預設為 16KB)來壓縮資料區塊。除了使用者資料之外,頁面格式還包含一些未壓縮的內部系統資料。基於檔案的壓縮公用程式可以檢查更大的資料區塊,因此可能在大型檔案中找到比 MySQL 在單一頁面中找到的更多重複字串。
另一種測試特定表格壓縮的方法是,將一些資料從未壓縮的表格複製到類似的壓縮表格(具有所有相同的索引),並放在每個表格一個檔案的表格空間中,然後查看產生的 .ibd
檔案大小。例如
USE test;
SET GLOBAL innodb_file_per_table=1;
SET GLOBAL autocommit=0;
-- Create an uncompressed table with a million or two rows.
CREATE TABLE big_table AS SELECT * FROM information_schema.columns;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
COMMIT;
ALTER TABLE big_table ADD id int unsigned NOT NULL PRIMARY KEY auto_increment;
SHOW CREATE TABLE big_table\G
select count(id) from big_table;
-- Check how much space is needed for the uncompressed table.
\! ls -l data/test/big_table.ibd
CREATE TABLE key_block_size_4 LIKE big_table;
ALTER TABLE key_block_size_4 key_block_size=4 row_format=compressed;
INSERT INTO key_block_size_4 SELECT * FROM big_table;
commit;
-- Check how much space is needed for a compressed table
-- with particular compression settings.
\! ls -l data/test/key_block_size_4.ibd
此實驗產生以下數字,當然這些數字可能會因您的表格結構和資料而有很大差異
-rw-rw---- 1 cirrus staff 310378496 Jan 9 13:44 data/test/big_table.ibd
-rw-rw---- 1 cirrus staff 83886080 Jan 9 15:10 data/test/key_block_size_4.ibd
若要查看壓縮是否對您的特定工作負載有效率
對於簡單的測試,請使用沒有其他壓縮表格的 MySQL 執行個體,並針對 Information Schema 的
INNODB_CMP
資料表執行查詢。對於涉及多個壓縮表格的工作負載的更精細測試,請針對 Information Schema 的
INNODB_CMP_PER_INDEX
資料表執行查詢。由於INNODB_CMP_PER_INDEX
資料表中的統計資料收集成本很高,您必須先啟用組態選項innodb_cmp_per_index_enabled
,才能查詢該資料表,您可能會將此類測試限制在開發伺服器或非關鍵複本伺服器上。針對您正在測試的壓縮表格執行一些典型的 SQL 陳述式。
透過查詢
INFORMATION_SCHEMA.INNODB_CMP
或INFORMATION_SCHEMA.INNODB_CMP_PER_INDEX
,並比較COMPRESS_OPS
與COMPRESS_OPS_OK
,來檢查成功的壓縮操作與整體壓縮操作的比率。如果高百分比的壓縮操作成功完成,則該表格可能是壓縮的良好候選者。
如果您獲得高比例的壓縮失敗,您可以調整
innodb_compression_level
、innodb_compression_failure_threshold_pct
和innodb_compression_pad_pct_max
選項,如第 17.9.1.6 節「OLTP 工作負載的壓縮」中所述,並嘗試進一步的測試。
資料庫壓縮與應用程式壓縮
決定是在應用程式中還是表格中壓縮資料;不要對相同的資料使用兩種壓縮類型。當您在應用程式中壓縮資料並將結果儲存在壓縮表格中時,額外的空間節省非常不可能,而雙重壓縮只會浪費 CPU 週期。
在資料庫中壓縮
啟用時,MySQL 表格壓縮是自動的,並適用於所有欄位和索引值。欄位仍然可以使用 LIKE
等運算子進行測試,且即使索引值經過壓縮,排序操作仍然可以使用索引。由於索引通常佔資料庫總大小的很大一部分,壓縮可能會顯著節省儲存、I/O 或處理器時間。壓縮和解壓縮操作發生在資料庫伺服器上,該伺服器很可能是一個功能強大的系統,其大小足以處理預期的負載。
在應用程式中壓縮
如果您在應用程式中壓縮資料(例如文字),然後再將其插入資料庫,您可以透過僅壓縮某些欄位而不是全部欄位,來節省不適合壓縮的資料的額外負荷。這種方法在用戶端電腦上使用 CPU 週期進行壓縮和解壓縮,而不是在資料庫伺服器上,這可能適用於具有多個用戶端的分散式應用程式,或用戶端電腦有備用 CPU 週期的情況。
混合方法
當然,可以結合這些方法。對於某些應用程式,可能適合使用一些壓縮表格和一些未壓縮表格。最好外部壓縮某些資料(並將其儲存在未壓縮的表格中),並允許 MySQL 壓縮應用程式中的(部分)其他表格。一如既往,預先的設計和實際測試對於做出正確的決策非常重要。
工作負載特性與壓縮
除了選擇要壓縮的表格(以及頁面大小)之外,工作負載也是影響效能的另一個關鍵因素。如果應用程式以讀取為主,而非更新為主,則在索引頁面用完每頁的「修改記錄」的空間後(MySQL 為壓縮資料維護的記錄),需要重組和重新壓縮的頁面會比較少。如果更新主要變更的是未編製索引的欄位或包含 BLOB
或恰好儲存為「頁外」的大型字串的欄位,則壓縮的額外負荷可能是可以接受的。如果表格的唯一變更是使用單調遞增的主鍵的 INSERT
,且次要索引很少,則幾乎不需要重組和重新壓縮索引頁面。由於 MySQL 可以透過修改未壓縮的資料,在壓縮頁面上「刪除標記」和刪除資料列「就地」,因此對表格的 DELETE
操作相對有效率。
對於某些環境,載入資料所需的時間與執行階段擷取一樣重要。尤其是在資料倉儲環境中,許多表格可能是唯讀或幾乎唯讀的。在這些情況下,除非節省磁碟讀取次數或儲存成本的結果非常顯著,否則在載入時間增加方面付出壓縮代價可能是可以接受的,也可能不可接受。
從根本上來說,當 CPU 時間可用於壓縮和解壓縮資料時,壓縮效果最佳。因此,如果您的工作負載是 I/O 密集型,而不是 CPU 密集型,您可能會發現壓縮可以改善整體效能。當您使用不同的壓縮組態測試應用程式效能時,請在類似於生產系統規劃組態的平台上進行測試。
組態特性與壓縮
從磁碟讀取和寫入資料庫頁面是系統效能中最慢的一環。壓縮嘗試透過使用 CPU 時間來壓縮和解壓縮資料,從而減少 I/O,並且在 I/O 相較於處理器週期是相對稀缺資源時最有效。
在具有快速多核心 CPU 的多使用者環境中執行時,情況通常更是如此。當壓縮表格的頁面在記憶體中時,MySQL 通常會在 緩衝池中使用額外的記憶體(通常為 16KB)來儲存該頁面的未壓縮副本。適應性 LRU 演算法嘗試平衡壓縮和未壓縮頁面之間的記憶體使用,以考量工作負載是以 I/O 密集型還是 CPU 密集型方式執行。儘管如此,在記憶體高度受限的情況下,使用更多記憶體專用於緩衝池的組態,在搭配壓縮表格使用時,通常會比記憶體高度受限的組態執行得更好。
選擇壓縮頁面大小
壓縮頁面大小的最佳設定取決於表格及其索引包含的資料類型和分佈。壓縮頁面大小應始終大於最大記錄大小,否則操作可能會失敗,如B 樹頁面的壓縮中所述。
將壓縮頁面大小設定得太大會浪費一些空間,但頁面不需要經常壓縮。如果壓縮頁面大小設定得太小,插入或更新可能需要耗時的重新壓縮,且 B 樹節點可能需要更頻繁地分割,從而導致較大的資料檔案和效率較低的索引。
通常,您會將壓縮頁面大小設定為 8K 或 4K 位元組。 由於 InnoDB 表格的最大行大小約為 8K,因此 KEY_BLOCK_SIZE=8
通常是一個安全的選擇。