在 MySQL 官方文档中, 透明表空间压缩称为 InnoDB Page Compression 以区别于原来的 InnoDB Table Compression,但是其实它们都是基于页(Page)的压缩。

    透明表空间压缩应该写成 InnoDB Transparent Page Compression 更为贴切。

    官方文档:https://dev.mysql.com/doc/refman/5.7/en/innodb-page-compression.html
    官方博客:https://mysqlserverteam.com/innodb-transparent-page-compression/

    透明表空间压缩的创建

    1. -- 透明表空间压缩的创建
    2. mysql> create table trans_test_1 (a int ) compression="zlib"; -- 使用zlib的压缩算法
    3. Query OK, 0 rows affected, 1 warning (0.14 sec) -- 存在warning
    4. mysql> create table trans_test_2 (a int ) compression="lz4"; -- 使用lz4的压缩算法
    5. Query OK, 0 rows affected, 1 warning (0.13 sec)
    6. mysql> alter table trans_test_2 compression="zlib";
    7. Query OK, 0 rows affected (0.05 sec)
    8. Records: 0 Duplicates: 0 Warnings: 0
    9. mysql> optimize table trans_test_2; -- 官方文档中提及如果是已存在的表,需要执行optimize table操作
    10. +------------------------+----------+----------+-------------------------------------------------------------------+
    11. | Table | Op | Msg_type | Msg_text |
    12. +------------------------+----------+----------+-------------------------------------------------------------------+
    13. | burn_test.trans_test_2 | optimize | note | Table does not support optimize, doing recreate + analyze instead |
    14. | burn_test.trans_test_2 | optimize | status | OK |
    15. +------------------------+----------+----------+-------------------------------------------------------------------+
    16. 2 rows in set, 1 warning (0.18 sec) -- 还是有warning
    17. mysql> show create table trans_test_1\G
    18. *************************** 1. row ***************************
    19. Table: trans_test_1
    20. Create Table: CREATE TABLE `trans_test_1` (
    21. `a` int(11) DEFAULT NULL
    22. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMPRESSION='zlib'
    23. 1 row in set (0.00 sec)
    24. -- zlib的压缩比更高
    25. -- lz4的速度更快

    在上述创建过程中,并没有指定页大小,而是使用了文件系统(filesystem)层中稀疏文件的特性,来达到压缩的目的。

    稀疏文件
    图片.png
    如上图所示,可以简单的理解为,文件中数据连续为0的部分不占用磁盘空间。

    1. # 创建一个零时的,且数据部分全0的文件
    2. shell> dd of=sparse-file bs=1k seek=5120 count=0 # 创建5M大小,内容全为0的文件
    3. 0+0 records in
    4. 0+0 records out
    5. 0 bytes (0 B) copied, 6.7872e-05 s, 0.0 kB/s # 无数据写入到磁盘
    6. shell> ls -hl sparse-file
    7. -rw-r--r--. 1 root root 5.0M Jan 5 00:07 sparse-file # 显示该文件大小为5M
    8. shell> du --block-size=1 sparse-file # 检查文件占用多少空间
    9. 0 sparse-file # 显示占用空间为0

    图片.png

    • 压缩后,原来 16K 的数据压缩成了 4K
    • 剩余的 12K 空间用特殊的字符填充(比如说是0)
    • 在写入文件系统时调用 Punching holes 写入,实则只写入 4K 的数据
    • 被填充的 12K 的空间,可以提供给后序的插入,更新等使用
    • 从 InnoDB 的角度看还是 16K 的页大小,只是文件系统知道该页只需要 4K 就能够存储(对 InnoDB 是透明的)
    • SpaceID 和 PageNumber 的读取方式没有改变(细节由文件系统屏蔽)
    • 由于文件系统的快大小是 4K,所以压缩后存储的空间也是 4K 对齐的

      • 比如 16K 压缩成了 10K,那就需要3个 4K 去存储
        1. mysql> desc information_schema.INNODB_SYS_TABLESPACES;
        2. +----------------+---------------------+------+-----+---------+-------+
        3. | Field | Type | Null | Key | Default | Extra |
        4. +----------------+---------------------+------+-----+---------+-------+
        5. | SPACE | int(11) unsigned | NO | | 0 | |
        6. | NAME | varchar(655) | NO | | | |
        7. | FLAG | int(11) unsigned | NO | | 0 | |
        8. | FILE_FORMAT | varchar(10) | YES | | NULL | |
        9. | ROW_FORMAT | varchar(22) | YES | | NULL | |
        10. | PAGE_SIZE | int(11) unsigned | NO | | 0 | |
        11. | ZIP_PAGE_SIZE | int(11) unsigned | NO | | 0 | |
        12. | SPACE_TYPE | varchar(10) | YES | | NULL | |
        13. | FS_BLOCK_SIZE | int(11) unsigned | NO | | 0 | | -- 文件系统的块大小
        14. | FILE_SIZE | bigint(21) unsigned | NO | | 0 | | -- 文件大小
        15. | ALLOCATED_SIZE | bigint(21) unsigned | NO | | 0 | | -- 文件实际分配的大小
        16. | COMPRESSION | varchar(5) | NO | | | |
        17. +----------------+---------------------+------+-----+---------+-------+
        18. 12 rows in set (0.00 sec)
        操作系统要求
    • 操作系统以及内核

      • RHEL7 kernel >= 3.10.0-123
      • Debian 7 kernel >= 3.2
      • Ubuntu 12.04LTS kernel >= 3.2
      • Ubuntu 14.0.4LTS kernel >= 3.13
      • Oracle 和 Suse 可以参考官方文档
    • 文件系统
      • 支持 Hole Punch
      • 比如 XFS,EXT4,NTFS 等 ```sql mysql> show warnings; +————-+———+—————————————————————————————————————————————————————————————-+ | Level | Code | Message | +————-+———+—————————————————————————————————————————————————————————————-+ | Warning | 138 | InnoDB: Punch hole not supported by the file system or the tablespace page size is not large enough. Compression disabled | +————-+———+—————————————————————————————————————————————————————————————-+ 1 row in set (0.00 sec)

    — 原因1是我的内核版本太低,不支持 — 原因2是因为general方式安装的mysql不支持透明压缩,需要自己编译 — http://bugs.mysql.com/bug.php?id=77974 ```

    作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf/nf4rrq 来源:殷建卫 - 架构笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。