MySQL表壓縮和頁壓縮,難道只是空間壓縮?

本文章向大家介紹MySQL表壓縮和頁壓縮,難道只是空間壓縮?,主要內容包括表壓縮、TPC 壓縮( Innodb Transaparent PageIO Compression)、表壓縮在業務上的使用、頁壓縮元數據、頁壓縮限制和使用說明、小結、基本概念、基礎應用、原理機制和需要注意的事項等,並結合實例形式分析了其使用技巧,希望通過本文能幫助到大家理解應用這部分內容。

臨近春節,相信每個公司都會進行全面巡檢,無論是業務層還是數據庫層,達到事前預防的目的;今天就來分享一下針對MySQL數據存儲層面,在數據庫存儲來不及擴容的情況下,MySQL中的壓縮方案;

日常工作中很多業務在表結構設計之初不會考慮存儲的設計,只有當業務發展到一定規模纔會意識到問題的嚴重性。而物理存儲主要是考慮是否要啓用表的壓縮功能,默認情況下,所有表都是非壓縮的。但說到壓縮,總會下意識地認爲壓縮會導致 MySQL 數據庫的性能下降。這個觀點說對也不對,需要根據不同場景進行區分。

目前很多引擎表支持壓縮,比如 Myisam、InnoDB、TokuDB、MyRocks 。本文主要是針對Innodb引擎表壓縮進行說明,針對MyRocks引擎的詳細可參考:《RocksDB引擎和Innodb性能對比》

數據庫存儲磁盤如果是非SSD的,數據庫幾乎都是 IO 負載型的,在 CPU 有大量餘量的時候,磁盤 IO 的瓶頸就已經凸顯出來。而數據的大量存儲,尤其是日誌型數據,會導致磁盤空間快速增長。硬盤不夠用也會在很多業務中凸顯出來。一種比較好的方式就誕生了,那就是通過犧牲少量 CPU 資源,採用壓縮來減少磁盤空間佔用,以及優化 IO 和帶寬。尤其針對讀多寫少的業務。

如果存儲磁盤是SSD,數據庫的 IO 負載有所降低,但是對於磁盤空間的問題還是沒有很好的解決。因此壓縮表使用還是非常的廣泛。這也就是爲什麼那麼多的引擎都支持壓縮的原因。而 innodb 在 MySQL 5.5 的時候就支持了壓縮功能,只是壓縮比比較低,通常在 50%左右。而 TokuDB 能達到 80%左右,MyRocks 的壓縮比能達到 70%左右。

注意:壓縮比和你存儲的數據組成有很大的關係,並不是所有的數據都能達到上面所說的壓縮比。如果大部分都是字符串,並且重複的數據比較多,壓縮比會很好。

表壓縮

數據庫中的表是由一行行記錄(rows)所組成,每行記錄被存儲在一個頁中,在 MySQL 中,一個頁的大小默認爲 16K,一個個頁又組成了每張表的表空間。通常我們認爲,如果一個頁中存放的記錄數越多,數據庫的性能越高。這是因爲數據庫表空間中的頁是存放在磁盤上,MySQL 數據庫先要將磁盤中的頁讀取到內存緩衝池,然後以頁爲單位來讀取和管理記錄。

一個頁中存放的記錄越多,內存中能存放的記錄數也就越多,那麼存取效率也就越高。若想將一個頁中存放的記錄數變多,可以啓用壓縮功能。此外,啓用壓縮後,存儲空間佔用也變小了,同樣單位的存儲能存放的數據也變多了。

如果要使用 innodb 壓縮前提條件是:innodb_file_per_table 這個參數要啓用,innodb_file_format 這個參數設置成 Barracuda。

COMPRESS 頁壓縮是 MySQL 5.7 版本之前提供的頁壓縮功能。只要在創建表時指定ROW_FORMAT=COMPRESS,並設置通過選項 KEY_BLOCK_SIZE 設置壓縮的比例;如果沒有指定 KEY_BLOCK_SIZE 的大小,默認 KEY_BLOCK_SIZE 爲 innodb_page_size 大小的一半,也可以通過指定 KEY_BLOCK_SIZE=n 參數來開啓 innodb 的壓縮功能,n 可以爲 1、2、4、8、16,單位是 K。n 的值越小,壓縮比越高,消耗的 CPU 資源也越多。

