mysql表數據壓縮

記得一次面試中,面試官問我是否知道表的壓縮,這個時候我才知道mysql有個表壓縮這麼個功能,今天試用下看看錶的壓縮率怎麼樣。mysql

這裏分兩個部分說明,第一部分:官方文檔說明;第二部分:具體實例測試。面試

【第一部分】算法

1、表壓縮概述:sql

表壓縮能夠在建立表時開啓,壓縮表可以使表中的數據以壓縮格式存儲,壓縮可以顯著提升原生性能和可伸縮性。壓縮意味着在硬盤和內存之間傳輸的數據更小且佔用相對少的內存及硬盤,對於輔助索引,這種壓縮帶來更加明顯的好處,由於索引數據也被壓縮了。壓縮對於硬盤是SSD的存儲設備尤其重要,由於它們相對普通的HDD硬盤比較貴且容量有限。數據庫

咱們都知道,CPU和內存的速度遠遠大於磁盤,由於對於數據庫服務器,磁盤IO可能會成爲緊要資源或者瓶頸。數據壓縮可以讓數據庫變得更小,從而減小磁盤的I/O,還能提升系統吞吐量,以很小的成本(耗費較多的CPU資源)。對於讀比重比較多的應用,壓縮是特別有用。壓縮可以讓系統擁有足夠的內存來存儲熱數據。服務器

在建立innodb表時帶上ROW_FORMAT=COMPRESSED參數可以使用比默認的16K更小的頁。這樣在讀寫時須要更少的I/O,對於SSD磁盤更有價值。數據結構

頁的大小經過KEY_BLOCK_SIZE參數指定。不一樣大小的頁意味着須要使用獨立表空間,不能使用系統共享表空間,能夠經過innodb_file_per_table指定。KEY_BLOCK_SIZE的值越小,你得到I/O好處就越多,可是若是由於你指定的值過小,當數據被壓縮到不足夠知足每頁多行數據記錄時,會產生額外的開銷來重組頁。對於一個表,KEY_BLOCK_SIZE的值有多小是有嚴格的限制的,通常是基於每一個索引鍵的長度。有時指定值太小,當create table或者alter table會失敗。性能

在緩衝池中,被壓縮的數據是存儲在小頁中的,這個小頁的實際大小就是KEY_BLOCK_SIZE的值。爲了提取和更新列值,mysql也會在緩衝池中建立一個未壓縮的16k頁。任何更新到未壓縮的頁也須要從新寫入到壓縮的頁,這時你須要估計緩衝池的大小以知足壓縮和未壓縮的頁,儘管當緩衝空間不足時,未壓縮的頁會被擠出緩衝池。在下次訪問時,不壓縮的頁還會被建立。測試

2、使用表的壓縮優化

在建立一個壓縮表以前,須要啓用獨立表空間參數innodb_file_per_table=1;也須要設置innodb_file_format=Barracuda,你能夠寫到my.cnf文件中不須要重啓mysql服務。

SET GLOBAL innodb_file_per_table=1;
SET GLOBAL innodb_file_format=Barracuda;
CREATE TABLE t1
 (c1 INT PRIMARY KEY) 
 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
  • 若是你指定ROW_FORMAT=COMPRESSED,那麼能夠忽略KEY_BLOCK_SIZE的值,這時使用默認innodb頁的一半,即8kb;
  • 若是你指定了KEY_BLOCK_SIZE的值,那麼你能夠忽略ROW_FORMAT=COMPRESSED,由於這時會自動啓用壓縮;
  • 爲了指定最合適KEY_BLOCK_SIZE的值,你能夠建立表的多個副本,使用不一樣的值進行測試,比較他們的.ibd文件的大小;
  • KEY_BLOCK_SIZE的值做爲一種提示,如必要,Innodb也可使用一個不一樣的值。0表明默認壓縮頁的值,Innodb頁的一半。KEY_BLOCK_SIZE的值只能小於等於innodb page size。若是你指定了一個大於innodb page size的值,mysql會忽略這個值而後產生一個警告,這時KEY_BLOCK_SIZE的值是Innodb頁的一半。若是設置了innodb_strict_mode=ON,那麼指定一個不合法的KEY_BLOCK_SIZE的值是返回報錯。

InnoDB未壓縮的數據頁是16K,根據選項組合值,mysql爲每一個表的.ibd文件使用1kb,2kb,4kb,8kb,16kb頁大小,實際的壓縮算法並不會受KEY_BLOCK_SIZE值影響,這個值只是決定每一個壓縮塊有多大,從而影響多少行被壓縮到每一個頁。設置KEY_BLOCK_SIZE等於16k並不能有效的進行壓縮,由於默認的innodb頁就是16k,可是對於擁有不少BLOB,TEXT,VARCHAR類型字段的表可能會有效果的。

