一、问题描述

用户在实际中可能会碰到类似以下 dead rows 无法 vacuum的问题,一个可能的原因是由于游标未结束的原因。

test=# vacuum(verbose) t1;
INFO: vacuuming "public.t1"
INFO: "t1": found 0 removable, 985 nonremovable row versions in 66 out of 67 pages
DETAIL: 788 dead row versions cannot be removed yet, oldest xmin: 4996
There were 0 unused item identifiers.
Skipped 1 page due to buffer pins, 0 frozen pages.
0 pages are entirely empty.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
INFO: vacuuming "pg_toast.pg_toast_29558"
INFO: index "pg_toast_29558_index" now contains 0 row versions in 1 pages
DETAIL: 0 index row versions were removed.
0 index pages have been deleted, 0 are currently reusable.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
INFO: "pg_toast_29558": found 0 removable, 0 nonremovable row versions in 0 out of 0 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 4996
There were 0 unused item identifiers.
Skipped 0 pages due to buffer pins, 0 frozen pages.
0 pages are entirely empty.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.

二、举例说明

1、事务不提交的情况

创建测试数据:

create table t1(id integer,name text);
create table t2(id integer);
insert insert t1 select generate_series(1,1000),repeat('a',500);

创建测试过程:

create or replace procedure proc01_nocommit as
cursor c01 is select id from t1;
v_id integer;
begin
open c01;
fetch c01 into v_id;
while (c01%FOUND) loop
insert into t2 values(v_id);
perform pg_sleep(1);
fetch c01 into v_id;
end loop;
end;
/

session 1:

call proc01_nocommit();

session 2:

test=# select * from pg_locks where relation='t1'::regclass;
locktype | database | relation | page | tuple | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction | pid | mode | granted | fastpath
----------+----------+----------+------+-------+------------+---------------+---------+-------+----------+--------------------+--------+-----------------+---------+----------
relation | 29504 | 29558 | | | | | | | | 4/2737 | 360612 | AccessShareLock | t | t
(1 row) test=# delete from t1 where mod(id,5)<>1;
DELETE 200

  

无法 vacuum

test=# vacuum(verbose) t1;
INFO: vacuuming "public.t1"
INFO: "t1": found 0 removable, 985 nonremovable row versions in 66 out of 67 pages
DETAIL: 788 dead row versions cannot be removed yet, oldest xmin: 4996
There were 0 unused item identifiers.
Skipped 1 page due to buffer pins, 0 frozen pages.
0 pages are entirely empty.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
INFO: vacuuming "pg_toast.pg_toast_29558"
INFO: index "pg_toast_29558_index" now contains 0 row versions in 1 pages
DETAIL: 0 index row versions were removed.
0 index pages have been deleted, 0 are currently reusable.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
INFO: "pg_toast_29558": found 0 removable, 0 nonremovable row versions in 0 out of 0 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 4996
There were 0 unused item identifiers.
Skipped 0 pages due to buffer pins, 0 frozen pages.
0 pages are entirely empty.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
VACUUM

  

结论:可以看到对象有 AccessShareLock 锁(实际验证,不管只要 cursor 定义了,不管是否open ,都会有 AccessShareLock 锁)。

2、事务提交的情景

修改过程块如下:

create or replace procedure proc01_commit as
cursor c01 is select id from t1;
v_id integer;
begin
open c01;
fetch c01 into v_id;
while (c01%FOUND) loop
insert into t2 values(v_id);
perform pg_sleep(1);
fetch c01 into v_id;
commit;
end loop;
end;
/

可以看到在游标内部加了commit;

PS:KingbaseES 支持游标跨事务的场景。在 commit时,会将剩余未完成游标的结果取回到临时文件,这样可以保证MVCC 机制。

Session 1:

call proc01_commit()

Session 2:

test=# select * from pg_locks where relation='t1'::regclass;
locktype | database | relation | page | tuple | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction | pid | mode | granted | fastpath
----------+----------+----------+------+-------+------------+---------------+---------+-------+----------+--------------------+--------+-----------------+---------+----------
(0 row) test=# delete from t1 where mod(id,5)<>0;
DELETE 800

  

结论:没有锁,可以vacuum。

test=# vacuum (verbose) t1;
INFO: vacuuming "public.t1"
INFO: "t1": removed 800 row versions in 67 pages
INFO: "t1": found 800 removable, 200 nonremovable row versions in 67 out of 67 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 4857
There were 0 unused item identifiers.
Skipped 0 pages due to buffer pins, 0 frozen pages.
0 pages are entirely empty.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
INFO: vacuuming "pg_toast.pg_toast_29549"
INFO: index "pg_toast_29549_index" now contains 0 row versions in 1 pages
DETAIL: 0 index row versions were removed.
0 index pages have been deleted, 0 are currently reusable.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
INFO: "pg_toast_29549": found 0 removable, 0 nonremovable row versions in 0 out of 0 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 4857
There were 0 unused item identifiers.
Skipped 0 pages due to buffer pins, 0 frozen pages.
0 pages are entirely empty.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
VACUUM

