postgresql dead_tuple和live_tuple

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
简介: --PG并没有像Oracle那样的undo来存放旧版本;而是将旧版本直接存放于relation文件中。


--PG并没有像Oracle那样的undo来存放旧版本;而是将旧版本直接存放于relation文件中。那么带来的问题就是dead tuple过多,导致relation文件不断增大而带来空间膨胀问题。
--为了解决这个问题,PG中引入了vacuum后台进程,专门来清理这些dead tuple,并回缩空间


--创建测试数据
postgres=# create table t (id int ,name varchar(50));
CREATE TABLE
postgres=# insert into t select id,'rudy'|| id from generate_series(1,100) id;


--查询统计信息,可知n_live_tup为100,n_dead_tup为0
postgres=# select relname,n_live_tup,n_dead_tup from pg_stat_user_tables where relname='t';
-[ RECORD 1 ]-----+-------
relid             | 88968
schemaname        | public
relname           | t
seq_scan          | 0
seq_tup_read      | 0
idx_scan          | 
idx_tup_fetch     | 
n_tup_ins         | 100
n_tup_upd         | 0
n_tup_del         | 0
n_tup_hot_upd     | 0
n_live_tup        | 100
n_dead_tup        | 0
last_vacuum       | 
last_autovacuum   | 
last_analyze      | 
last_autoanalyze  | 
vacuum_count      | 0
autovacuum_count  | 0
analyze_count     | 0
autoanalyze_count | 0


--由以下可知,没更新一次,n_dead_tup加1
postgres=# update t set name='dead tuple' where id=1;
UPDATE 1
postgres=# select relname,n_live_tup,n_dead_tup from pg_stat_user_tables where relname='t';
 relname | n_live_tup | n_dead_tup 
---------+------------+------------
 t       |        100 |          1


postgres=# update t set name='dead tuple 2' where id=1;          
UPDATE 1
postgres=# select relname,n_live_tup,n_dead_tup from pg_stat_user_tables where relname='t';
 relname | n_live_tup | n_dead_tup 
---------+------------+------------
 t       |        100 |          2
 
 
--每删除一次数据 n_live_tup 和 n_dead_tup 均加1 
postgres=# delete from  t where id<10;
DELETE 9
postgres=# select relname,n_live_tup,n_dead_tup from pg_stat_user_tables where relname='t';
 relname | n_live_tup | n_dead_tup 
---------+------------+------------
 t       |         91 |         11
 
--此时的空间回收可以使用 vacuum 进行
postgres=# vacuum (verbose ,analyze ) t;
INFO:  vacuuming "public.t"
INFO:  scanned index "t_id_idx" to remove 9 row versions
DETAIL:  CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO:  "t": removed 9 row versions in 1 pages
DETAIL:  CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO:  index "t_id_idx" now contains 101 row versions in 2 pages
DETAIL:  9 index row versions were removed.
0 index pages have been deleted, 0 are currently reusable.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO:  "t": found 11 removable, 101 nonremovable row versions in 1 out of 1 pages
DETAIL:  0 dead row versions cannot be removed yet.
There were 2 unused item pointers.
0 pages are entirely empty.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO:  analyzing "public.t"
INFO:  "t": scanned 1 of 1 pages, containing 101 live rows and 0 dead rows; 101 rows in sample, 101 estimated total rows
VACUUM
postgres=# select relname,n_live_tup,n_dead_tup,last_vacuum,last_analyze from pg_stat_user_tables where relname='t';
 relname | n_live_tup | n_dead_tup |          last_vacuum          |         last_analyze          
---------+------------+------------+-------------------------------+-------------------------------
 t       |        101 |          0 | 2015-11-23 22:32:17.970209-08 | 2015-11-23 22:32:17.972155-08
 
 
 --不带表名的vacuum会回收统计系统中的所有的表,此时系统会有大量的io操作,故不要在数据库繁忙时操作
 vacuum (verbose ,analyze ) ;
 
-- 注意 vacuum full会锁表和索引,而且是“AccessExclusiveLock”级别的。其实vacuum full会重建整个表,这个的功能实现在cluster.c文件中,因为其行业相当于是一个cluster重建的一个变种
 
 
 
 
 
 vacuum的功能


1.回收空间


    这个通常是大家最容易想起来的功能。回收空间,将dead tuple清理掉。但是已经分配的空间,一般不会释放掉。除非做vacuum full,但是需要exclusive lock。
一般不太建议,因为如果表最终还是会涨到这个高水位上,经常做vacuum full意义不是非常大。一般合理设置vacuum参数,进行常规vacuum也就够了。


2.冻结tuple的xid


  PG会在每条记录(tuple)的header中,存放xmin,xmax信息(增删改事务ID)。transactionID的最大值为2的32次,即无符整形来表示。当transactionID超过此最大值后,会循环使用。


这会带来一个问题:就是最新事务的transactionID会小于老事务的transactionID。如果这种情况发生后,PG就没有办法按transactionID来区分事务的先后,也没有办法实现MVCC了。
因此PG用vacuum后台进程,按一定的周期和算法触发vacuum动作,将过老的tuple的header中的事务ID进行冻结。冻结事务ID,即将事务ID设置为“2”(“0”表示无效事务ID;“1”表示bootstrap,
即初始化;“3”表示最小的事务ID)。PG认为被冻结的事务ID比任何事务都要老。这样就不会出现上面的这种情况了。