3、InnoDB表的壓縮優化

 在進行表壓縮時須要考慮影響壓縮性能的因素,如:

  • 哪些表須要壓縮
  • 如何選擇壓縮表的頁大小
  • 基於運行時性能特徵是否須要調整buffer pool大小,如系統在壓縮和解壓縮數據所花費的時間量,系統負載更像一個數據倉庫仍是OLTP事務性系統。
  • 若是在壓縮表上執行DML操做,因爲數據分佈的方式,可能致使壓縮失敗,這時你可能須要配置額外的更高級的配置選項

一、什麼時候用壓縮表

通常而言,對於讀遠遠大於寫的應用以及擁有合理數量的字符串列的表,使用壓縮效果會更好。

二、數據特性及壓縮率

影響數據文件壓縮效率的一個關鍵因素是數據自己的結構,在塊數據中,壓縮是經過識別重複字符進行壓縮的,對於徹底隨機的數據是一個糟糕的狀況,通常而言,有重複數據的壓縮更好。對於字符串的列壓縮就不錯,不管是string仍是blob、text等類型的。另外一方面,若是表中的數據是二進制類型,如整形、浮點型等或者以前別壓縮過的如jpg、png類型的,壓縮效果通常很差,但也不是絕對的。

爲了決定是否對某個表進行壓縮,你須要進行試驗,能夠對比未壓縮與壓縮後的數據文件的大小,以及監控系統對於壓縮表的工做負載進行決定。具體試驗請查看第二部分。

查看監控壓縮表的負載,以下:

  • 對於簡單的測試,如一個mysql實例上沒有其餘的壓縮表了,直接查詢INFORMATION_SCHEMA.INNODB_CMP表數據便可,該表存一些壓縮表的數據狀態,結構以下:
Column name Description
PAGE_SIZE 採用壓縮頁大小(字節數).
COMPRESS_OPS Number of times a B-tree page of the size PAGE_SIZE has been compressed. Pages are compressed whenever an empty page is created or the space for the uncompressed modification log runs out.
COMPRESS_OPS_OK Number of times a B-tree page of the size PAGE_SIZE has been successfully compressed. This count should never exceed COMPRESS_OPS.
COMPRESS_TIME Total time in seconds spent in attempts to compress B-tree pages of the size PAGE_SIZE.
UNCOMPRESS_OPS Number of times a B-tree page of the size PAGE_SIZE has been uncompressed. B-tree pages are uncompressed whenever compression fails or at first access when the uncompressed page does not exist in the buffer pool.
UNCOMPRESS_TIME Total time in seconds spent in uncompressing B-tree pages of the size PAGE_SIZE.
  • 對於精細的測試,如多個壓縮表,查詢INFORMATION_SCHEMA.INNODB_CMP_PER_INDEX表數據,因爲該表收集數據須要付出昂貴得代價,因此必須啓動innodb_cmp_per_index_enabled選項才能查詢。通常不要在生產環境下開啓該選項。
  • 還能夠針對壓縮運行一些測試SQL看看效率如何。
  • 若是發現不少壓縮失敗,那麼你能夠調整innodb_compression_level, innodb_compression_failure_threshold_pct, 和innodb_compression_pad_pct_max參數。

三、數據庫壓縮和應用程序壓縮

不須要在應用端和數據庫同時壓縮相同的數據,那樣效果並不明顯並且還消耗不少CPU資源。對於數據庫壓縮,是在server端進行的。若是你在插入數據前經過代碼進行數據壓縮,而後插入數據庫,這樣耗費不少CPU資源,固然若是你的CPU有大量結餘。你也能夠結合二者,對於某些表進行應用程序壓縮,而對其餘數據採用數據庫壓縮。

四、工做負載特性和壓縮率

爲了選擇哪些表可使用壓縮,工做負載是另外一個決定因素,通常而言,若是你的系統是I/O瓶頸,那麼可使用CPU進行壓縮與解壓縮,以CPU換取I/O。

4、INNODB表是如何壓縮的?

一、壓縮算法

mysql進行壓縮是藉助於zlib庫,採用L777壓縮算法,這種算法在減小數據大小、CPU利用方面是成熟的、健壯的、高效的。同時這種算法是無失真的,所以原生的未壓縮的數據老是可以從壓縮文件中重構,LZ777實現原理是查找重複數據的序列號而後進行壓縮,因此數據模式決定了壓縮效率,通常而言,用戶的數據可以被壓縮50%以上。

不一樣於應用程序壓縮或者其餘數據庫系統的壓縮,InnoDB壓縮是同時對數據和索引進行壓縮,不少狀況下,索引可以佔數據庫總大小的40%-50%。若是壓縮效果很好,通常innodb文件會減小25%-50%或者更多,並且減小I/O增長系統吞吐量,可是會增長CPU的佔用,你可經過設置innodb_compression_level參數來平衡壓縮級別和CPU佔用。

