一、问题描述

用户在实际中可能会碰到类似以下 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. NC16462 [NOIP2015]跳石头

    NC16462 [NOIP2015]跳石头 题目 题目描述 一年一度的"跳石头"比赛又要开始了! 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块 ...

  2. Spring Boot 知识点总结

    现在仅总结重要和实用的知识点,更加全面的请见链接:1.:2.. 微服务:架构风格(服务微化):一个应用应该是一组小型服务:可以通过HTTP的方式进行互通:微服务:每一个功能元素终都是一个可独立替换和独 ...

  3. ModuleNotFoundError: No module named 'distutils.spawn'

    解决办法: 安装python3-distutils sudo apt-get install python3-distutils

  4. C++多文件源程序

    一.多文件结构的源代码组织 一个C++程序开发工程(project)可以包含多个源程序文件,一个源程序文件(.cpp)可以包含多个函数.一个函数只能集中放在一个源程序文件中,不能将其定义代码拆开存放在 ...

  5. umask计算创建文件、目录的默认权限

    很多人以为 创建文件默认权限就是 666-umask=创建文件的默认权限 创建目录的默认权限就是 777-umask=创建目录的默认权限   这种计算其实是不严谨的 为什么我们创建的文件的权限是 64 ...

  6. 002 JWT令牌

    1.JWT数据 Json Web Token 添加数据 --> 解析数据 --> 传递数据 1.1 JWT数据处传递流程 注意:JWT数据必须携带在请求头(Request Header)的 ...

  7. 01 Mybatis框架添加英雄步骤

    客户端发出请求的几种方式 通过浏览器的地址栏中发出请求 通过html页面中的超链接发出请求 通过html页面中的form表单发出请求 通过前端框架发出请求 工程中使用数据库需要做的几件事: 在pom. ...

  8. day05 Java_循环_基本类型数组

    精华笔记: 循环结构: for结构:应用率高.与次数相关的循环 三种循环结构的选择规则: 先看循环是否与次数相关: 若相关----------------------------直接上for 若无关, ...

  9. golang面试-代码编写题1-14

    目录 1.代码编写题--统计文本行数-bufio 2.代码编写题--多协程收集错误信息-channel 3.代码编写题--超时控制,内存泄露 4.代码编写题--单例模式 5.代码编写题--九九乘法表 ...

  10. Centos7基本配置信息查看

    Centos7查看cpu,内存,磁盘等信息 cpu信息 cat /proc/cpuinfo |grep "model name" && cat /proc/cpui ...