
# 字段压缩
#### 操作场景
为了减少数据页面存储空间占用，节省成本，TaurusDB推出细粒度的字段压缩，提供ZLIB和ZSTD两种压缩算法，用户可以综合考虑压缩比和压缩解压性能影响，选择合适的压缩算法，对不频繁访问的大字段进行压缩。同时，字段压缩特性提供自动压缩的能力，帮助用户更方便地使用此特性。
#### 使用须知
- TaurusDB实例内核版本大于等于2.0.54.240600可使用该功能。内核版本的查询方法请参见[如何查看云数据库 TaurusDB实例的版本号](https://support.huaweicloud.com/taurusdb_faq/taurusdb_faq_0141.html)。
- 不支持分区表、临时表、非InnoDB引擎表。
- 压缩字段上不能包含索引(主键、唯一索引、二级索引、外键、全文索引)。
- 仅支持的数据类型：BLOB（包含TINYBLOB、BLOB、MEDIUMBLOB、LONGBLOB），TEXT（包含TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT），VARCHAR，VARBINARY。
- 不支持在生成列上使用此特性。
- 不支持在分区表和带有压缩字段的表之间执行EXCHANGE PARTITION式语句。
- 不支持IMPORT TABLESPACE。
- 仅支持在CREATE TABLE/ALTER TABLE ADD/ALTER TABLE CHANGE/ALTER TABLE MODIFY场景使用此特性。
- ALTER TABLE ADD COLUMN不支持INSTANT算法，ALTER TABLE {CHANGE\|MODIFY} 语法涉及数据变化时不支持使用INSTANT算法。
- 自动压缩场景(rds_column_compression=2)，定义字段的最大长度需大于等于字段压缩阈值(rds_column_compression_threshold)时才可以被添加压缩属性；显式压缩场景(rds_column_compression=1)，若定义压缩字段的最大长度小于字段压缩阈值，字段仍可被添加压缩属性，同时收到warning信息。
- 若当前表中包含压缩字段，暂不支持NDP计算下推。
- 客户手动拉取BINLOG同步过程中ALTER语句会出现不兼容的问题，推荐客户侧使用HINT的方式来解决。
- 利用DRS迁移至无该特性的实例，压缩属性被消除。全量迁移任务可以进行，增量迁移时ALTER语句中存在压缩字段会导致迁移任务失败。
- 物理备份方面，利用备份去做数据恢复的版本也必须是带有字段压缩特性的。
- 升级至新版本之后，如果已经使用字段压缩功能，不支持回退至无该特性的版本。
 
#### 语法
扩展column_definition定义，支持在CREATE TABLE/ALTER TABLE ADD/ALTER TABLE CHANGE/ALTER TABLE MODIFY场景定义列属性时使用压缩特性。
```
create_definition: {
    col_name column_definition
  | {INDEX | KEY} [index_name] [index_type] (key_part,...)
      [index_option] ...
  | {FULLTEXT | SPATIAL} [INDEX | KEY] [index_name] (key_part,...)
      [index_option] ...
  | [CONSTRAINT [symbol]] PRIMARY KEY
      [index_type] (key_part,...)
      [index_option] ...
  | [CONSTRAINT [symbol]] UNIQUE [INDEX | KEY]
      [index_name] [index_type] (key_part,...)
      [index_option] ...
  | [CONSTRAINT [symbol]] FOREIGN KEY
      [index_name] (col_name,...)
      reference_definition
  | check_constraint_definition
}
alter_option: {
    table_options
  | ADD [COLUMN] col_name column_definition
        [FIRST | AFTER col_name]
  | ADD [COLUMN] (col_name column_definition,...)
  | CHANGE [COLUMN] old_col_name new_col_name column_definition
        [FIRST | AFTER col_name]
  | MODIFY [COLUMN] col_name column_definition
        [FIRST | AFTER col_name]
  ...
```
其中column_definition为：
```
column_definition: {
    data_type [NOT NULL | NULL] [DEFAULT {literal | (expr)} ]
      [VISIBLE | INVISIBLE]
      [AUTO_INCREMENT] [UNIQUE [KEY]] [[PRIMARY] KEY]
      [COMMENT 'string']
      [COLLATE collation_name]
      [COLUMN_FORMAT {FIXED | DYNAMIC | DEFAULT}]
      [COLUMN_FORMAT {FIXED|DYNAMIC|DEFAULT}|COMPRESSED[={ZLIB|ZSTD}**]]
      [ENGINE_ATTRIBUTE [=] 'string']
      [SECONDARY_ENGINE_ATTRIBUTE [=] 'string']
      [STORAGE {DISK | MEMORY}]
      [reference_definition]
      [check_constraint_definition]
  | data_type
      [COLLATE collation_name]
      [GENERATED ALWAYS] AS (expr)
      [VIRTUAL | STORED] [NOT NULL | NULL]
      [VISIBLE | INVISIBLE]
      [UNIQUE [KEY]] [[PRIMARY] KEY]
      [COMMENT 'string']
      [reference_definition]
      [check_constraint_definition]
}
```
#### 特性参数说明
表1参数说明 
| 参数名称                                     | 描述                                                                                                                                                                                                                                                                                                                                                                                                                                             | 取值范围              | 默认值  | 级别     | 是否动态生效 |
|:---|:---|:---|:---|:---|:---|
| rds_column_compression                   | - 当参数取值为0时，表示字段压缩特性关闭，不再支持显式或者自动创建压缩列。  - 当参数取值为1时，表示仅支持显式创建压缩列。  - 当参数取值为2时，表示同时支持显式或自动创建压缩列。   | \[0,2\]           | 0    | GLOBAL | 是      |
| rds_default_column_compression_algorithm | 设置字段压缩特性默认的压缩算法，适用于如下场景： - 显式创建压缩字段而不指定具体的压缩算法。  - 自动压缩场景。                                                                                           | ZLIB或ZSTD         | ZLIB | GLOBAL | 是      |
| rds_column_compression_threshold         | 设置字段压缩特性的阈值。 - 当列定义最大长度小于此阈值时，可以显式创建压缩列，但会收到提示信息，不能自动地创建压缩列。  - 当列定义最大长度大于等于此阈值时，支持显式或者自动创建压缩列。                                                      | \[20-4294967295\] | 100  | GLOBAL | 是      |
| rds_zlib_column_compression_level        | 控制字段压缩特性中zlib压缩算法的压缩级别。 - 当参数取值为0时代表不压缩。  - 取值为除0外范围内的其他参数值时，取值越小，压缩速度越快但压缩效果越差；取值越大，压缩速度越慢但压缩效果越好。                                         | \[0,9\]           | 6    | GLOBAL | 是      |
| rds_zstd_column_compression_level        | 控制字段压缩特性中zstd压缩算法的压缩级别。 取值越小，压缩速度越快但压缩效果越差；取值越大，压缩速度越慢但压缩效果越好。                                                                                                                                                                                                                                                                                                                                  | \[1,22\]          | 3    | GLOBAL | 是      |
   
#### 使用示例
1. 显式创建压缩字段。
   ```
   mysql> show variables like 'rds_column_compression';
   +------------------------+-------+
   | Variable_name          | Value |
   +------------------------+-------+
   | rds_column_compression | 1     |
   +------------------------+-------+
   1 row in set (0.00 sec)
   mysql> show variables like 'rds_default_column_compression_algorithm';
   +------------------------------------------+-------+
   | Variable_name                            | Value |
   +------------------------------------------+-------+
   | rds_default_column_compression_algorithm | ZLIB  |
   +------------------------------------------+-------+
   1 row in set (0.00 sec)
   mysql> create table t1(c1 varchar(100) compressed, c2 varchar(100) compressed=zlib, c3 varchar(100) compressed=zstd) default charset=latin1;
   Query OK, 0 rows affected (0.06 sec)
   mysql> show create table t1\G
   *************************** 1. row ***************************
   Table: t1
   Create Table: CREATE TABLE `t1` (
   `c1` varchar(100) /*!99990 800220201 COMPRESSED=ZLIB */ DEFAULT NULL,
   `c2` varchar(100) /*!99990 800220201 COMPRESSED=ZLIB */ DEFAULT NULL,
   `c3` varchar(100) /*!99990 800220201 COMPRESSED=ZSTD */ DEFAULT NULL
   ) ENGINE=InnoDB DEFAULT CHARSET=latin1
   1 row in set (0.00 sec)
   ```
   
2. 自动创建压缩字段。
   ```
   mysql> set global rds_column_compression = 2;
   Query OK, 0 rows affected (0.00 sec)
   mysql> show variables like 'rds_column_compression';
   +------------------------+-------+
   | Variable_name          | Value |
   +------------------------+-------+
   | rds_column_compression | 2     |
   +------------------------+-------+
   1 row in set (0.01 sec)
   mysql> show variables like 'rds_column_compression_threshold';
   +----------------------------------+-------+
   | Variable_name                    | Value |
   +----------------------------------+-------+
   | rds_column_compression_threshold | 100   |
   +----------------------------------+-------+
   1 row in set (0.01 sec)
   mysql> show variables like 'rds_default_column_compression_algorithm';
   +------------------------------------------+-------+
   | Variable_name                            | Value |
   +------------------------------------------+-------+
   | rds_default_column_compression_algorithm | ZLIB  |
   +------------------------------------------+-------+
   1 row in set (0.01 sec)
   mysql> create table t2(c1 varchar(99), c2 varchar(100)) default charset=latin1;
   Query OK, 0 rows affected (0.05 sec)
   mysql> show create table t2\G
   *************************** 1. row ***************************
   Table: t2
   Create Table: CREATE TABLE `t2` (
   `c1` varchar(99) DEFAULT NULL,
   `c2` varchar(100) /*!99990 800220201 COMPRESSED=ZLIB */ DEFAULT NULL
   ) ENGINE=InnoDB DEFAULT CHARSET=latin1
   1 row in set (0.01 sec)
   ```
   
3. 关闭特性。
   ```
   mysql> set global rds_column_compression = 0;
   Query OK, 0 rows affected (0.00 sec)
   mysql> show variables like 'rds_column_compression';
   +------------------------+-------+
   | Variable_name          | Value |
   +------------------------+-------+
   | rds_column_compression | 0     |
   +------------------------+-------+
   1 row in set (0.01 sec)
   mysql> show variables like 'rds_column_compression_threshold';
   +----------------------------------+-------+
   | Variable_name                    | Value |
   +----------------------------------+-------+
   | rds_column_compression_threshold | 100   |
   +----------------------------------+-------+
   1 row in set (0.01 sec)
   mysql> create table t3(c1 varchar(100) compressed, c2 varchar(100) compressed=zlib, c3 varchar(100) compressed=zstd) default charset=latin1;
   Query OK, 0 rows affected, 3 warnings (0.04 sec)
   mysql> show create table t3\G
   *************************** 1. row ***************************
   Table: t3
   Create Table: CREATE TABLE `t3` (
   `c1` varchar(100) DEFAULT NULL,
   `c2` varchar(100) DEFAULT NULL,
   `c3` varchar(100) DEFAULT NULL
   ) ENGINE=InnoDB DEFAULT CHARSET=latin1
   1 row in set (0.01 sec)
   ```
   
 
#### 确认效果
1. 通过执行show create table语句展示表结构信息，发现其中包含/\*!99990 800220201 COMPRESSED=xxxx \*/的内容，可认为已使用字段压缩特性。 例如：
   ```
   mysql> show create table t1\G
   *************************** 1. row ***************************
          Table: t1
   Create Table: CREATE TABLE `t1` (
     `c1` varchar(100) /*!99990 800220201 COMPRESSED=ZLIB */ DEFAULT NULL,
     `c2` varchar(100) /*!99990 800220201 COMPRESSED=ZLIB */ DEFAULT NULL,
     `c3` varchar(100) /*!99990 800220201 COMPRESSED=ZSTD */ DEFAULT NULL
   ) ENGINE=InnoDB DEFAULT CHARSET=latin1
   1 row in set (0.00 sec)
   ```
   
2. 利用系统视图information_schema.columns查询压缩字段。 例如：
   ```
   mysql> select TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, EXTRA from information_schema.columns where extra like '%compressed%';
   +--------------+------------+-------------+-----------------+
   | TABLE_SCHEMA | TABLE_NAME | COLUMN_NAME | EXTRA           |
   +--------------+------------+-------------+-----------------+
   | test         | t1         | c1          | COMPRESSED=ZLIB |
   | test         | t1         | c2          | COMPRESSED=ZLIB |
   | test         | t1         | c3          | COMPRESSED=ZSTD |
   | test         | t2         | c2          | COMPRESSED=ZLIB |
   +--------------+------------+-------------+-----------------+
   4 rows in set (0.50 sec)
   ```
   
3. 通过查询status信息，以确认字段压缩或解压缩接口的实际调用次数。
   ```
   mysql> show global status like '%column%compress%';
   +--------------------------------+-------+
   | Variable_name                  | Value |
   +--------------------------------+-------+
   | Innodb_column_compress_count   | 243   |
   | Innodb_column_uncompress_count | 34    |
   +--------------------------------+-------+
   ```
   
4. 通过执行如下语句或者查看监控界面信息，对比压缩前后表占用大小，确认压缩效果。
   ```
   SELECT table_name AS `Table`, round(((data_length + index_length) / 1024 / 1024), 2) AS `Size in MB` FROM information_schema.TABLES WHERE table_schema = "***" and table_name='***'
   ```
   
 
#### 压缩比和性能影响验证
1. 插入随机数据场景，表中有1万行数据，每行是由400个MD5函数返回的32位字符串构成。
   ```
   CREATE TABLE `random_data` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `data` longtext,
   PRIMARY KEY (`id`)
   ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
   DELIMITER $$
   CREATE PROCEDURE `generate_random_data`()
   BEGIN
     DECLARE i INT DEFAULT 1;
     DECLARE j INT DEFAULT 1;
     DECLARE str longtext;
     WHILE i <= 10000 DO
       SET j = 1;
       SET str = '';
       WHILE j <= 400 DO
         SET str = CONCAT(str, MD5(RAND()));
         SET j = j + 1;
       END WHILE;
       INSERT INTO `random_data` (`data`) VALUES (str);
       SET i = i + 1;
     END WHILE;
   END$$
   DELIMITER ;
   ```
   分别设置rds_column_compression=0和rds_column_compression=2，其他参数默认，导入如上表结构并调用存储过程插入数据，利用zlib/zstd算法压缩，计算压缩前后数据文件大小的比率为1.8。
   
2. 通过sysbench导入64张表，每张表1000万行数据，其中c和pad字段类型更改为varchar，修改后的表结构如下所示：
   ```
   CREATE TABLE `sbtest1` (
     `id` int NOT NULL AUTO_INCREMENT,
     `k` int NOT NULL DEFAULT '0',
     `c` varchar(120) COLLATE utf8mb4_0900_bin NOT NULL DEFAULT '',
     `pad` varchar(60) COLLATE utf8mb4_0900_bin NOT NULL DEFAULT '',
     PRIMARY KEY (`id`),
     KEY `k_1` (`k`)
   ) ENGINE=InnoDB AUTO_INCREMENT=10000001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
   ```
   - 分别设置rds_column_compression=0和rds_column_compression=2，其他参数默认，导入表结构和数据，计算收益后实际只对c列进行zlib/zstd压缩，计算压缩前后数据文件大小的比率为1.2。
   
   - 性能测试方面，理论上压缩级别越高对性能的影响越大，压缩后性能损耗在10%左右。
    
 
