1 VACUUM 说明
1.1 背景说明
在之前的博客我们了解到openGauss中有两种数据引擎:Astore和Ustore。
Astore采用追加更新模式,即同一个page页中既存在前映像也存在当前值,只是前映像会被标记为删除。
Astore是opengauss的默认存储引擎,Astore存储引擎由于同一个块中包含太多的前映像,如果频繁的更新操作会导致大量的磁盘“垃圾”,因为在执行查询操作的时候即使标记了删除也会扫描,所以大大的降低性能。
openGauss Astore(Append Update)和 Ustore(In-place Update)数据引擎 说明
https://www.cndba.cn/dave/article/116545
为了保证openGauss的性能,需要定期执行VACUUM或者VACUUM full进行清理。VACUUM可以回收表或B-Tree索引中已经删除的行所占据的存储空间,特别是在经常更新的表上。
1.2 vacuum 注意事项
- 如果没有参数,VACUUM处理当前数据库里用户拥有相应权限的每个表。如果参数指定了一个表,VACUUM只处理指定的那个表。
- 要对一个表进行VACUUM操作,通常用户必须是表的所有者或者被授予了指定表VACUUM权限的用户,默认系统管理员有该权限。数据库的所有者允许对数据库中除了共享目录以外的所有表进行VACUUM操作(该限制意味着只有系统管理员才能真正对一个数据库进行VACUUM操作)。VACUUM命令会跳过那些用户没有权限的表进行垃圾回收操作。
- VACUUM不能在事务块内执行。
- 建议生产数据库经常清理(至少每晚一次),以保证不断地删除失效的行。尤其是在增删了大量记录之后,对受影响的表执行VACUUM ANALYZE命令是一个很好的习惯。这样将更新系统目录为最近的更改,并且允许查询优化器在规划用户查询时有更好地选择。
- 不建议日常使用FULL选项,但是可以在特殊情况下使用。例如在用户删除了一个表的大部分行之后,希望从物理上缩小该表以减少磁盘空间占用。VACUUM FULL通常要比单纯的VACUUM收缩更多的表尺寸。FULL选项并不清理索引,所以推荐周期性的运行REINDEX命令。实际上,首先删除所有索引,再运行VACUUM FULL命令,最后重建索引通常是更快的选择。如果执行此命令后所占用物理空间无变化(未减少),请确认是否有其他活跃事务(删除数据事务开始之前开始的事务,并在VACUUM FULL执行前未结束)存在,如果有等其他活跃事务退出进行重试。
- VACUUM会导致I/O流量的大幅增加,这可能会影响其他活动会话的性能。因此,有时候会建议使用基于开销的VACUUM延迟特性。
- 如果指定了VERBOSE选项,VACUUM将打印处理过程中的信息,以表明当前正在处理的表。各种有关当前表的统计信息也会打印出来。但是对于列存表执行VACUUM操作,指定了VERBOSE选项,无信息输出。
- 当含有带括号的选项列表时,选项可以以任何顺序写入。如果没有括号,则选项必须按语法显示的顺序给出。
- VACUUM和VACUUM FULL时,会根据参数vacuum_defer_cleanup_age延迟清理行存表记录,即不会立即清理刚刚删除的元组。
- VACUUM ANALYZE先执行一个VACUUM操作,然后给每个选定的表执行一个ANALYZE。对于日常维护脚本而言,这是一个很方便的组合。
- 简单的VACUUM(不带FULL选项)只是简单地回收空间并且令其可以再次使用。这种形式的命令可以和对表的普通读写并发操作,因为没有请求排他锁。VACUUM FULL执行更广泛的处理,包括跨块移动行,以便把表压缩到最少的磁盘块数目里。这种形式要慢许多并且在处理的时候需要在表上施加一个排他锁。
- VACUUM列存表内部执行的操作包括三个:迁移delta表中的数据到主表、VACUUM主表的delta表、VACUUM主表的desc表。该操作不会回收delta表的存储空间,如果要回收delta表的冗余存储空间,需要对该列存表执行VACUUM DELTAMERGE。
- 同时执行多个VACUUM FULL可能出现死锁。
- 如果没有打开xc_maintenance_mode参数,那么VACUUM FULL操作将跳过所有系统表。
- 执行DELETE后立即执行VACUUM FULL命令,可能不会回收空间,这取决于是否有DELETE事务之前开启的事务仍处于活跃状态。此时需要等待所有事务结束,或者重启数据库,再重新执行VACUUM FULL命令进行清理。
2 自动清理
在openGauss中,系统自动清理线程(autovacuum)自动执行VACUUM和ANALYZE命令,回收被标识为删除状态的记录空间,并更新表的统计数据。
自动清理的相关配置参数如下:
openGauss=# select name,setting,context,source from pg_settings where name like '%autovacuum%';
name | setting | context | source
---------------------------------+------------+------------+--------------------
autovacuum | on | sighup | configuration file
autovacuum_analyze_scale_factor | 0.1 | sighup | default
autovacuum_analyze_threshold | 50 | sighup | default
autovacuum_freeze_max_age | 4000000000 | postmaster | default
autovacuum_io_limits | -1 | sighup | default
autovacuum_max_workers | 3 | postmaster | default
autovacuum_mode | mix | sighup | default
autovacuum_naptime | 600 | sighup | default
autovacuum_vacuum_cost_delay | 20 | sighup | default
autovacuum_vacuum_cost_limit | -1 | sighup | default
autovacuum_vacuum_scale_factor | 0.2 | sighup | default
autovacuum_vacuum_threshold | 50 | sighup | default
log_autovacuum_min_duration | -1 | sighup | default
(13 rows)
关于这些参数的说明,直接参考官方手册:
3 操作示例
3.1 语法说明
回收空间并更新统计信息,对关键字顺序无要求:
VACUUM [ ( { FULL | FREEZE | VERBOSE | {ANALYZE | ANALYSE }} [,...] ) ]
[ table_name [ (column_name [, ...] ) ] [ PARTITION ( partition_name ) | SUBPARTITION ( subpartition_name ) ] ] ;
仅回收空间,不更新统计信息:
VACUUM [ FULL [COMPACT] ] [ FREEZE ] [ VERBOSE ] [ table_name
[ PARTITION ( partition_name ) | SUBPARTITION ( subpartition_name ) ] ] ;
回收空间并更新统计信息,且对关键字顺序有要求:
VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] { ANALYZE | ANALYSE } [ VERBOSE ]
[ table_name [ (column_name [, ...] ) ] ] [ PARTITION ( partition_name ) ];
这里要注意 FULL 选项:
- 选择“FULL”清理,这样可以恢复更多的空间,但是需要耗时更多,并且在表上施加了排他锁,会影响业务的使用。
- 使用FULL参数会导致统计信息丢失,如果需要收集统计信息,需要在VACUUM FULL语句中加上analyze关键字。
3.2 操作示例
[dave@www.cndba.cn ~]$ gsql -h localhost -p 15500 -d postgres -U omm -W omm@123456 -r
gsql ((openGauss 5.0.0 build a07d57c3) compiled at 2023-03-29 03:07:56 commit 0 last mr )
SSL connection (cipher: ECDHE-RSA-AES128-GCM-SHA256, bits: 128)
Type "help" for help.
openGauss=# vacuum analyze cndba;
VACUUM
openGauss=# vacuum verbose cndba;
INFO: vacuuming "public.cndba"(dn_6001_6002_6003 pid=3297)
INFO: "cndba": found 0 removable, 2 nonremovable row versions in 1 out of 1 pages(dn_6001_6002_6003 pid=3297)
DETAIL: 0 dead row versions cannot be removed yet. There were 0 unused item pointers. 0 pages are entirely empty. CPU 0.00s/0.00u sec elapsed 0.00 sec.
VACUUM
openGauss=# vacuum (verbose,analyze) cndba;
INFO: vacuuming "public.cndba"(dn_6001_6002_6003 pid=3297)
INFO: "cndba": found 0 removable, 2 nonremovable row versions in 1 out of 1 pages(dn_6001_6002_6003 pid=3297)
DETAIL: 0 dead row versions cannot be removed yet. There were 0 unused item pointers. 0 pages are entirely empty. CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO: analyzing "public.cndba"(dn_6001_6002_6003 pid=3297)
INFO: ANALYZE INFO : "cndba": scanned 1 of 1 pages, containing 2 live rows and 0 dead rows; 2 rows in sample, 2 estimated total rows(dn_6001_6002_6003 pid=3297)
VACUUM
openGauss=# vacuum (full,analyze) cndba;
VACUUM
openGauss=# vacuum (verbose,full,analyze) cndba;
INFO: vacuuming "public.cndba"(dn_6001_6002_6003 pid=3297)
INFO: "cndba": found 0 removable, 2 nonremovable row versions in 1 pages(dn_6001_6002_6003 pid=3297)
DETAIL: 0 dead row versions cannot be removed yet.
CPU 0.00s/0.00u sec elapsed 0.01 sec.
INFO: analyzing "public.cndba"(dn_6001_6002_6003 pid=3297)
INFO: ANALYZE INFO : "cndba": scanned 1 of 1 pages, containing 2 live rows and 0 dead rows; 2 rows in sample, 2 estimated total rows(dn_6001_6002_6003 pid=3297)
VACUUM
openGauss=# vacuum (verbose,full,analyze) customer_par partition(p1);
INFO: vacuuming "public.customer_par"(dn_6001_6002_6003 pid=3297)
INFO: "customer_par": found 0 removable, 0 nonremovable row versions in 0 pages(dn_6001_6002_6003 pid=3297)
DETAIL: 0 dead row versions cannot be removed yet.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
VACUUM
openGauss=#
查看表占用空间大小:
openGauss=# SELECT nspname || '.' || relname AS "relation",
pg_size_pretty(pg_total_relation_size(C.oid)) AS "total_size"
FROM pg_class C
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
AND C.relkind <> 'i'
AND nspname !~ '^pg_toast' and relname='cndba';
relation | total_size
--------------+------------
public.cndba | 8192 bytes
(1 row)
4 VACUUM FULL表大小无变化
当对表使用VACUUM FULL也可能出现清理完成后表大小和清理前一样大的情况。
假定该表的名称为table_name,对于该现象可能有以下两种原因:
- table_name表本身没有delete过数据,使用VACUUM FULL table_name后无需清理delete的数据。
- 在执行VACUUM FULL table_name时有并发的事务存在,可能会导致VACUUM FULL跳过清理最近删除的数据,导致清理不完全。
对于第二种可能原因,有如下两种处理方法:
- 如果在VACUUM FULL时有并发的事务存在,此时需要等待所有事务结束,再次执行VACUUM FULL命令对该表进行清理。
- 再使用以下命令查看活跃事务列表: select txid_current_snapshot(); 如果发现活跃事务列表中有XID比当前的事务XID小时,停止数据库再启动数据库,再次使用VACUUM FULL。
版权声明:本文为博主原创文章,未经博主允许不得转载。