摘要: 对于更新和删除操作频繁的表,会存在大量垃圾数据,导致磁盘空间的浪费和查询扫描时额外的IO开销,需要定期执行清理操作(vacuum)来控制行存表以及表上索引的膨胀。本文将对vacuum的原理以及影响vacuum效果的因素进行简单介绍。

本文分享自华为云社区《为什么vacuum后表还是继续膨胀?》,原文作者:大威天龙:-。

vacuum简介 :

对于GaussDB中的行存表,在更新元组或者删除元组后,旧版本的数据仍然存在,仅在元组头信息中标记了删除或更新的事务号(xmax)。对于更新和删除操作频繁的表,会存在大量垃圾数据,导致磁盘空间的浪费和查询扫描时额外的IO开销,需要定期执行清理操作(vacuum)来控制行存表以及表上索引的膨胀。

vacuum 操作的内部原理:

Vacuum 的主要步骤:

1.移除死亡元组并对满足条件的老元组执行frozen操作。

2.移除指向死亡元组的索引元组,更新对应表的fsm 和 vm 文件

    • FSM: free space map 空闲空间映射文件,插入数据时会根据该文件来选择合适的page.
    • VM: visibility map 可见性映射文件,后续vacuum时会根据该文件来选择是否扫描某个page,提高vacuum效率;同时在进行index-only-scan时也会使用该文件来提高可见性判断的效率)。

3.更新统计数据pg_stat_all_tables。 Linepointer 不会被移除,用于在之后复用。
示意图如下:

vacuum 之前

vacuum 之后

为什么vacuum后表还是继续膨胀

影响vacuum效果的因素

1、Oldestxmin的推进
vacuum 只能清理掉当前全局存活的最老事务(OldestXmin)之前的事务所产生的垃圾数据,所以如果仍然存在老事务的话(比如长事务或者长sql的存在),新事务所产生的垃圾数据并不会被vacuum立即清理。例如:

会话1:新建表row_tbl并插入一条数据,起一个事务先不提交

gaussdb=# create table row_tbl(a int, b int);
CREATE TABLE
gaussdb=# insert into row_tbl values(1,1);
INSERT 0 1
gaussdb=# begin;
BEGIN
gaussdb=# SELECT txid_current_snapshot();
txid_current_snapshot
-----------------------
210115:210115:
(1 row)
gaussdb=# SELECT txid_current();
txid_current
--------------
210115
(1 row)

会话2:删除数据后做vacuum清理操作,再次插入数据,数据也没有复用之前空间;查询视图可以发现垃圾数据并没有被清理掉。

gaussdb=# select ctid,* from row_tbl;
ctid | a | b
-------+---+---
(0,1) | 1 | 1
(1 row)
gaussdb=# delete row_tbl;
DELETE 1
gaussdb=# SELECT txid_current_snapshot();
txid_current_snapshot
-----------------------
210115:210122:
(1 row)
gaussdb=# vacuum row_tbl;
VACUUM
gaussdb=# insert into row_tbl values(2,2);
INSERT 0 1
gaussdb=# select ctid,* from row_tbl;
ctid | a | b
-------+---+---
(0,2) | 2 | 2
(1 row)
gaussdb=# select n_dead_tup, last_vacuum from pg_stat_all_tables where relname='row_tbl';
n_dead_tup | last_vacuum
------------+-------------------------------
1 | 2021-06-10 20:04:58.987631+08
(1 row)

会话1:将会话1的事务结束再执行vacuum,查询视图可以发现没有死亡元组,插入数据可以发现复用了旧的空间(即ctid是(0,1)的空间)。

gaussdb=# SELECT txid_current_snapshot();
txid_current_snapshot
-----------------------
210136:210136:
(1 row)
gaussdb=# vacuum row_tbl;
VACUUM
gaussdb=# select n_dead_tup, last_vacuum from pg_stat_all_tables where relname='row_tbl';
n_dead_tup | last_vacuum
------------+-------------------------------
0 | 2021-06-10 20:09:10.516564+08
(1 row)
gaussdb=# insert into row_tbl values(3,3);
INSERT 0 1
gaussdb=# select ctid,* from row_tbl;
ctid | a | b
-------+---+---
(0,1) | 3 | 3
(0,2) | 2 | 2
(2 rows)

2、LinePointer状态还未处于unused

元组被删除后,只有当vacuum将元组的LinePointer(或者叫item pointer, 指向具体的元组)置为LP_UNUSED状态后,该LinePointer才有可能在新插入数据时复用。

3、Fsm还未生成
插入数据时,依赖fsm文件来选择可用的page,如果fsm没有生成则会导致使用新的page而不是复用旧的。

4、批量导入
在旧版本Gaussdb中,对表进行批量插入数据的操作时,会直接申请新的page来插入数据。所以在某些场景下虽然vacuum后清理了脏数据,但由于业务场景以批量插入为主,导致vacuum对膨胀的控制效果并不理想。目前已经支持批量插入数据时对空间的复用。

一些建议与总结

  1. 尽量避免长事务,可以通过视图pg_running_xacts查看是否有老事务没有结束或者两阶段事务残留
  2. 定期做vacuum来及时回收垃圾空间
  3. 对于已经膨胀的索引可以通过reindex来缩小大小。
  4. vacuum能清理垃圾数据,但无法将这些空间还给操作系统,对于已经膨胀的表只能通过vacuum full来缩小大小。

想了解GuassDB(DWS)更多信息,欢迎微信搜索“GaussDB DWS”关注微信公众号,和您分享最新最全的PB级数仓黑科技~

点击关注,第一时间了解华为云新鲜技术~

