MySQL5.7 InnoDB Page Compression

来源:互联网 发布:淘宝怎样申请退货退款 编辑:程序博客网 时间:2024/06/01 21:10

1、介绍

mysql5.7中,innodb页结构增加了一个类型FIL_PAGE_COMPRESSED,用来完成Transparent page compression 特性

2、说明

1)压缩内容包括:除去FIL_PAGE_DATA外所有数据,包括tail
2)压缩后的内容+FIL_PAGE_DATA会以block_size对齐,并将空洞清0。意味着将16K压缩到9K,也需要12KB的数据,因此将block_size设小点,这样的场景将受益,可以
   减少空间浪费。
3)FIL_PAGE_VERSION内容存1;FIL_PAGE_ALGORITHM_V1指哪个压缩算法:ZLIB、LZ4
   FIL_PAGE_ORIGINAL_TYPE_V1:原始页类型;
   FIL_PAGE_ORIGINAL_SIZE_V1:原始页需要压缩的内容大小
   FIL_PAGE_COMPRESS_SIZE_V1:内容压缩后大小
4)目前支持2种压缩算法:zlib和lz4,可以方便扩展新的算法
5)压缩只是在持久化磁盘的时候压缩,内存中的页仍然是原始的样子

3、用法

表定义:
可以通过CREATE TABLE、ALTER TABLE来定义压缩表:
  create table t1(i int,b blob) compression='zlib';
也可以选择compression='lz4'来指定lz4压缩算法,注意compression属性的ALTER是立即生效,在做完ALTER COMPRESSION属性操作后,需要做一次表的rebuild,例如optimize table操作,才能对已有的数据做punch hole。compression属性存储在frm文件中,以2个字节存储字符串长度,随后存储compression属性定义字符串,这也是一个操作系统降级的风险点。

4、代码分析

staticbyte*os_file_compress_page(Compressioncompression,ulintblock_size,//文件系统block大小。通常4Kbyte*src,//需要压缩页的指针ulintsrc_len,//页大小byte*dst,//压缩后,存入目标ulint*dst_len)//压缩内存长度{ulintlen = 0;ulintcompression_level = page_zip_level;ulintpage_type = mach_read_from_2(src + FIL_PAGE_TYPE);//如果要节省空间,页大小至少是文件系统block的2倍。压缩的页不包括R-tree页if (page_type == FIL_PAGE_RTREE    || block_size == ULINT_UNDEFINED    || compression.m_type == Compression::NONE    || src_len < block_size * 2) {*dst_len = src_len;return(src);}/* Must compress to <= N-1 FS blocks. */ulintout_len = src_len - (FIL_PAGE_DATA + block_size);/* This is the original data page size - the page header. */ulintcontent_len = src_len - FIL_PAGE_DATA;/* Only compress the data + trailer, leave the header alone */switch (compression.m_type) {case Compression::NONE:ut_error;case Compression::ZLIB: {uLongfzlen = static_cast<uLongf>(out_len);if (compress2(dst + FIL_PAGE_DATA,&zlen,src + FIL_PAGE_DATA,static_cast<uLong>(content_len),static_cast<int>(compression_level)) != Z_OK) {*dst_len = src_len;return(src);}len = static_cast<ulint>(zlen);break;}case Compression::LZ4:len = LZ4_compress_default(reinterpret_cast<char*>(src) + FIL_PAGE_DATA,reinterpret_cast<char*>(dst) + FIL_PAGE_DATA,static_cast<int>(content_len),static_cast<int>(out_len));if (len == 0  || len >= out_len) {*dst_len = src_len;return(src);}break;default:*dst_len = src_len;return(src);}/* Copy the header as is. */memmove(dst, src, FIL_PAGE_DATA);/* Add compression control information. Required for decompressing. */mach_write_to_2(dst + FIL_PAGE_TYPE, FIL_PAGE_COMPRESSED);mach_write_to_1(dst + FIL_PAGE_VERSION, 1);mach_write_to_1(dst + FIL_PAGE_ALGORITHM_V1, compression.m_type);mach_write_to_2(dst + FIL_PAGE_ORIGINAL_TYPE_V1, page_type);mach_write_to_2(dst + FIL_PAGE_ORIGINAL_SIZE_V1, content_len);mach_write_to_2(dst + FIL_PAGE_COMPRESS_SIZE_V1, len);/* Round to the next full block size */len += FIL_PAGE_DATA;*dst_len = ut_calc_align(len, block_size);/* Clear out the unused portion of the page. */if (len % block_size) {memset(dst + len, 0x0, block_size - (len % block_size));}return(dst);}
5、参考

http://mysql.taobao.org/monthly/2015/08/01/
http://mysqlserverteam.com/innodb-transparent-page-compression/