PostgreSQL隐藏字段tableoid
问题来源:
今天群里有人问:tableoid字段在每行都有,而且一个表里面的值是重复的,这样不合理......
因此做了一些分析:
1)创建了一个表
apple=# \d test_time Table "public.test_time" Column | Type | Modifiers --------+-----------------------------+----------- id | integer | date | timestamp without time zone |
2)查看该表的所有字段 包括隐藏的:
apple=# select * from pg_attribute where attrelid in (select oid from pg_class where relname = 'test_time'); attrelid | attname | atttypid | attstattarget | attlen | attnum | attndims | attcacheoff | atttypmod | attbyval | attstorage | attalign | attnotnull | atthasdef | attisdropped | attislocal | attinhcount | attcollation | attacl | attoptions | attfdwoptions ----------+----------+----------+---------------+--------+--------+----------+-------------+-----------+----------+------------+----------+------------+-----------+--------------+------------+-------------+--------------+--------+------------+--------------- 33433 | tableoid | 26 | 0 | 4 | -7 | 0 | -1 | -1 | t | p | i | t | f | f | t | 0 | 0 | | | 33433 | cmax | 29 | 0 | 4 | -6 | 0 | -1 | -1 | t | p | i | t | f | f | t | 0 | 0 | | | 33433 | xmax | 28 | 0 | 4 | -5 | 0 | -1 | -1 | t | p | i | t | f | f | t | 0 | 0 | | | 33433 | cmin | 29 | 0 | 4 | -4 | 0 | -1 | -1 | t | p | i | t | f | f | t | 0 | 0 | | | 33433 | xmin | 28 | 0 | 4 | -3 | 0 | -1 | -1 | t | p | i | t | f | f | t | 0 | 0 | | | 33433 | ctid | 27 | 0 | 6 | -1 | 0 | -1 | -1 | f | p | s | t | f | f | t | 0 | 0 | | | 33433 | id | 23 | -1 | 4 | 1 | 0 | -1 | -1 | t | p | i | f | f | f | t | 0 | 0 | | | 33433 | date | 1114 | -1 | 8 | 2 | 0 | -1 | -1 | t | p | d | f | f | f | t | 0 | 0 | | | (8 rows)
可以发现有6个隐藏的字段,其中cmax xmax cmin xmin都跟事物有关,在PG事物处理相关文章中可以经常看到。
恰好前段时间研究PG表去重复数据用过ctid,物理地址块上的编号,因此今天再来学习一下tableoid。
3)初步分析结果:
A. 存磁盘的时候,数据是一行一行的存储,有必要知道该行数据属于哪个表。(那么如果支持列存储的话,确实可以对这些数据进行压缩了,只存一条即可。)
B. 继承表的情况,知道数据是在哪个子表里面。
4)视图不会有默认字段:
apple=# select * from pg_attribute where attrelid in (select oid from pg_class where relname in (select viewname from pg_views)) and attnum < 0; attrelid | attname | atttypid | attstattarget | attlen | attnum | attndims | attcacheoff | atttypmod | attbyval | attstorage | attalign | attnotnull | atthasdef | attisdropped | attislocal | attinhcount | attcollation | attacl | attoptions | attfdwoptions ----------+---------+----------+---------------+--------+--------+----------+-------------+-----------+----------+------------+----------+------------+-----------+--------------+------------+-------------+--------------+--------+------------+--------------- (0 rows)
5)以后想查看表的oid再也不用去pg_class里面找了:
apple=# select tableoid from test_time; tableoid ---------- 33433 (1 row)
搞了半天发现也没啥,白折腾了......
-----------------------
在创建表的时候,可以选择是否创建有OID的隐藏列:create table xxx (id int,...) with oids;
apple=# create table test_without_oid(id int, info text, crt_time timestamp) without oids; CREATE TABLE apple=# select oid, * from test_without_oid ; ERROR: column "oid" does not exist LINE 1: select oid, * from test_without_oid ; ^ HINT: Perhaps you meant to reference the column "test_without_oid.id". apple=# select * from test_without_oid ; id | info | crt_time ----+------+---------- (0 rows) apple=# create table test_with_oid(id int, info text, crt_time timestamp) with oids; CREATE TABLE apple=# select oid, * from test_with_oid ; oid | id | info | crt_time -----+----+------+---------- (0 rows)
--2017-05-05
参考消息:
每个表都有几个系统字段,这些字段是由系统隐含定义的。 因此,这些名字不能用于用户定义的字段名。 (请注意这些限制与这个名字是否关键字无关;把名字用引号括起来并不能让你逃离这些限制。) 你实际上不需要注意这些字段,只要知道它们存在就可以了。 oid 行的对象标识符(对象 ID)。这个字段只有在创建表的时候使用了 WITH OIDS,或者是设置了配置参数 default_with_oids 时出现。 这个字段的类型是 oid(和字段同名); 参阅Section 8.12 获取有关这种类型的更多信息。 tableoid 包含本行的表的 OID。这个字段对那些从继承层次中选取的查询特别有用(参阅 Section 5.8), 因为如果没有它的话,我们就很难说明一行来自哪个独立的表。 tableoid 可以和pg_class 的 oid 字段连接起来获取表名字。 xmin 插入该行版本的事务的标识(事务 ID)。(注意:在这个环境里, 一个行版本是一行的一个状态;一行的每次更新都为同一个逻辑行创建一个新的行版本。) cmin 在插入事务内部的命令标识(从零开始)。 xmax 删除事务的标识(事务ID),如果不是被删除的行版本,那么是零。 在一个可见行版本里,这个字段有可能是非零。这通常意味着删除事务还没有提交, 或者是一个删除的企图被回滚掉了。 cmax 在删除事务内部的命令标识符,或者是零。 ctid 一个行版本在它所处的表内的物理位置。请注意,尽管 ctid 可以用于非常快速地定位行版本,但每次 VACUUM FULL 之后, 一个行的 ctid 都会被更新或者移动。 因此 ctid 是不能作为长期的行标识符的。 应该使用OID,或者更好是用户定义的序列号,来标识一个逻辑行。
严以律己、宽以待人