暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Postgres系统表的隐含字段(一)

漠南的工作笔记 2017-02-10
625

为了方便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


cmincmax用于判断同一事务内的不同命令导致的行版本变化是否可见。如果一个事务内的所有命令都是严格按顺序执行的,那么每个命令都能看到之前该事物内的所有变更,这种情况下不需要使用命令标识。



ctid

tuple在表中的物理位置,vacuum不会改变ctidvacuum 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_classoid字段连接起来获取表名字。

         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,是系统字段xminxmax的数据类型。事务标识符占32位,范围应该在2^3240亿以内。超出后循环赋值操作

postgres=#  checkpoint;select txid_current();

CHECKPOINT

 txid_current

--------------

 172366    --注:当前txidtop_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的值)

txidxid的关系:   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)

 

 


文章转载自漠南的工作笔记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论