Postgresql通过数据多版本实现mvcc,删除数据并不会真正删除数据,而是修改标识,更新是通过删除+插入的方式进行,所以在频繁更新的系统,数据膨胀是个头疼的问题,如果不进行处理,数据膨胀倍数可能达到十几倍。

为了处理膨胀问题,pg提供了vacuum工具,vacuum分为普通vacuum和vacuum full,普通vacuum会清理死元组,但是不会进行空间重组,磁盘上的空间不会释放,但是会释放死元组的空间,后续插入的元组会根据空闲空间管理fsm优先插入空闲空间。Vacuum full清理会释放磁盘空间,但是会获取八级锁,因为vacuum full的原理是新建一个表数据文件,然后从老表中拷贝数据到新文件中,这个过程会阻塞select。

因为影响业务,pg社区开发了pg_repack工具,老版本叫pg_reorg。Pg_repack以extension的方式存在,用户可以自己安装该插件。本文简单介绍一下pg_repack的使用。

Pg_repack的源码在github或者pgxn上都可以下载,这里编译安装、创建插件的过程就不再赘述。

在安装完后,就可以在操作系统命令行使用pg_repack命令了,下面列举了pg_repack的一些命令用法:

pg_repack --no-order --table test_1 test
pg_repack --wait-timeout 3600 --jobs 10 --no-order -d test
pg_repack --wait-timeout 3600 --jobs 10 --no-order --schema=test -d test
pg_repack --wait-timeout 3600 --jobs 10 --only-indexes --table test.test_1 --no-order -d test
pg_repack --wait-timeout 3600 --jobs 10 --index test.idx1 --no-order -d test

经过测试,在执行pg_repack的同时对表进行并发查询,性能下降大概只有10%到20%,读取操作可以正常进行。并且表的oid没有发生变化,repack执行完成后,通过pg_relation_filepath()函数查询发现表的数据文件发生了改变,同时会删除原来的数据文件,其实执行vacuum full数据文件也会发生改变。

test=# select pg_relation_filepath(16475);pg_relation_filepath
----------------------base/16387/16580
(1 row)test=# select pg_relation_filepath(16475);pg_relation_filepath
----------------------base/16387/16601
(1 row)

下面聊聊repack的原理吧,原理其实和vacuum full是类似的,都是新建一个文件,然后将老文件数据拷贝过来,然后进行文件切换,它不阻塞读写的秘诀就是新建文件和拷贝的过程是在线做的,在没有完成拷贝之前,原来的文件还是可以读写的,只有在切表那一瞬间可能会有影响。

那么它是怎么做到在线拷贝的呢?源库的数据文件一直在变,所以表文件其实分为两部分,一部分是基础数据,一部分是增量数据,基础数据的拷贝就是正常的拷贝,增量数据是通过创建触发器来捕获在该表上的读写操作来实现的,待基础数据拷贝完后再将trigger捕获的增量sql进行应用,达到最终结果。

我们其实可以发现,pg_repack会在库里创建名为repack的schema,里面有两张表:primary_keys和tables。Primarys分为两列,第一列indrelid代表表的oid,第二列indexrelid代表主键或唯一索引的oid。Tables表记录了创建trigger以及捕获的相关语句,语句按一条条的record进行记录。如下所示:

test=# select * from tables;
-[ RECORD 1 ]-----+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
relname           | public.products
relid             | 16388
reltoastrelid     | 16391
reltoastidxid     | 16393
schemaname        | public
pkid              |
ckid              |
create_pktype     |
create_log        | CREATE TABLE repack.log_16388 (id bigserial PRIMARY KEY, pk repack.pk_16388, row public.products)
create_trigger    |
enable_trigger    | ALTER TABLE public.products ENABLE ALWAYS TRIGGER repack_trigger
create_table_1    | CREATE TABLE repack.table_16388 WITH (oids = false) TABLESPACE
tablespace_orig   | pg_default
create_table_2    |  AS SELECT product_no,name,price FROM ONLY public.products
copy_data         | INSERT INTO repack.table_16388 SELECT product_no,name,price FROM ONLY public.products
alter_col_storage |
drop_columns      |
delete_log        | DELETE FROM repack.log_16388
lock_table        | LOCK TABLE public.products IN ACCESS EXCLUSIVE MODE
ckey              |
sql_peek          | SELECT * FROM repack.log_16388 ORDER BY id LIMIT $1
sql_insert        | INSERT INTO repack.table_16388 VALUES ($1.*)
sql_delete        |
sql_update        |
sql_pop           | DELETE FROM repack.log_16388 WHERE id IN (
-[ RECORD 2 ]-----+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
relname           | public.test
relid             | 16400
reltoastrelid     | 0
reltoastidxid     | 0
schemaname        | public
pkid              |
ckid              |
create_pktype     |
create_log        | CREATE TABLE repack.log_16400 (id bigserial PRIMARY KEY, pk repack.pk_16400, row public.test)
create_trigger    |
enable_trigger    | ALTER TABLE public.test ENABLE ALWAYS TRIGGER repack_trigger
create_table_1    | CREATE TABLE repack.table_16400 WITH (oids = false) TABLESPACE
tablespace_orig   | pg_default
create_table_2    |  AS SELECT id FROM ONLY public.test
copy_data         | INSERT INTO repack.table_16400 SELECT id FROM ONLY public.test
alter_col_storage |
drop_columns      |
delete_log        | DELETE FROM repack.log_16400
lock_table        | LOCK TABLE public.test IN ACCESS EXCLUSIVE MODE
ckey              |
sql_peek          | SELECT * FROM repack.log_16400 ORDER BY id LIMIT $1
sql_insert        | INSERT INTO repack.table_16400 VALUES ($1.*)
sql_delete        |
sql_update        |
sql_pop           | DELETE FROM repack.log_16400 WHERE id IN (
-[ RECORD 3 ]-----+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
relname           | public.fruits
relid             | 16394
reltoastrelid     | 16397
reltoastidxid     | 16399
schemaname        | public
pkid              |
ckid              |
create_pktype     |
create_log        | CREATE TABLE repack.log_16394 (id bigserial PRIMARY KEY, pk repack.pk_16394, row public.fruits)
create_trigger    |
enable_trigger    | ALTER TABLE public.fruits ENABLE ALWAYS TRIGGER repack_trigger
create_table_1    | CREATE TABLE repack.table_16394 WITH (oids = false) TABLESPACE
tablespace_orig   | pg_default
create_table_2    |  AS SELECT number,name,price FROM ONLY public.fruits
copy_data         | INSERT INTO repack.table_16394 SELECT number,name,price FROM ONLY public.fruits
alter_col_storage |
drop_columns      |
delete_log        | DELETE FROM repack.log_16394
lock_table        | LOCK TABLE public.fruits IN ACCESS EXCLUSIVE MODE
ckey              |
sql_peek          | SELECT * FROM repack.log_16394 ORDER BY id LIMIT $1
sql_insert        | INSERT INTO repack.table_16394 VALUES ($1.*)
sql_delete        |
sql_update        |
sql_pop           | DELETE FROM repack.log_16394 WHERE id IN (
-[ RECORD 4 ]-----+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
relname           | public.test_1
relid             | 16475
reltoastrelid     | 0
reltoastidxid     | 0
schemaname        | public
pkid              | 16493
ckid              |
create_pktype     | CREATE TYPE repack.pk_16475 AS (c1 integer)
create_log        | CREATE TABLE repack.log_16475 (id bigserial PRIMARY KEY, pk repack.pk_16475, row public.test_1)
create_trigger    | CREATE TRIGGER repack_trigger AFTER INSERT OR DELETE OR UPDATE ON public.test_1 FOR EACH ROW EXECUTE PROCEDURE repack.repack_trigger('INSERT INTO repack.log_16475(pk, row) VALUES( CASE WHEN $1 IS NULL THEN NULL ELSE (ROW($1.c1)::repack.pk_16475) END, $2)')
enable_trigger    | ALTER TABLE public.test_1 ENABLE ALWAYS TRIGGER repack_trigger
create_table_1    | CREATE TABLE repack.table_16475 WITH (oids = false) TABLESPACE
tablespace_orig   | pg_default
create_table_2    |  AS SELECT c1,c2,c3,c4,c5 FROM ONLY public.test_1
copy_data         | INSERT INTO repack.table_16475 SELECT c1,c2,c3,c4,c5 FROM ONLY public.test_1
alter_col_storage |
drop_columns      |
delete_log        | DELETE FROM repack.log_16475
lock_table        | LOCK TABLE public.test_1 IN ACCESS EXCLUSIVE MODE
ckey              |
sql_peek          | SELECT * FROM repack.log_16475 ORDER BY id LIMIT $1
sql_insert        | INSERT INTO repack.table_16475 VALUES ($1.*)
sql_delete        | DELETE FROM repack.table_16475 WHERE (c1) = ($1.c1)
sql_update        | UPDATE repack.table_16475 SET (c1, c2, c3, c4, c5) = ($2.c1, $2.c2, $2.c3, $2.c4, $2.c5) WHERE (c1) = ($1.c1)
sql_pop           | DELETE FROM repack.log_16475 WHERE id IN (

好吧,加油吧。

欢迎关注我的公众号:数据库架构之美

使用pg_repack实现在线vacuum相关推荐

  1. postgres数据库表空间收缩之pg_squeeze,pg_repack

    #数据库表空间收缩之pg_squeeze,pg_repack 文章目录 pg_squeeze1.2 原理 优点 安装 使用 pgstattuple 临时处理 监控方式 注意事项 squeeze1.2和 ...

  2. 编程器P800-ISP在线编程器接口介绍

    完整文件:n459.com/file/25127180-478863159 以下内容无关: -------------------------------------------分割线-------- ...

  3. pg_repack使用

    可参考官方文档: https://reorg.github.io/pg_repack/?spm=a2c63.p38356.879954.3.6d6d15b3rdFspH RDS PostgreSQL支 ...

  4. postgresql垃圾清理插件pg_repack

    pg_repack插件部署: wget http://api.pgxn.org/dist/pg_repack/1.4.5/pg_repack-1.4.5.zip source /home/postgr ...

  5. pg_repack插件安装使用

    pg_repack插件安装使用 获取代码 在 这个链接里 可以选择需要下载的pg_repack版本 wget http://api.pgxn.org/dist/pg_repack/1.4.4/pg_r ...

  6. pg_repack bloat 处理测试初步

    一.软件安装 1.软件需求: postgresql-9.5.2.tar.gz pg_repack-1.3.4.zip 2.安装pg_repack [root@localhost pg_repack-1 ...

  7. PostgreSQL 并行vacuum patch - 暨为什么需要并行vacuum或分区表

    标签 PostgreSQL , vacuum , freeze , 分区表 , 并行vacuum 背景 我们之前做过一个这样的测试,单表数据从1000万到10亿,对其进行增删改查的压测,性能几乎没有衰 ...

  8. 新特性:postgresql的vacuum漫谈

    关注我们,下载更多资源 刘伟 刘伟,云和恩墨软件开发部研究院研究员:前微博DBA,主要研究方向为开源数据库,分布式数据库,擅长自动化运维以及数据库内核研究. ◆◆前言◆◆ 即便是从数据库特性,SQL功 ...

  9. [渝粤教育] 西南科技大学 英语泛读 在线考试复习资料

    英语泛读--在线考试复习资料 一.单选题 1.It is recommended that the project ______ until all the preparations have bee ...

最新文章

  1. linux动态库注册函数,Linux动态库函数的详解
  2. More than React(一)为什么ReactJS不适合复杂交互的前端项目?
  3. 交换机和路由器的区别_路由器与交换机的区别?
  4. 编程菜鸟的日记-初学尝试编程-寻找2到n之间的素数并输出
  5. 基于Vue的Quasar Framework 介绍 这个框架UI组件很全面
  6. WRF用户手册翻译:Chapter 5: WRF Model
  7. Redis哈希数详解
  8. 阅读《大型网站技术架构》前两章心得体会及总结
  9. Linux的学习方法
  10. 自己定义图片的progressbar
  11. Ajax请求URL后加随机数原理
  12. c#socket编程 (转)
  13. 人人开源(快速搭建项目)
  14. html+css+js:文案馆网页设计
  15. CentOS安装NTFS-3G读写Windows 10的移动NTFS磁盘
  16. Cron表达式学习:每天十二点执行一次:0 0 12 * * ?
  17. 一寸照像素和厘米的关系及换算
  18. 全球及中国大健康产业投资潜力与运营价值分析报告2022-2028年
  19. LDF转Excel;LDF转位定义;Excel转LDF;Excel转位定义;MatrixCreat(四)之工具使用
  20. bilstm-crf_序列标注问题

热门文章

  1. cdh 添加jar包_hive引入jar包--HIVE.AUX.JARS.PATH和hive.aux.jars.path
  2. QT 度和温度符号的显示(字符编码)
  3. JSP导入导出Excel功能
  4. 批量提取 srt 字幕文件中的文字
  5. 迭代模型(Iterative Model)
  6. 瀑布模型原型模型迭代模型螺旋模型的适用场景
  7. Android自定义圆角矩形图片ImageView
  8. 数字信号处理3个作业-----作业3自相关与Burg求解AR模型系数以估计其功率谱
  9. chrome提示代理(https://....)要求提供用户名和密码
  10. 快速删除node_modules(rimraf)