3.更新统计信息


    vacuum analyze时,会更新统计信息,让PG的planner能够算出更准确的执行计划。autovacuum_analyze_threshold和autovacuum_analyze_scale_factor参数可以控制analyze的触发的频率。


4.更新visibility map


在PG中,有一个visibility map用来标记那些page中是没有dead tuple的。这有两个好处,一是当vacuum进行scan时,直接可以跳过这些page。
二是进行index-only scan时,可以先检查下visibility map。这样减少fetch tuple时的可见性判断,从而减少IO操作,提高性能。
另外visibility map相对整个relation,还是小很多,可以cache到内存中。






自动vacuum配置
自动vacuum的执行直接由autovacuum参数值决定,默认值是on。
log_autovacuum_min_duration:默认值为-1,关闭vacuum的日志记录,配置为0表示记录autovacuum的所有log。参数设置为正整数表示对于在此时间内完成的vacuum操作不进行log记录,如果没能完成,则记录超出时间内的log。该参数对于了解对象执行vacuum操作的时间非常有用。
autovacuum_max_workers:最大的autovacuum进程的数量,默认值为3。参数大小的配置主要依据系统当前负载和资源。对于系统负载较重的情况,建议开启少量的进程为好,反之,空闲时间可以采用较大值的方式。
autovacuum_naptime:检查数据库的时间间隔。默认为1分钟。
autovacuum_vacuum_threshold:参数表示执行autovacuum操作之前,对单个表中记录执行DML操作的最少行数。达到该行数时自动激活autovacuum操作。该参数针对数据库中的所有表,还可以通过对单个表配置不同的值来改变相应表的autovacuum操作。默认值是50。
autovacuum_analyze_threshold:激活自动analyze操作的最小行数。默认值50。机制与上面相同。
autovacuum_vacuum_scale_factor:该参数采用百分比的方式设定阀值。默认值为20%,当DML涉及的数据量大于某个表的20%时,自动触发autovacuum操作。同样可以通过对单个表进行阀值设定。
autovacuum_analyze_scale_factor:机制与上面相同,到达阀值是自动激活analyze操作。同样可以通过对单个表进行阀值设定。
autovacuum_freeze_max_age:为防止事务ID的重置,在启用vacuum操作之前,表的pg_class .relfrozenxid字段的最大值,默认为200万。
autovacuum_vacuum_cost_delay:autovacuum进程的时间延迟限制,默认值是20ms。对于单个表同样适用。
autovacuum_vacuum_cost_limit:autovacuum进程的开销延迟限制,默认值是-1,表示不进行开销限制,系统将会直接依据vacuum_cost_limit参数管理vacuum的开销。对于单个表同样适用。
目录
相关文章
|
3月前
|
SQL 消息中间件 存储
Flink报错问题之Flink报错:Table sink 'a' doesn't support consuming update and delete changes which is produced by node如何解决
Flink报错通常是指在使用Apache Flink进行实时数据处理时遇到的错误和异常情况;本合集致力于收集Flink运行中的报错信息和解决策略,以便开发者及时排查和修复问题,优化Flink作业的稳定性。
|
3月前
|
消息中间件 Kubernetes Java
实时计算 Flink版操作报错合集之写入 Kafka 报错 "Failed to send data to Kafka: Failed to allocate memory within the configured max blocking time 60000 ms",该怎么解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
220 0
|
3月前
|
消息中间件 Oracle 关系型数据库
实时计算 Flink版操作报错合集之报错io.debezium.DebeziumException: The db history topic or its content is fully or partially missing. Please check database history topic configuration and re-execute the snapshot. 是什么原因
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
147 0
|
存储 关系型数据库 PostgreSQL
PostgreSQL TID及tuple slot
PostgreSQL TID及tuple slot
171 0
PostgreSQL TID及tuple slot
|
10月前
|
SQL 流计算
Flink CDC这俩statement mode和batch mode啥区别
Flink CDC这俩statement mode和batch mode啥区别
83 1
list和tuple的区别
了解list和tuple的相同点和不同点
93 0
|
关系型数据库 PostgreSQL 索引
PostgreSQL通过索引获取heap tuple解析
PostgreSQL通过索引获取heap tuple解析
124 0
|
Java 索引
logstash问题记录:Attempted to resurrect connection to dead ES instance, but got an error
logstash问题记录:Attempted to resurrect connection to dead ES instance, but got an error
761 0
logstash问题记录:Attempted to resurrect connection to dead ES instance, but got an error
|
NoSQL Java MongoDB
MongoDB Limit与Skip方法
MongoDB Limit与Skip方法
73 0
|
域名解析 存储 供应链
MongoDB 4.2 内核解析 - Change Stream
本文将为大家讲解 MongoDB 4.2 的 Change Stream 功能,接下来将分别从其功能、使用以及内部实现进行详细介绍。
948 0
MongoDB 4.2 内核解析 - Change Stream