
# VACUUM
#### 功能描述
VACUUM回收表或B-Tree索引中已经删除的行所占据的存储空间。在一般的数据库操作里，那些已经DELETE的行并没有从它们所属的表中物理删除；在完成VACUUM之前它们仍然存在。因此有必要周期地运行VACUUM，特别是在经常更新的表上。
#### VACUUM与VACUUM FULL的区别
VACUUM命令存在两种形式，VACUUM和VACUUM FULL，VACUUM命令做的是LAZY VACUUM。从字面意思就可以看出来，LAZY VACUUM是VACUUM FULL的简化版，具体区别见下表。
表1VACUUM与VACUUM FULL的区别 
| 比较维度 | VACUUM                                                                                   | VACUUM FULL                                                    |
|:---|:---|:---|
| 空间清理 | 如果删除记录位于表的末端，其所占用的空间将会被物理释放并归还操作系统。如果删除记录不是末端数据，会将表中或索引中dead tuple所占用的空间置为可用状态，从而复用这些空间。 | 不论被清理的数据处于何处，这些数据所占用的空间都将被物理释放并归还于操作系统。当再有数据插入后，系统会分配新的磁盘页面使用。 |
| 锁类型  | 4级锁，共享更新排他锁（ShareUpdateExclusiveLock），可以与其他操作并行。                                         | 8级锁，访问排他锁（AccessExclusiveLock），执行期间会同时锁表，基于该表的其他操作全部挂起。        |
| 物理空间 | 不会释放。                                                                                    | 会释放。                                                           |
| 事务ID | 不回收。                                                                                     | 回收                                                             |
| 执行开销 | 开销较小，可以定期执行。                                                                             | 开销巨大，建议确认数据库所占磁盘页面空间接近临界值再执行操作，且最好选择数据量操作较少的时段完成。              |
| 执行效果 | 执行后会有所提升。                                                                                | 执行完后，基于该表的操作效率大大提升。                                            |
   
