postgresql垃圾回收

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介:

之前学习pg vacuum的时候,只是简单的知道pg的mvcc会产生多版本,多版本会有垃圾,垃圾需要处理,vacuum就可以清除这些垃圾。可是一直没有仔细想过到底哪些垃圾是可以清除的,哪些是不能处理的。下面我们仔细研究下这个问题,vacuum可以降低表的年龄可以释放空闲空间,也可以垃圾回收,我们先只单独讨论垃圾回收这一过程。
首先什么样的数据是垃圾数据:
postgres=# create table a(id int);
CREATE TABLE
postgres=# insert into a values(1);
INSERT 0 1
postgres=# select *,ctid from a;

 id ctid
  1 (0,1)

(1 row)
创建好测试表插入第一条数据,这个数据是在0号页面第一行上。
下面更新下这条数据
postgres=# update a set id=10;
UPDATE 1
postgres=# select *,ctid from a;

 id ctid
 10 (0,2)

(1 row)
发现,数据记录在0号页面的第二行上了,原来第一行的记录被更新了将更新的数据放到了第二行上,所以之前的第一条记录就已经没用了,是一条垃圾记录了。但是这时候这条记录并没有被回收,只是隐藏了,下面看下回收的过程:
postgres=# vacuum verbose a;
INFO: vacuuming "public.a"
INFO: "a": found 1 removable, 1 nonremovable row versions in 1 out of 1 pages
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
可以看到有一条记录被移除了。那是不是有垃圾无法被vacuum回收的情况呢?是有,下面分两种不同版本的来分析下,pg9.4和pg9.6因为pg9.6对快照过旧做了一些改动。先说9.4吧。
9.4:
先模拟不能回收的情况:
会话A:
postgres=# begin;
BEGIN
postgres=# select txid_current();

txid_current

 98978845

(1 row)

postgres=# select pg_backend_pid();

pg_backend_pid

      31156

(1 row)

postgres=#

会话A开始一个事务,申请一个事务号,产看下会话A的pid是多少,不要提交。
会话B:
postgres=# select backend_xid,backend_xmin from pg_stat_activity where pid=31156;

 backend_xid backend_xmin
    98978850

(1 row)

postgres=# select txid_current();

 txid_current

     98978851
(1 row)

postgres=# update a set id =1000;
UPDATE 1
postgres=# select *,ctid from a;

  id ctid
 1000 (0,2)

(1 row)

postgres=# vacuum verbose a;
INFO: vacuuming "public.a"
INFO: "a": found 0 removable, 2 nonremovable row versions in 1 out of 1 pages
DETAIL: 1 dead row versions cannot be removed yet.
There were 1 unused item pointers.
0 pages are entirely empty.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
VACUUM
postgres=#
会话B先看下会话A的backend_pid和backend_xmin是否有值,然后看下当前最新事务号,更新下a表后进行vacuum,发现有一条垃圾记录无法回收。这个是为什么呢?先说下backend_pid和backend_xmin,backend_pid是当开启一个事务时,申请到事务号是就会有值(是指begin后又插入或者更新操作等),backend_xmin在read commit级别下是每条语句都会有快照,但是语句执行完马上就释放,长时间执行语句是可以看到该值:
会话A:
postgres=# select pg_backend_pid();

 pg_backend_pid

          11194
(1 row)

postgres=# select pg_sleep(20);
会话B:
postgres=# select backend_xid,backend_xmin from pg_stat_activity where pid=11194;

 backend_xid backend_xmin
              98979813

(1 row)
当repeatable read和串行化的隔离级别中,开启一个事务,任意一条语句都会申请到backend_xmin。
呢垃圾回收和这两个值有什么关系呢?9.6以前是只能回收tuple的xmax小于min(backend_xid,backend_xmin)的 ,所以当你有一个长事务时长时间不提交,它之后更新删除的xmax都会大于呢个长事务的backend_xid所以这些垃圾数据就都无法回收,造成表膨胀。当你备份时事务的隔离级别会是repeatable read,时间过长和上面一样会产生表膨胀。
下面说下9.6的变化吧,9.6新增了old_snapshot_theshold,这个是表示当语句持有backend_xmin的时间超过old_snapshot_theshold设定的时间并且读取到的数据块的lsn大于backend_xmin快照存储的lsn时就会发生snapshot too old的情况。下面模拟下这种情况。
会话A:
postgres=# begin transaction isolation level repeatable read;
BEGIN
postgres=# select 1;

 ?column?

        1
(1 row)

postgres=# select *,ctid from a where ctid::text like '%(1427,%' limit 10;

   id ctid
 4735747 (1427,1)
 1209750 (1427,2)
 3293719 (1427,3)
  555445 (1427,4)
 3724432 (1427,5)
 3114037 (1427,6)
  182685 (1427,7)
  213731 (1427,8)
 4052679 (1427,9)
 1677525 (1427,10)

(10 rows)

postgres=# select *,ctid from a where ctid::text like '%(1427,%' limit 10;
ERROR: snapshot too old
STATEMENT: select *,ctid from a where ctid::text like '%(1427,%' limit 10;
ERROR: snapshot too old
会话B:
postgres=# select backend_xid,backend_xmin from pg_stat_activity where pid=30504;

 backend_xid backend_xmin
              109690248

(1 row)

