大多數時候,InnoDB 資料儲存和壓縮中描述的內部最佳化會確保系統使用壓縮資料良好運行。但是,由於壓縮效率取決於資料的性質,您可以做出會影響壓縮表格效能的決策
使用本節中的指南來協助您做出這些架構和配置選擇。當您準備好進行長期測試並將壓縮表格投入生產時,請參閱第 17.9.1.4 節,「在執行階段監控 InnoDB 表格壓縮」,以了解如何在真實環境下驗證這些選擇的有效性。
何時使用壓縮
一般而言,壓縮最適合包含大量字串欄位的表格,且資料讀取的頻率遠高於寫入頻率。由於沒有任何保證的方法可以預測壓縮是否對特定情況有利,因此請始終使用特定的工作負載和資料集在具代表性的組態上進行測試。在決定要壓縮哪些表格時,請考慮下列因素。
資料特性和壓縮
壓縮在縮減資料檔案大小方面的效率關鍵決定因素是資料本身的性質。請回想一下,壓縮的運作方式是識別資料區塊中重複的位元組字串。完全隨機化的資料是最壞的情況。一般資料通常具有重複的值,因此可以有效地壓縮。字串通常壓縮效果良好,無論是定義在 CHAR
、VARCHAR
、TEXT
還是 BLOB
欄位中。另一方面,主要包含二進位資料(整數或浮點數)或先前壓縮的資料(例如JPEG或PNG影像)的表格通常可能無法有效壓縮、顯著壓縮或根本無法壓縮。
您可以選擇是否為每個 InnoDB 表格啟用壓縮。一個表格及其所有索引使用相同的(壓縮後)頁面大小。有可能包含表格所有欄位資料的主鍵(叢集)索引,會比次要索引更有效率地壓縮。對於具有長資料列的情況,使用壓縮可能會導致長欄位值被儲存在「頁外」,如同DYNAMIC 資料列格式中所討論。這些溢出頁面可能會壓縮得很好。考慮到這些因素,對於許多應用程式而言,某些表格的壓縮效率會高於其他表格,您可能會發現只有壓縮部分表格時,您的工作負載才能達到最佳效能。
為了決定是否壓縮特定表格,請進行實驗。您可以使用實作 LZ77 壓縮的工具(例如 gzip
或 WinZip)在未壓縮表格的 .ibd 檔案副本上,粗略估計您的資料可以被壓縮的效率。您預期從 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 週期而言是稀缺資源時,壓縮最有效。
當在具有快速、多核心 CPU 的多使用者環境中執行時,通常尤其如此。當壓縮表格的頁面在記憶體中時,MySQL 通常會在緩衝池中為頁面的未壓縮副本使用額外的記憶體,通常為 16KB。自我調整 LRU 演算法嘗試平衡壓縮頁面和未壓縮頁面之間的記憶體使用量,以考慮工作負載是以 I/O 限制或 CPU 限制的方式執行。儘管如此,與記憶體高度受限的配置相比,具有更多專用於緩衝池的記憶體配置往往在使用壓縮表格時執行效果更好。
選擇壓縮頁面大小
壓縮頁面大小的最佳設定取決於表格及其索引所包含的資料類型和分佈。壓縮頁面大小應始終大於最大記錄大小,否則操作可能會失敗,如B 樹頁面的壓縮中所述。
將壓縮頁面大小設定得太大會浪費一些空間,但頁面不必經常被壓縮。如果壓縮頁面大小設定得太小,則插入或更新可能需要耗時的重新壓縮,並且 B 樹節點可能必須更頻繁地分割,從而導致更大的資料檔案和效率較低的索引。
通常,您將壓縮頁面大小設定為 8K 或 4K 位元組。鑑於 InnoDB 表格的最大資料列大小約為 8K,KEY_BLOCK_SIZE=8
通常是一個安全的選擇。