#### 关于自动清理（AUTOVACUUM）
由于VACUUM操作可释放空间，对提升查询性能至关重要，DWS提供了自动清理的能力，用户可根据自身业务需要，在指定条件下，让系统触发自动清理功能，通过管理控制台配置，参见[管理运维计划](https://support.huaweicloud.com/mgtg-dws/dws_01_1162.html)。
 #### 在线VACUUM FULL
DWS的9.1.1.300及以上集群版本中支持在线VACUUM FULL（对应语法**VACUUM FULL** **ONLINE**），该功能可以在不长时间加排他锁的情况下，允许对表的并发读写，从而减少对业务的影响。因此，当数据库管理员在业务低峰期发现业务表脏页率较高时，可以执行在线VACUUM FULL操作，以回收表空间并优化数据库性能，同时确保业务的连续性和数据库的可用性。
![](https://support.huaweicloud.com/sqlreference-911-dws/public_sys-resources/note_3.0-zh-cn.png)
在线VACUUM FULL特性目前为**商用Beta特性**，如需使用，请联系技术支持。
在线VACUUM FULL功能约束限制如下：
- 目前支持 2.0表和行存表。不支持临时表、系统表、外表、复制表、物化视图、LSM、binlog、冷热表、大宽表及行列混存表。
- 不支持细粒度备份恢复，执行VACUUM FULL ONLINE后无法进行细粒度恢复。
- 在线VACUUM FULL操作执行失败可能会导致数据残留。需手动执行以下命令并删除残留的辅助SCHEMA（以data_redis_ovf_\<table_oid\>命名）。
  ```
  ALTER TABLE [ table_name ] SET (append_mode=off);
  ```
  
- 处于重分布状态和扩缩容状态的集群，不能执行在线VACUUM FULL。
- 2.0集群升级3.0集群期间不能执行在线VACUUM FULL。
- 在线VACUUM FULL不支持资源隔离与资源监控，不支持空间管控与告警拦截。

- 在线VACUUM FULL操作针对大表（例如含有索引和分区的2.0表）性能与VACUUM FULL持平。但对于小表性能劣化明显，主要限制为进程启动和状态检查，耗时数秒。

- 在线VACUUM FULL操作完成的最后阶段会阻塞写操作，在小时级的VACUUM FULL操作中，阻塞时间在分钟级。在最后瞬间会对读操作产生毫秒级的短暂阻塞。
- 建议业务低峰期执行，因为执行在线VACUUM FULL会降低DDL/DML操作的性能，且最后阻塞写操作的时长与业务数据量相关。
 
#### 注意事项
- 如果没有参数，VACUUM处理当前数据库里用户拥有相应权限的每个表。如果参数指定了一个表，VACUUM只处理指定的那个表。
- 要对一个表进行VACUUM操作，通常用户必须是表的所有者，被授予了指定表VACUUM权限的用户或者被授予了gs_role_vacuum_any角色的用户，系统管理员默认拥有此权限。数据库的所有者允许对数据库中除了共享目录以外的所有表进行VACUUM操作（该限制意味着只有系统管理员才能真正对一个数据库进行VACUUM操作）。VACUUM命令会跳过那些用户没有权限的表进行垃圾回收操作。
- VACUUM不能在事务块内执行。
- 建议生产数据库经常清理（至少每晚一次），以保证不断地删除失效的行。VACUUM ANALYZE先执行一个VACUUM操作，然后给每个选定的表执行一个ANALYZE。尤其是在增删了大量记录之后，对受影响的表执行VACUUM ANALYZE命令是一个很好的习惯。这样将更新系统目录为最近的更改，并且允许查询优化器在规划用户查询时有更好的选择。
- VACUUM会导致I/O流量的大幅增加，这可能会影响其他活动会话的性能。因此，有时候会建议使用基于开销的VACUUM延迟特性。
- 如果指定了VERBOSE选项，VACUUM将打印处理过程中的信息，以表明当前正在处理的表。各种有关当前表的统计信息也会打印出来。
- 语法格式中含有带括号的选项列表时，选项可以以任何顺序写入。如果没有括号，则选项必须按语法显示的顺序给出。
- VACUUM列存表内部执行的操作包括四个：VACUUM主表、VACUUM主表的desc表、VACUUM主表的delta表、迁移delta表中的数据到主表。该操作不会回收delta表的存储空间，如果要回收delta表的冗余存储空间，需要对该列存表执行VACUUM DELTAMERGE。VACUUM主表操作默认开启，可以通过调节参数colvacuum_threshold_scale_factor（该参数需联系技术支持修改）来关闭该功能。
- VACUUM列存主表功能不支持临时表、冷热表和时序表。
- VACUUM列存主表功能对空间的回收是延后的，若需要立即回收空间，在执行VACUUM后，运行vac_fileclear_relation函数，将会对指定表施加排他锁，完成空间回收。
- 简单的VACUUM（不带FULL选项）只是简单地回收空间并且令其可以再次使用。这种形式的命令可以和对表的普通读写并发操作，因为没有请求排他锁。VACUUM FULL执行更广泛的处理，包括跨块移动行，以便把表压缩到最少的磁盘块数目里。这种形式要慢许多并且在处理的时候需要在表上施加一个排他锁。
- 不建议日常使用FULL选项，但是可以在特殊情况下使用。例如在用户删除了一个表的大部分行之后，希望从物理上缩小该表以减少磁盘空间占用。VACUUM FULL通常要比单纯的VACUUM收缩更多的表尺寸。如果执行此命令后所占用物理空间无变化（未减少），请确认是否有其他活跃事务（删除数据事务开始之前开始的事务，并在VACUUM FULL执行前未结束）存在，如果有等其他活跃事务退出进行重试。
- VACUUM和VACUUM FULL时，会根据参数vacuum_defer_cleanup_age延迟清理行存表记录，即不会立即清理刚删除的元组。
- VACUUM FULL系统表只能离线操作，在线VACUUM FULL系统表除了会锁表，还可能导致一些异常情况并产生报错。
- 对列存分区表执行VACUUM FULL，会同时锁表和锁分区。对分区表指定的分区VACUUM FULL时，只锁定指定的分区，其他分区仍然可以被访问，但对整个分区表的操作可能受到影响。
- VACUUM FULL操作分区表时与用户DML语句在如下特定场景有并发时可能发生分布式死锁，请谨慎操作：
  - VACUUM FULL子分区与insert/update/delete主表。
  
  - VACUUM FULL全表与select全表/select子分区。
   
- 在存算分离架构下，不支持全库VACUUM/全库VACUUM FULL/全库VACUUM ANALYZE/全库VACUUM DELTAMERGE操作。
- 在存算分离架构下，正在重分布的列存3.0的表执行VACUUM操作时，系统不会进行实际的数据清理动作，但会返回如下提示信息：
  执行VACUUM操作时，会跳过VACUUM操作。
  ```
  VACUUM tpcds.web_returns_p1;
  NOTICE:  skip vacuum relation "web_returns_p1" since it is in redistribution state
  ```
  执行VACUUM ANALYZE操作时，会跳过VACUUM操作，但是会收集统计信息。
  ```
  VACUUM ANALYZE tpcds.web_returns_p1;
  NOTICE:  skip vacuum relation "web_returns_p1" since it is in redistribution state
  ```
  
![](https://support.huaweicloud.com/sqlreference-911-dws/public_sys-resources/warning_3.0-zh-cn.png)
- 对表执行VACUUM FULL操作时会触发表重建和表上的索引重建（重建过程中会先把数据写到一个新的数据文件中，重建完成之后删除原始文件），当表比较大时，重建会消耗较多的磁盘空间。当磁盘空间不足时，要谨慎对待大表VACUUM FULL操作，防止触发集群只读。
- 定期对脏页率、小CU占比超过25%的表执行VACUUM FULL，普通表需在低峰期执行，系统表需离线执行。
- 更多开发设计规范参见[总体开发设计规范](https://support.huaweicloud.com/devg-dws/dws_04_0075.html)。
 
#### 语法格式
- 回收空间并更新统计信息，关键字顺序必须按语法显示的顺序给出。
  ```
  VACUUM [ ( { FULL | FREEZE | VERBOSE | {ANALYZE | ANALYSE }} [,...] ) ]
      [ table_name [ (column_name [, ...] ) ] ] [ PARTITION ( partition_name ) ];
  ```
  
- 仅回收空间，不更新统计信息。
  ```
  VACUUM [ FULL [COMPACT] ] [ FREEZE ] [ VERBOSE ] [ table_name ] [ PARTITION ( partition_name ) ];
  ```
  
- 回收空间并更新统计信息，且对关键字顺序有要求。
  ```
  VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] { ANALYZE | ANALYSE } [ VERBOSE ] 
      [ table_name [ (column_name [, ...] ) ] ] [ PARTITION ( partition_name ) ];
  ```
  
- 针对HDFS表和列存表，将delta table中的数据转移到主表存储。（partition_name参数仅8.2.1.200及以上集群版本支持）
  ```
  VACUUM DELTAMERGE [ table_name ][partition_name];
  ```
  
- 针对HDFS表，删除HDFS表在HDFS存储上的空值分区目录。
  ```
  VACUUM HDFSDIRECTORY [ table_name ];
  ```
  
 
- 在线VACUUM FULL，支持DDL/DML操作与VACUUM FULL操作同时执行，不阻塞DDL/DML操作（该语法仅9.1.1.300及以上集群版本的2.0表支持）。
  ```
  VACUUM FULL [ table_name ] ONLINE;
  ```
  
#### 参数说明
表2VACUUM参数说明 
| 参数                 | 描述                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | 取值范围            |
|:---|:---|:---|
| FULL               | 选择该参数，可以恢复更多的空间，但是会耗时更多，并且在表上施加了排他锁。 FULL选项还可以带有COMPACT参数，只针对HDFS表，指定该参数的VACUUM FULL操作性能要好于未指定该参数的VACUUM FULL操作。 须知： - COMPACT和PARTITION参数不能同时使用。  - 使用FULL参数会导致统计信息丢失，如果需要收集统计信息，请在VACUUM FULL语句中加上analyze关键字。                                                                                                                                                                                                                                                                                                         | -               |
| FREEZE             | 用于解决事务ID回绕(Transaction ID Wraparound)问题，指定FREEZE相当于执行VACUUM时将vacuum_freeze_min_age参数设为0。 须知： DWS使用64位xid，理论上不会存在绕回问题，所以不建议客户操作VACUUM FREEZE。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | -               |
| VERBOSE            | 为每个表打印一份详细的清理工作报告。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | -               |
| ANALYZE \| ANALYSE | 更新用于优化器的统计信息，以决定执行查询的最有效方法。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | -               |
| table_name         | 需要清理的表的名称（可以带有模式修饰）。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | 缺省时为当前数据库中的所有表。 |
| column_name        | 需要分析的具体的字段名称。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | 缺省时为所有字段。       |
| PARTITION          | 指定清理的表为分区表。HDFS表不支持PARTITION参数。 说明： PARTITION参数和COMPACT同时使用会报错：COMPACT can not be used with PARTITION.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | -               |
| partition_name     | 要清理的表的分区名称。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | 缺省时为所有分区。       |
| DELTAMERGE         | 只针对HDFS表和列存表，将HDFS表或列存表的delta表中的数据转移到主表上存储。对HDFS表而言，当delta表中数据量小于六万行，则不作迁移，只有在大于或等于六万行数据时，将delta表中所有数据迁移到HDFS上，并通过truncate清理delta表的存储空间。对列存表而言，此操作总是会将delta表中的数据全部转移到CU中。 说明： 为了检查列存delta表中的信息（HDFS表的delta表数据可以通过explain analyze查到），提供下述DFX函数，用于获取某个列存表的delta表中数据存储情况： - pgxc_get_delta_info(TEXT)，传入参数为列存表名，搜集并显示各个节点上的对应delta表信息，包括当前存活tuple数量、表大小、使用的最大block ID。  - get_delta_info(TEXT)，传入参数为列存表名，汇总pgxc_get_delta_info得到的结果，返回其delta表整体的当前存活tuple数量、表大小、使用的最大block ID。查询临时表delta信息时，需要显式指定临时表的schema，否则会报错找不到表。   | -               |
| HDFSDIRECTORY      | 只针对HDFS表，清理HDFS表（存储在HDFS表的目录下）的空值分区目录。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | -               |
| ONLINE             | 在线执行VACUUM FULL操作，不会全程阻塞DDL/DML操作。该参数仅9.1.1.300及以上集群版本支持。 - **ONLINE参数不能与除FULL外的其他任何关键字同时使用**。  - 在线执行VACUUM FULL功能的约束和限制请参考[在线VACUUM FULL]。                                                                                                                                                                                                                                                                                                                                                                           | -               |
   
#### 示例
清理当前数据库中的所有表。
```
VACUUM;
```
仅回收表tpcds.web_returns_p1分区P2的空间，不更新统计信息。
```
VACUUM FULL tpcds.web_returns_p1 PARTITION(P2);
```
回收表tpcds.web_returns_p1空间，并更新统计信息。
```
VACUUM FULL ANALYZE tpcds.web_returns_p1;
```
清理当前数据库中的所有表并收集查询优化器的统计信息。
```
VACUUM ANALYZE;
```
仅清理特定表reason。
```
VACUUM (VERBOSE, ANALYZE) tpcds.reason;
```
对列存表table_delta进行DELTAMERGE操作。
```
VACUUM DELTAMERGE tpcds.table_delta;
```
仅对列存表table_delta的分区p1进行DELTAMERGE操作。
```
VACUUM DELTAMERGE tpcds.table_delta partition(p1);
```
执行在线VACUUM FULL。
```
VACUUM FULL tpcds.web_returns_p1 ONLINE;
```