postgres=# update a set id =1090 where id =4735747;
UPDATE 1
postgres=#
会话A先开启repeatable read隔离级别得到一个backend_xmin,扫描1427号页面,B会话更新1427号页面任意一行记录,等到一个old_snapshot_theshold的时间,再去A会话里查找1427号页面就会发现snapshot too old这个错。
那这个对垃圾回收有哪些影响呢?之前是看tuple的xmax是否大于min(backend_xid,backend_xmin),大于就无法回收,现在是tuple的xmax是否大于
max(old_snapshot_theshold中记录的最老记录,backend_xid,backend_xmin),
old_snapshot_theshold是每分钟记录最大的backend_xid没有取当前最小事务号.
下面模拟9.6新增可以回收的情况:
会话A:
postgres=# begin;
BEGIN
postgres=# select pg_sleep(200);
会话B:
postgres=# insert into a values(1);
INSERT 0 1
postgres=# insert into a values(1);
INSERT 0 1
postgres=# delete from a where id=1;
DELETE 2
postgres=# select * from a limit 1;

   id

 3137507
(1 row)

postgres=# vacuum verbose a;
INFO: vacuuming "public.a"
INFO: "a": found 0 removable, 452 nonremovable row versions in 2 out of 1428 pages
DETAIL: 2 dead row versions cannot be removed yet.
There were 2 unused item pointers.
Skipped 0 pages due to buffer pins.
0 pages are entirely empty.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
VACUUM
postgres=# vacuum verbose a;
INFO: vacuuming "public.a"
INFO: "a": removed 2 row versions in 2 pages
INFO: "a": found 2 removable, 450 nonremovable row versions in 2 out of 1428 pages
DETAIL: 0 dead row versions cannot be removed yet.
There were 2 unused item pointers.
Skipped 0 pages due to buffer pins.
0 pages are entirely empty.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
VACUUM
postgres=#
完整过程是先,开启A会话,A会话得到pg_backend_xmin,B会话插入记录并删除,进行第一次vacuum发现呢条记录无法回收,等A运行一段时间old_snapshot_theshold获取到的backend_xid大于backend_xmin就可以回收这些垃圾记录了, 需要先查一下这个表才能回收(不知道什么原因)。

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
存储 算法 关系型数据库
PostgreSQL 垃圾回收参数优化之 - maintenance_work_mem , autovacuum_work_mem
PostgreSQL 垃圾回收参数优化之 - maintenance_work_mem , autovacuum_work_mem
3413 1
|
存储 弹性计算 算法
PostgreSQL 垃圾回收参数优化之 - maintenance_work_mem , autovacuum_work_mem
标签 PostgreSQL , 垃圾回收 , 索引扫描 , 内存 背景 夜谈PostgreSQL 垃圾回收参数优化之 - maintenance_work_mem , autovacuum_work_mem。 http://www.postgres.cn/v2/news/viewone/1/398 https://rhaas.blogspot.com/2019/01/how-much
2508 0
|
Java 关系型数据库 PostgreSQL
PostgreSQL物理"备库"的哪些操作或配置,可能影响"主库"的性能、垃圾回收、IO波动
标签 PostgreSQL , 物理复制 , 垃圾回收 , vacuum_defer_cleanup_age , hot_standby_feedback , max_standby_archive_delay , max_standby_streaming_delay 背景 PostgreSQL 物理备库的哪些配置,或者哪些操作,可能影响到主库呢? 首先,简单介绍一下PostgreSQL的物理备库,物理备库就是基于PostgreSQL WAL流式复制,实时恢复的备库。
4167 0
|
关系型数据库 Java 数据库
PostgreSQL 老湿机图解平安科技遇到的垃圾回收"坑"
背景 从海安那里反馈的一个问题,是平安科技在使用PostgreSQL的过程中,遇到的一个有些"不可思议"的问题。 一张经常被更新的表,通过主键查询这张表的记录时,发现需要扫描异常多的数据块。 其实原因有2。 .1. 长事务有关,我在很多文章都提到过,PG在垃圾回收时,只判断垃圾版
6961 0
|
16天前
|
关系型数据库 MySQL 数据库
mysql卸载、下载、安装(window版本)
mysql卸载、下载、安装(window版本)
|
1月前
|
关系型数据库 MySQL 数据库
rds安装数据库客户端工具
安装阿里云RDS的数据库客户端涉及在本地安装对应类型(如MySQL、PostgreSQL)的客户端工具。对于MySQL,可选择MySQL Command-Line Client或图形化工具如Navicat,安装后输入RDS实例的连接参数进行连接。对于PostgreSQL,可以使用`psql`命令行工具或图形化客户端如PgAdmin。首先从阿里云控制台获取连接信息,然后按照官方文档安装客户端,最后配置客户端连接以确保遵循安全指引。
86 1
|
5天前
|
关系型数据库 MySQL 数据库
《MySQL 简易速速上手小册》第1章:MySQL 基础和安装(2024 最新版)
《MySQL 简易速速上手小册》第1章:MySQL 基础和安装(2024 最新版)
28 4
|
29天前
|
Ubuntu 关系型数据库 MySQL
Ubuntu 中apt 安装MySQL数据库
Ubuntu 中apt 安装MySQL数据库
69 0
|
1天前
|
关系型数据库 MySQL Windows
windows安装MySQL5.7教程
windows安装MySQL5.7教程
6 0