
为了方便postgresql的管理,在postgresql数据库中有几个字段,这些字段是由系统隐含定义的。因为表中已经隐含了这些命名的字段,所以用户定义的字段名称不能再使用这些名字。今天,就来整理下部分常见的隐藏列。
cmax
事务内部执行删除类操作的命令ID,此标识是从0开始的顺序增加的。下一次事务在该tuple上执行删除操作才会改变cmax数值。如果一个事务执行删除操作后执行rollback操作,cmax的值依旧会发生改变。所以通过cmax的值不能完全确定哪些tuple是在同一个事务上执行的,而且不能用于判断tuple上的数值是否发生过变化。
session 1: postgres=# select cmax ,* from stu order by id; cmax | id | name ------+----+------ 0 | 1 | Tom 0 | 2 | any 0 | 3 | lida (3 rows)
session 2: postgres=# begin; BEGIN postgres=# update stu set name='Tom' where id=1; UPDATE 1 postgres=# update stu set name='any' where id=2; UPDATE 1 postgres=# update stu set name='lida' where id=3; UPDATE 1
session 1: postgres=# select cmax ,* from stu order by id; cmax | id | name ------+----+------ 0 | 1 | Tom 1 | 2 | any 2 | 3 | lida (3 rows)
session 2: postgres=# rollback; ROLLBACK
postgres=# select cmax ,* from stu order by id; cmax | id | name ------+----+------ 0 | 1 | Tom 1 | 2 | any 2 | 3 | lida (3 rows) |
由于postgresql特有的MVCC机制。所以在执行了update操作后,等同于既执行了delete,又执行了insert。
cmin
事务内部执行插入类操作的命令ID,此标识是从0开始的顺序增加的。下一次事务在该tuple上执行插入操作才会改变cmin数值。如果一个事务执行插入操作后执行rollback操作,cmin的值依旧会发生改变。所以通过cmin的值不能完全确定哪些tuple是在同一个事务上执行的,而且不能用于判断tuple上的数值是否发生过变化。
session 1: postgres=# select cmin ,* from stu order by id; cmin | id | name ------+----+------ 0 | 1 | Tom 0 | 2 | any 0 | 3 | lida (3 rows)
session 2: postgres=# begin; BEGIN postgres=# update stu set name='Tom1' where id=1; UPDATE 1 postgres=# update stu set name='any1' where id=2; UPDATE 1 postgres=# update stu set name='lida1' where id=3;
session 1: postgres=# select cmin ,* from stu order by id; cmin | id | name ------+----+------ 0 | 1 | Tom 1 | 2 | any 2 | 3 | lida (3 rows)
session 2: postgres=# rollback; ROLLBACK
session 1: postgres=# select cmin ,* from stu order by id; cmin | id | name ------+----+------ 0 | 1 | Tom 1 | 2 | any 2 | 3 | lida (3 rows) |
由于postgresql特有的MVCC机制。所以在执行了update操作后,等同于既执行了delete,又执行了insert。
cmin和cmax用于判断同一事务内的不同命令导致的行版本变化是否可见。如果一个事务内的所有命令都是严格按顺序执行的,那么每个命令都能看到之前该事物内的所有变更,这种情况下不需要使用命令标识。
ctid
tuple在表中的物理位置,vacuum不会改变ctid,vacuum full时会改变。
postgres=# select ctid,* from stu1; ctid | id | name --------+----+------- (0,14) | 1 | Tom1 (0,15) | 2 | any2 (0,16) | 3 | lida3 (3 rows)
postgres=# vacuum stu1; VACUUM postgres=# select ctid,* from stu1; ctid | id | name --------+----+------- (0,14) | 1 | Tom1 (0,15) | 2 | any2 (0,16) | 3 | lida3 (3 rows)
postgres=# vacuum full; VACUUM postgres=# select ctid,* from stu1; ctid | id | name -------+----+------- (0,1) | 1 | Tom1 (0,2) | 2 | any2 (0,3) | 3 | lida3 (3 rows) |
oid
对象标识符(对象ID)。这个字段只有在创建表时使用了 "with oids" 或者配置参数 "default_with_oids" 的值为真时才出现, 这个字段的类型为 oid (类型名和字段名同名)。oid是全局分配的,并不是某一张表单独分配的。
tableoid
包含本行的表的oid。对父表(该表存在有继承关系的子表)进行查询时,使用这个字段就可以知道某一行来自父表还是子表,以及是哪个子表。tableoid可以和pg_class的oid字段连接起来获取表名字。
postgres=# create table test(id int); CREATE TABLE
postgres=# select tableoid from test; tableoid ---------- (0 rows)
postgres=# select tableoid from test; tableoid ---------- 18825 (1 row)
postgres=# select relname from pg_class where oid=18825; relname --------- test (1 row) 等价于 postgres=# select 18825::regclass; regclass ---------- test (1 row) 由此可以查询该数据来自于哪张表。 |
txid
当前事务ID,值范围在2^64内,不可循环,也xid存在等式关系,详见xid说明。
txid_current
当前事务ID,如果当前事务没有则分配一个新的,函数获取得到的值即为txid的值。
xid
事务(缩写xact)标识符xid,是系统字段xmin和xmax的数据类型。事务标识符占32位,范围应该在2^32约40亿以内。超出后循环赋值操作
postgres=# checkpoint;select txid_current(); CHECKPOINT txid_current -------------- 172366 --注:当前txid(top_level xid) (1 row) postgres=# \q [postgres@host-10-10-0-11 pgdata]$ pg_controldata | grep Latest\ checkpoint\'s\ NextXID: Latest checkpoint's NextXID: 0:172366 (注:此处的m:n两个数字的意思是:m - xid循环次数;n:当前xid的值) txid和xid的关系: txid =m*2^32+n |
xmin
插入tuple的事务id。新插入一行时,将新插入行的xmin填写为当前的事务ID。在事务中修改某一行时,实际上是新插入一行,旧行上的xmin不变,新行上的xmin填为当前事务ID。
xmax
删除此行时的事务ID,第一次插入时,此字段为0,如果查询出来此字段不为0,则可能是删除此字段的事务还没有提交,或者删除此行的事务回滚掉了。在事务中修改某一行时,旧行上的xmax改为改为当前的事务ID,新行上的xmax填为0。在事务中删除某一行,把被删除行上的xmax填为当前的事务ID
update情况实验:
session 1: postgres=# select xmax,id,name from stu; xmax | id | name ------+----+------- 0 | 1 | Tom 0 | 2 | Lili 0 | 3 | LiHUa (3 rows)
session 2: postgres=# begin; BEGIN postgres=# update stu set name='Tony' where id=2; UPDATE 1
session 1: postgres=# select xmax,id,name from stu; xmax | id | name --------+----+------- 0 | 1 | Tom 160165 | 2 | Lili 0 | 3 | LiHUa (3 rows)
session 2: postgres=# end; COMMIT
session 1: postgres=# select xmax,id,name from stu; xmax | id | name ------+----+------- 0 | 1 | Tom 0 | 3 | LiHUa 0 | 2 | Tony (3 rows) |
delete回滚实验:
session 1: postgres=# select xmax,id,name from stu order by id; xmax | id | name ------+----+------- 0 | 1 | Tom 0 | 2 | Tony 0 | 3 | LiHUa (3 rows)
session 2: postgres=# begin; BEGIN postgres=# delete from stu where id=3; DELETE 1
session 1: postgres=# select xmax,id,name from stu order by id; xmax | id | name --------+----+------- 0 | 1 | Tom 0 | 2 | Tony 160347 | 3 | LiHUa (3 rows)
session 2: postgres=# rollback;
session 1: postgres=# select xmax,id,name from stu order by id; xmax | id | name --------+----+------- 0 | 1 | Tom 0 | 2 | Tony 160347 | 3 | LiHUa (3 rows)
|