注意:32K 或者 64K 的頁不支持壓縮。啓用壓縮後,索引數據也同樣會被壓縮。

也可以通過調整 innodb_compression_level 來設置壓縮的級別,級別從 1~9,默認是 6。級別越低,意味着壓縮比越高,同時也意味着需要更多的 CPU 資源。

啓用表的頁壓縮功能後,性能有明顯損失,因爲壓縮需要有額外的開銷。主要原因是一個壓縮頁在內存緩衝池中,存在壓縮和解壓兩個頁。在 buffer_pool 緩衝池中,壓縮的數據通過 KEY_BLOCK_SIZE 的大小的頁來保存,如果要提取壓縮的數據或者要更新壓縮數據對應的列,則會創建一個未壓縮頁來解壓縮數據,然後在數據更新完成後,會將爲壓縮頁的數據重新寫入到壓縮頁中。內存不足的時候,MySQL 會將對應的未壓縮頁踢出去。因此如果你啓用了壓縮功能,你的 buffer_pool 緩衝池中可能會存在壓縮頁和未壓縮頁,也可能只存在壓縮頁。不過可能仍然需要將你的 buffer_pool 緩衝池調大,以便能同時能保存壓縮頁和未壓縮頁。

如下是官方文檔描述:

In the buffer pool, the compressed data is held in small pages, with a page size based on the KEY_BLOCK_SIZE value. For extracting or updating the column values, MySQL also creates an uncompressed page in the buffer pool with the uncompressed data. Within the buffer pool, any updates to the uncompressed page are also re-written back to the equivalent compressed page. You might need to size your buffer pool to accommodate the additional data of both compressed and uncompressed pages, although the uncompressed pages are evicted from the buffer pool when space is needed, and then uncompressed again on the next access.

總之,COMPRESS 頁壓縮,適合用於一些對性能不敏感的業務表,例如日誌表等

爲了 解決壓縮性能下降的問題,從MySQL 5.7 版本開始推出了 TPC 壓縮功能,其利用文件系統的空洞(Punch Hole)特性進行壓縮。

TPC 壓縮( Innodb Transaparent PageIO Compression)

可以使用下面的命令創建 TPC 壓縮表:

CREATE TABLE Transaction (
id BINARY(16) PRIMARY KEY,
.....
)
COMPRESSION=ZLIB | LZ4 | NONE;

要使用 TPC 壓縮,首先要確認當前的操作系統是否支持空洞特性。通常來說,當前常見的 操作系統都已支持空洞特性:

 

在Linux系統上,文件系統塊大小是空洞特性的單位大小。因此,只有當頁面數據可以壓縮到小於或等於InnoDB頁面大小減去文件系統塊大小時,頁面壓縮才起作用。例如,如果innodb_page_size=16K,文件系統塊大小爲4K,則頁面數據必須壓縮到小於或等於12K,才能生效。

這是因爲不同於 COMPRESS 頁壓縮,TPC 壓縮在內存中只有一個 16K 的解壓縮後的頁,對於緩衝池沒有額外的存儲開銷。

表壓縮在業務上的使用

總的來說,對一些對性能不敏感的業務表,例如日誌表、賬單表等,它們只對存儲空間有要求,因此可以使用 COMPRESS 頁壓縮功能。

在一些較爲核心的流水業務表上,更推薦使用 TPC壓縮。因爲流水信息是一種非常核心的數據存儲業務,通常伴隨核心業務。如一筆交易,下單、記流水,這就是一個核心業務的模型。

所以,用戶對流水錶有性能需求。此外,流水又非常大,啓用壓縮功能可更爲有效地存儲數據。

若對壓縮產生的性能抖動有所擔心,我的建議:由於流水錶通常是按月或天進行存儲,對當前正在使用的流水錶不要啓用 TPC 功能,對已經成爲歷史的週期表啓用 TPC 壓縮功能,如下所示:

 

需要特別注意的是:通過命令 ALTER TABLE xxx COMPRESSION = ZLIB 可以啓用 TPC 頁壓縮功能,但是這隻對後續新增的數據會進行壓縮,對於原有的數據則不進行壓縮。所以上述ALTER TABLE 操作只是修改元數據,瞬間就能完成。

