Highgo数据库的全局临时表relpersistence

从一个highgo瀚高数据库的告警谈起,有套业务库告警一套业务库的年龄age过高,这是防止事务回卷的监控项,超过是2亿(autovacuum_freeze_max_age)的80%,于时同事查询了一下age 最大的表发现top 1是业务用户下的TOAD_PLAN_TABLE,age 接近21亿,也就是最大允许的值。继续分析发现在Highgo数据库相比pg多的一种表类型。

Age怎么算?

age函数是当前的事务id到最老的relfrozenxid之间的差,正常事务id一直增加,而relfrozenxid在做了vacuum freeze后也会增加。表的最老事务号则是记录在pg_class.relfrozenxid里面的,如果表的年龄大于autovacuum_freeze_max_age会自动freeze,或者手动vacuum freeze xxx或vacumm full xxx; 命令手动做freeze。

《PostgreSQL的事务回卷》分享过事务回卷,不再复述,

当前事务ID

SELECT pg_current_xact_id();

同时查询top age的表

select oid, relname, relfrozenxid ,age(relfrozenxid) age, pg_current_xact_id() 
from pg_class c
where c.relkind in ('r', 'm') order by age desc limit 10;

结果就有了开头的问题top 2表 20亿age , 表名为业务用户下的TOAD_PLAN_TABLE和quest_xxxx。其他表age都在1.6亿. 这两个表名对于Oracle DBA 并不陌生, 是Quest 公司的数据库客户端工作Toad 在查看执行计划时自动创建的全局临时表。 查看pg_class中的relfrozenxid 确实为0, pg_class.relfrozenxid 为 0 确实是一个特殊状态,如系统预编译或一些view,sequence等对象是0。在relkind列可以查看对应类型:

r = ordinary table, i = index, S = sequence, t = TOAST table, v = view, m = materialized view, c = composite type, f = foreign table, p = partitioned table, I = partitioned index

通常业务的table和mview不为0, table中又要排除临时表。 所以同事的SQL语名并不严谨应该是排除掉relfrozenxid=0的。

select oid, relname, relfrozenxid ,age(relfrozenxid) age, pg_current_xact_id() 
from pg_class c 
where c.relkind in ('r', 'm') and relfrozenxid <> 0 order by age desc limit 10;

临时表

在postgresql中支持临时表,但是不同于oracle中的临时表, 在postgresql中的临时表也是会话级和事务级,但是会话退出会删除。从字典中relpersistence 列可以确认

p = permanent table/sequence, u = unlogged table/sequence, t = temporary table/sequence
可以看到在postgresql中relpersistence 只有p,u,t. 希望我们查看这个案例中的TOAD_PLAN_TABLE的relpersistence 是g,那是怎么进来的呢?

测试

我们在highgo 中创建临时表。

$ psql
psql (14.10)
IvorySQL-pro-3.2.0
Type "help" for help.

highgo=# CREATE TEMPORARY TABLE temp_table (id int);
CREATE TABLE

highgo=# select oid,relname,reltype,relpages,relkind,relpersistence from pg_class where relname='temp_table';
  oid   |  relname   | reltype | relpages | relkind | relpersistence
--------+------------+---------+----------+---------+----------------
 121507 | temp_table |  121509 |        0 | r       | t
(1 row)

highgo=# CREATE global TEMPORARY TABLE g_temp_table (id int);
WARNING:  GLOBAL is deprecated in temporary table creation
LINE 1: CREATE global TEMPORARY TABLE g_temp_table (id int);
               ^
CREATE TABLE
highgo=# select oid,relname,reltype,relpages,relkind,relpersistence from pg_class where relname='g_temp_table';
  oid   |   relname    | reltype | relpages | relkind | relpersistence
--------+--------------+---------+----------+---------+----------------
 121510 | g_temp_table |  121512 |        0 | r       | t
(1 row)

=# \c highgo
IvorySQL-pro-3.2.0
You are now connected to database "highgo" as user "hg".
highgo=# select oid,relname,reltype::regtype,relpages,relkind,relpersistence from pg_class where relname='g_temp_table';
 oid | relname | reltype | relpages | relkind | relpersistence
-----+---------+---------+----------+---------+----------------
(0 rows)

Note: 临时表对应的relpersistence是t, 退出后表不存在。 也不是g, 那是因为当前是highgo的postgresql 模式,它还直接oracle模式,我们在oracle 模式下创建临时表。

[hg@dev]$ psql anbob system -p 1521 -s
psql (14.10)
IvorySQL-pro-3.2.0
Type "help" for help.

anbob=# select sysdate;
***(Single step mode: verify command)*******************************************
select sysdate;
***(press return to proceed or enter x and return to cancel)********************

      sysdate
-------------------
 20251016 13:29:42
(1 row)

anbob=# select relpersistence,relkind,count(*) from pg_class group by relpersistence,relkind;
***(Single step mode: verify command)*******************************************
select relpersistence,relkind,count(*) from pg_class group by relpersistence,relkind;
***(press return to proceed or enter x and return to cancel)********************

 relpersistence | relkind | count
----------------+---------+-------
 p              | v       |   183
 p              | r       |  5078
 p              | p       |     2
 p              | i       |  5170
 p              | t       |  5044
 p              | c       |     2
 p              | I       |     1
 p              | S       |     3
(8 rows)

anbob=# CREATE global TEMPORARY TABLE temp_table (id int);
***(Single step mode: verify command)*******************************************
CREATE global TEMPORARY TABLE temp_table (id int);
***(press return to proceed or enter x and return to cancel)********************

CREATE TABLE
anbob=# select relpersistence,relkind,count(*) from pg_class group by relpersistence,relkind;
***(Single step mode: verify command)*******************************************
select relpersistence,relkind,count(*) from pg_class group by relpersistence,relkind;
***(press return to proceed or enter x and return to cancel)********************

 relpersistence | relkind | count
----------------+---------+-------
 p              | v       |   183
 p              | r       |  5078
 p              | p       |     2
 g              | r       |     1
 p              | i       |  5170
 p              | t       |  5044
 p              | c       |     2
 p              | I       |     1
 p              | S       |     3
(9 rows)

anbob=# select oid,relname,reltype,relpages,relkind,relpersistence from pg_class where relname='temp_table';
***(Single step mode: verify command)*******************************************
select oid,relname,reltype,relpages,relkind,relpersistence from pg_class where relname='temp_table';
***(press return to proceed or enter x and return to cancel)********************

  oid   |  relname   | reltype | relpages | relkind | relpersistence
--------+------------+---------+----------+---------+----------------
 121519 | temp_table |  121521 |        0 | r       | g
(1 row)

anbob=# exit

[hg@ ~]$ psql anbob system -p 1521
psql (14.10)
IvorySQL-pro-3.2.0
Type "help" for help.

anbob=# select oid,relname,reltype,relpages,relkind,relpersistence from pg_class where relname='temp_table';
  oid   |  relname   | reltype | relpages | relkind | relpersistence
--------+------------+---------+----------+---------+----------------
 121519 | temp_table |  121521 |        0 | r       | g
(1 row)

NOte: 这就不奇怪了,该表是在highgo的oracle兼容模式下创建的临时表,对应的relpersistence为g, 这是postgresql所没有的,并且同oracle的临时表,在会话断开后并不会自动删除。

— over —

Leave a Comment