MySQL InnoDB支持数据压缩,有两种数据压缩方式,第一种为表压缩,通常也称之为行格式压缩,另外一种是页压缩(Page Compression),又叫做透明页压缩(Transparent Page Compression),是一种页面级别的数据压缩,页压缩对操作系统及文件系统有一定的要求。本文主要介绍页压缩的原理及使用方法。
页压缩只支持InnoDB独立表空间:file-per-table
页压缩需要操作系统具有稀疏文件(sparse file)或者文件打孔技术(hole punching)的支持,目前支持这种功能的主流操作系统如下:
- Windows NTFS
- RHEL 7 内核 3.10.0-123 及更高版本
- Ubuntu 14.0.4 LTS 内核 3.13 及更高版本
- Ubuntu 12.0.4 LTS 内核 3.2 及更高版本
- Debian 7 内核 3.2 及更高版本
1. 页压缩语法
在create table或者alter table时,加上 COMPRESSION 子句,支持的压缩算法主要有Zlib 和 LZ4。
开启页压缩:
CREATE TABLE t1 (c1 INT) COMPRESSION="zlib";
ALTER TABLE t1 COMPRESSION="zlib";
OPTIMIZE TABLE t1;
禁用页压缩:
ALTER TABLE t1 COMPRESSION="None";
OPTIMIZE TABLE t1;
2. 页压缩原理
当一个页被写入磁盘时,InnoDB使用指定的压缩算法对该页进行压缩,然后将压缩后的数据写入磁盘,此时打孔机制会将压缩后的页尾空闲块进行释放,以减少磁盘空间占用。如果压缩失败,则按照原样写入数据。
在Linux操作系统中,文件系统块大小是打孔的单位尺寸,因此,页压缩后的数据必须小于等于InnoDB页大小减去文件系统块大小的值,才能使页压缩生效。举个例子,InnoDB页大小16K,文件系统块大小4K,页数据必须被压缩到小于等于12K,才能使用打孔机制,减少磁盘空间占用。
在Windows操作系统中,稀疏文件基于NTFS文件系统压缩功能实现,打孔单位尺寸为NTFS压缩单元尺寸,这个尺寸是NTFS簇大小的16倍。NTFS簇大小与压缩单元大小对应关系如下表:
NTFS簇大小 | NTFS压缩单元大小 |
---|---|
512Bytes | 8KB |
1KB | 16KB |
2KB | 32KB |
4KB | 64KB |
同样的,只有当压缩后的数据小于等于InnoDB页大小减去压缩单元的大小时,才能使页压缩生效。默认的NTFS簇大小4KB,压缩单元大小64KB,这就意味着NTFS默认配置下,无法使用页压缩。因此,如果要想页压缩在NTFS文件系统上生效,需要设置NTFS簇大小为512Bytes,此时压缩单元大小为8KB,设置InnoDB页大小为默认的16KB,或者更大的32KB、64KB,才能使页压缩生效。
3. 页压缩的元数据
系统表 INNODB_SYS_TABLESPACES 存储了页压缩相关的元数据,其主要字段含义如下:
INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES
- FS_BLOCK_SIZE:文件系统块尺寸,打孔单元的大小。
- FILE_SIZE:表示未压缩文件的尺寸。
- ALLOCATED_SIZE:在磁盘上分配的文件的实际尺寸。
使用页压缩功能后,ls命令显示的大小是未压缩的大小,而实际的大小使用du命令查看。
- ls -l tablespace_name.ibd,显示FILE_SIZE大小
- du --block-size=1 tablespace_name.ibd,显示ALLOCATED_SIZE大小
4. 页压缩的限制和使用注意事项
- 如果文件系统块大小或者压缩单元大小乘以2大于innodb页大小时,页压缩将自动失效。
- 共享表空间(系统表空间,临时表空间,通用表空间)中的表不支持页压缩。
- undo log 和 redo log 表空间不支持页压缩。
- 空间索引 R-tree 页 不支持页压缩。
- 行格式压缩过的表(ROW_FORMAT=COMPRESSED),不支持页压缩。
- 在InnoDB崩溃恢复过程中,更新的页面将以未压缩的形式写出。
- 在一个不支持压缩算法的服务器上加载页压缩后的表空间,会导致I/O错误。
- 使用一个较大的innodb页大小,比如64KB,文件系统块大小4KB,这样的配置能够提高压缩效果,但是同时也会导致写放大,需要更大的buffer pool,增加I/O消耗。