为什么vacuum后表还是继续膨胀?的更多相关文章

  1. Greenplum 调优--VACUUM系统表

    Greenplum 调优--VACUUM系统表 1.VACUUM系统表原因 Greenplum是基于MVCC版本控制的,所有的delete并没有删除数据,而是将这一行数据标记为删除, 而且update ...

  2. php history.back返回后表单数据丢失的解决办法

    js使用history.back返回表单数据丢失的主要原因就是使用了session_start();的原因,该函数会强制当前页面不被缓存.本文章向码农介绍php history.back返回后表单数据 ...

  3. ASP.NET MVC 客户端验证失败后表单仍然提交问题

    客户端验证失败后表单仍然提交问题!导致页面刷新,辛辛苦苦输入的内容荡然无存. 多么奇怪的问题.按道理,验证失败,就应该显示各种错误信息,不会提交表单才对.而现在,错误信息正常显示,但页面却刷新了一遍. ...

  4. 包含LOB_Data列的表删除大量数据后表及数据库文件的收缩

    最近有一张表(内含varchar(max)字段),占用空间达到240G,删除历史数据后几十万条后,空间并未得到释放. 然后用DBCC CLEANTABLE(0,tb_name,100)来释放删除记录后 ...

  5. 按下enter键后表单自动提交问题

    在HTML的form表单里,按下enter键之后,默认情况下表单会自动提交. 在公司一个项目里,按下enter键自动提交表单的查询结果与按下搜索框的搜索结果页面显示不一样,按下搜索按钮之后是通过Aja ...

  6. oracle删除数据后表空间仍过大问题解决方法

    -----亲测有效------- --一.备份原始数据库库--1.备份空表--在plsql里面执行一下这句话 然后把结果集 再执行一把 再导数据select 'alter table '||table ...

  7. form表单中只有一个input时,按回车键后表单自动提交(form表单的一个小坑)

    form中只有一个input按回车键表单会自动提交 在一个form表单中,若只有一个input,按回车键表单会自动提交,但是当表单中存在多个input时,按回车键不会执行任何操作,这是form表单的一 ...

  8. bootstrap editable初始化后表单

    function loadData() { var url = "${ctx }/sys/marketing/product/page"; $('#tablepager').boo ...

  9. bootstrap editable初始化后表单可修改数据

    function loadData() { var url = "${ctx }/sys/marketing/product/page"; $('#tablepager').boo ...

  10. 在客户端先通过JS验证后再将表单提交到服务器

    问题:想要在客户端先通过JS验证后再将表单提交到服务器 参考资料: jQuery 事件 - submit() 方法 试验过程: 服务器端使用PHP <html> <head> ...

随机推荐

  1. 【羚珑AI智绘营】分分钟带你拿捏SD中的色彩控制

    导言 颜色控制一直是AIGC的难点,prompt会污染.img2img太随机- 今天带来利用controlnet,实现对画面颜色的有效控制.都说AIGC是抽卡,但对把它作为工具而非玩具的设计师,必须掌 ...

  2. 『STAOI』G - Round 2 半个游记

    很刺激. 2023.3.2 23:17 第一次过审. 2023.3.5 00:02 第一次打回. 原因是背锅人的链接又双叒叕挂错了((( 2023.3.6 21:20 第二次过审. 2023.3.8 ...

  3. Python合并多个Excel文件中的指定sheet

    本文将介绍一个用于合并多个Excel文件中指定sheet的Python代码.这个功能可以方便地整理和分析数据.我们将逐步解释代码的每个部分,并提供示例用法. 导入库 首先,我们导入了需要使用的三个库: ...

  4. synchronized 解决方案

    4.2 synchronized 解决方案 为了避免临界区的竞态条件发生,有多种手段可以达到目的. 阻塞式的解决方案:synchronized,Lock 非阻塞式的解决方案:原子变量 本次课使用阻塞式 ...

  5. JVM核心知识体系(转)

    1.问题 1.如何理解类文件结构布局? 2.如何应用类加载器的工作原理进行将应用辗转腾挪? 3.热部署与热替换有何区别,如何隔离类冲突? 4.JVM如何管理内存,有何内存淘汰机制? 5.JVM执行引擎 ...

  6. Util应用框架基础(五) - 异常处理

    本节介绍Util应用框架如何处理系统错误. 概述 系统在运行过程中可能发生错误. 系统错误可以简单分为两类: 系统异常 系统本身出现的错误. 业务异常 不满足业务规则出现的错误. 如何处理系统异常 如 ...

  7. off-line RL | CQL:魔改 Bellman error 更新,得到 Q 函数 lower-bound

    论文题目: Conservative Q-Learning for Offline Reinforcement Learning CQL 是师兄盛赞的一篇论文:"是 off-line RL ...

  8. 国企项目就用国产的 Solon Java Framework,v2.5.12 发布

    Solon 是什么框架? Java 新的生态级应用开发框架.国产.从零开始构建,有自己的标准规范与开放生态(历时五年,具备全球第二级别的生态规模).与其他框架相比,解决了两个重要的痛点:启动慢,费内存 ...

  9. 车的可用捕获量(3.26leetcode每日打卡)

    在一个 8 x 8 的棋盘上,有一个白色车(rook).也可能有空方块,白色的象(bishop)和黑色的卒(pawn).它们分别以字符 "R",".",&quo ...

  10. 终端必备大杀器----Fish

    目录 下载 安装 添加 权限 依赖库安装 cmake 预处理 编译 安装 配置fish 其他 下载 Github 地址-- fish-shell openSUSE 开源下载地址 openSUSE 开源 ...