若想要對整個表進行壓縮,需要執行 OPTIMIZE TABLE 命令:

ALTER TABLE dic_history_202201 COMPRESSION=ZLIB;
OPTIMIZE TABLE dic_history_202201;

禁用頁面壓縮

使用ALTER TABLE將compression設置爲None。設置COMPRESSION=None後發生的表空間寫入不再使用頁壓縮。要解壓縮現有頁面,必須在設置COMPRESSION=None後使用OPTIMIZE table重新生成表。

ALTER TABLE dic_history_202201 COMPRESSION="None";
OPTIMIZE TABLE dic_history_202201;

頁壓縮元數據

頁壓縮元數據存儲在 INFORMATION_SCHEMA.INNODB_TABLESPACES表中,表中有三列:

FS_BLOCK_SIZE: The file system block size, which is the unit size used for hole punching. #文件系統塊大小 FILE_SIZE: The apparent size of the file, which represents the maximum size of the file, uncompressed. #文件的實際大小,表示未壓縮文件的最大大小 ALLOCATED_SIZE: The actual size of the file, which is the amount of space allocated on disk. # 文件的實際大小,即磁盤上分配的空間量

mysql>show create table employeesG
*************************** 1. row ***************************
Table: employees
Create Table: CREATE TABLE `employees` (
`emp_no` int NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` enum('M','F') NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMPRESSION='zlib'
1 row in set (0.00 sec)
 
mysql>SELECT SPACE, NAME, FS_BLOCK_SIZE, FILE_SIZE, ALLOCATED_SIZE FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='wjqtest/employees';
+-------+-------------------+---------------+-----------+----------------+
| SPACE | NAME | FS_BLOCK_SIZE | FILE_SIZE | ALLOCATED_SIZE |
+-------+-------------------+---------------+-----------+----------------+
| 265 | wjqtest/employees | 4096 | 114688 | 32768 |
+-------+-------------------+---------------+-----------+----------------+
1 row in set (0.00 sec)
 
# ls -l /data/mysql_8306/data/wjqtest/employees.ibd
-rw-r----- 1 mysql mysql 114688 Jan 11 11:22 /data/mysql_8306/data/wjqtest/employees.ibd
 
# du --block-size=1 /data/mysql_8306/data/wjqtest/employees.ibd
32768 /data/mysql_8306/data/wjqtest/employees.ibd

如上:在linux系統上,ls -l employees.ibd,以字節爲單位顯示明顯的文件大小(相當於文件大小)。要查看磁盤上實際分配的空間量(相當於分配的大小),使用du –block-size=1 employees.ibd。–block size=1選項以字節而不是塊的形式輸入分配的空間,查詢的結果和INFORMATION_SCHEMA.INNODB_TABLESPACES記錄的結果一致。

頁壓縮限制和使用說明

* 如果文件系統塊大小*2>innodb_頁面大小,則禁用頁面壓縮。 * 駐留在共享表空間(包括系統表空間、臨時表空間和常規表空間)中的表不支持頁面壓縮。 * undo/redo日誌表空間不支持頁面壓縮。 * 使用具有較大InnoDB頁面大小和相對較小文件系統塊大小的頁面壓縮功能可能會導致寫入放大。例如,最大InnoDB頁面大小爲64KB,文件系統塊大小爲4KB,這可能會提高壓縮,但也可能會增加對緩衝池的需求,從而增加I/O和潛在的寫放大。

小結

在進行表結構設計時,除了進行列的選擇外,還需要考慮存儲的設計,特別是對於表的壓縮功能的設計,總結來說:

* COMPRESS 頁壓縮適合用於性能要求不高的業務表,如日誌表等; * COMPRESS 頁壓縮內存緩衝池存在壓縮和解壓的兩個頁,會影響性能; * 對存儲有壓縮需求,又希望性能不要有明顯退化,推薦使用 TPC 壓縮; * 通過 ALTER TABLE 啓用 TPC 壓縮後,還需要執行命令 OPTIMIZE TABLE 才能立即完成空間的壓縮。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章