游标长时间open导致表无法vacuum问题的更多相关文章

  1. 防止shell脚本长时间执行导致ssh超时

    在一些对安全性要求较高的场景下.ssh的超时时间是管理员预先设置好的,在闲置一段时间后ssh连接会自己主动断开. 这样的情况下假设通过ssh运行脚本,而脚本运行时间又比較长的话.会导致sshclien ...

  2. JVM 调优 —— GC 长时间停顿问题及解决方法

    零. 简介 垃圾收集器长时间停顿,表现在 Web 页面上可能是页面响应码 500 之类的服务器错误问题,如果是个支付过程可能会导致支付失败,将造成公司的直接经济损失,程序员要尽量避免或者说减少此类情况 ...

  3. SQL一次查出相关类容避免长时间占用表(下)

    /* server: db: EDI */ -- 以下案例多次查询同一张表,仅有Name条件不同 --可以使用一次查出相关类容避免长时间占用表 USE EDI GO DECLARE @FileType ...

  4. SQL一次查出相关类容避免长时间占用表(上)

    /* server: db: EDI */ -- 以下案例多次查询同一张表,仅有组合条件Name+Direction不同 --可以使用一次查出相关类容避免长时间占用表 USE EDI GO DECLA ...

  5. kali长时间未使用导致数字签名过期无法更新源解决办法

    kali长时间未使用,数字签名会过期,从而导致无法更新源. apt-get update:从源(Source)服务器那里下载最新的软件包列: apt-get upgrade:对已经安装的软件包本身进行 ...

  6. 查看Oracle中存储过程长时间被卡住的原因

    1:查V$DB_OBJECT_CACHE SELECT * FROM V$DB_OBJECT_CACHE WHERE name='CUX_OE_ORDER_RPT_PKG' AND LOCKS!='0 ...

  7. ASP.NET 工作流:支持长时间运行操作的 Web 应用程序

    ASP.NET 工作流 支持长时间运行操作的 Web 应用程序 Michael Kennedy   代码下载位置:MSDN 代码库 在线浏览代码 本文将介绍以下内容: 独立于进程的工作流 同步和异步活 ...

  8. ios之申请后台延时执行和做一个假后台的方法(系统进入长时间后台后,再进入前台部分功能不能实现)

    转自:http://sis hu ok.com/forum/blogCategory/showByCategory.html?categories_id=138&user_id=10385   ...

  9. 为什么drop table的时候要在checking permissions花很长时间?

    昨天,我drop一个表的时候在checking permissions花了20s+,这个时间花在哪里了呢?经常查找发现我的配置文件innodb_file_per_table=1的,innodb需要遍历 ...

随机推荐

  1. 【Parcel 2 + Vue 3】从0到1搭建一款极快,零配置的Vue3项目构建工具

    前言 一周时间,没见了,大家有没有想我啊!哈哈!我知道肯定会有的.言归正传,我们切入正题.上一篇文章中我主要介绍了使用Vite2+Vue3+Ts如何更快的入手项目.那么,今天我将会带领大家认识一个新的 ...

  2. application.yml 常用基本配置

    前言 在平时的项目开发中,自己对application.yml的配置的写法较为熟悉,现在自己就application.yml常用的配置进行总结如下: 1.Tomcat 配置 server: #设置请求 ...

  3. NC25043 [USACO 2007 Jan S]Protecting the Flowers

    NC25043 [USACO 2007 Jan S]Protecting the Flowers 题目 题目描述 Farmer John went to cut some wood and left ...

  4. Java服务假死后续之内存溢出

    一.现象分析 上篇博客说到,Java服务假死的原因是使用了Guava缓存,30分钟的有效期导致Full GC无法回收内存.经过优化后,已经不再使用Guava缓存,实时查询数据.从短期效果来看,确实解决 ...

  5. Sentinel-流量防卫兵

    1.背景 1.1 简介 Sentinel 以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度保护服务的稳定性. Sentinel 具有以下特征 丰富的应用场景:Sentinel 承接了阿里巴 ...

  6. 如何参与开源项目 - 细说 GitHub 上的 PR 全过程

    目录 一.概述 二.为什么要参与开源项目 三.为什么我想介绍如何 PR 四.我想参与开源项目,怎么开始? 4.1.寻找一个合适的开源项目 4.2.寻找贡献点 五.我要提交 PR,怎么上手? 5.1.第 ...

  7. pytorch 基础内容

    一些基础的操作: import torch as th a=th.rand(3,4) #随机数,维度为3,4的tensor b=th.rand(4)print(a)print(b) a+b tenso ...

  8. Java变量和Scanner类

    1.变量的分类1)按数据类型分类   详细说明: 1. 整型:byte(1字节=8bit) \ short(2字节) \ int(4字节) \ long(8字节)   ① byte范围:-128 ~ ...

  9. GET 和 POST 请求的区别与安全性

    超文本传输协议( HTTP )是用于启用客户端与服务器之间的通信,其中 GET 请求和 POST 请求是则是 HTTP 方法中最为常用的两种.那么这 GET 和 POST 的区别到底是什么呢?两者是否 ...

  10. 高级数据结构学习笔记 / Data Structure(updating)

    树状数组   查询操作:O(logn) 修改操作:O(logn) #define lowbit(x) (x & -x) int tr[N]; // 树状数组 // 添加c个大小为x的数值 vo ...