二、InnoDB數據存儲及壓縮

全部數據和b-tree索引都是按頁進行存儲的,每行包含主鍵和表的其餘列。輔助索引也是b-tree結構的,包含對值:索引值及指向每行記錄的指針,這個指針實際上就是表的主鍵值。

在innodb壓縮表中,每一個壓縮頁(1,2,4,8)都對應一個未壓縮的頁16K,爲了訪問壓縮頁中的數據,若是該頁在buffer pool中不存在,那麼就從硬盤上讀到這個壓縮頁,而後進行解壓到原來的數據結構。爲了最小化I/O和減小解壓頁的次數,有時,buffer pool中包括壓縮和未壓縮的頁,爲給其餘頁騰出地方,buffer pool會驅逐未壓縮頁,僅僅留下壓縮頁在內存中。或者若是一個頁一段時間沒有被訪問,那麼會被寫到硬盤上。這樣一來,任什麼時候候,buffer pool中均可以包含壓縮頁和未壓縮頁,或者只有壓縮頁或者二者都沒有。

Mysql採用LRU算法來保證哪些頁應該在內存中仍是被驅逐。所以熱數據通常都會在內存中。

5、OLTP系統壓縮負載優化

通常而言,innodb壓縮對於只讀或者讀比重比較多的應用效果更好,SSD的出現,使得壓縮更加吸引咱們,尤爲對於OLTP系統。對於常常update、delete、insert的應用,經過壓縮表可以減小他們的存儲需求和每秒I/O操做。

下面是針對寫密集的應用,設置壓縮表的一些有用參數:

  • innodb_compression_level:決定壓縮程度的參數,若是你設置比較大,那麼壓縮比較多,耗費的CPU資源也較多;相反,若是設置較小的值,那麼CPU佔用少。默認值6,能夠設置0-9
  • innodb_compression_failure_threshold_pct:默認值5,範圍0到100.設置中斷點避免高昂的壓縮失敗率。
  • innodb_compression_pad_pct_max:指定在每一個壓縮頁面能夠做爲空閒空間的最大比例,該參數僅僅應用在設置了innodb_compression_failure_threshold_pct不爲零狀況下,而且壓縮失敗率經過了中斷點。默認值50,能夠設置範圍是0到75.

【第二部分】實驗:

#沒有設置壓縮前的數據大小
-rw-rw----. 1 mysql mysql 368M 12月 29 11:05 test.ibd
#設置KEY_BLOCK_SIZE=1
(product)root@localhost [sakila]> alter table test KEY_BLOCK_SIZE=1;
Query OK, 0 rows affected (14 min 49.30 sec)
Records: 0  Duplicates: 0  Warnings: 0

-rw-rw----. 1 mysql mysql 204M 1月  11 21:43 test.ibd      #####壓縮率44.5%
#設置KEY_BLOCK_SIZE=2 (product)root@localhost [sakila]> alter table test KEY_BLOCK_SIZE=2; Query OK, 0 rows affected (9 min 55.60 sec) Records: 0 Duplicates: 0 Warnings: 0 -rw-rw----. 1 mysql mysql 180M 1月 12 13:40 test.ibd #####壓縮率51% #設置KEY_BLOCK_SIZE=4 (product)root@localhost [sakila]> alter table test KEY_BLOCK_SIZE=4; Query OK, 0 rows affected (7 min 24.52 sec) Records: 0 Duplicates: 0 Warnings: 0 -rw-rw----. 1 mysql mysql 172M 1月 11 21:09 test.ibd #####壓縮率53.2% #設置KEY_BLOCK_SIZE=8 (product)root@localhost [sakila]> alter table test KEY_BLOCK_SIZE=8; Query OK, 0 rows affected (5 min 16.34 sec) Records: 0 Duplicates: 0 Warnings: 0 -rw-rw----. 1 mysql mysql 172M 1月 11 21:00 test.ibd #####壓縮率53.2% #設置KEY_BLOCK_SIZE=16 (product)root@localhost [sakila]> alter table test KEY_BLOCK_SIZE=16; Query OK, 0 rows affected (2 min 47.48 sec) Records: 0 Duplicates: 0 Warnings: 0 -rw-rw----. 1 mysql mysql 336M 1月 12 13:54 test.ibd #####壓縮率8.6%  

【總結】:經過以上測試可知,當KEY_BLOCK_SIZE的值設置爲4或者8時,壓縮效果最好,設置爲16效果最差,由於頁的默認值16K。一般我是設置爲8。

相關文章
相關標籤/搜索