5.4. 系统列

每一个表都拥有一些由系统隐式定义的系统列。因此,这些列的名字不能像用户定义的列一样使用(注意这种限制与名称是否为关键词没有关系,即便用引号限定一个名称也无法绕过这种限制)。 事实上用户不需要关心这些列,只需要知道它们存在即可。
  • oid:一行的对象标识符(对象ID)。该列只有在表使用WITH OIDS创建时或者default_with_oids配置变量被设置时才存在。该列的类型为oid(与列名一致),该类型详见 8.18. 对象标识符类型
  • tableoid:包含这一行的表的OID。该列是特别为从继承层次(见 5.9. 继承 )中选择的查询而准备,因为如果没有它将很难知道一行来自于哪个表。tableoid可以与pg_class的oid列进行连接来获得表的名称。
  • xmin:插入该行版本的事务身份(事务ID)。一个行版本是一个行的一个特别版本,对一个逻辑行的每一次更新都将创建一个新的行版本。
  • cmin:插入事务中的命令标识符(从0开始)。
  • xmax:删除事务的身份(事务ID),对于未删除的行版本为0。对于一个可见的行版本,该列值也可能为非零。这通常表示删除事务还没有提交,或者一个删除尝试被回滚。
  • cmax:删除事务中的命令标识符,或者为0。
  • ctid:行版本在其表中的物理位置。注意尽管ctid可以被用来非常快速地定位行版本,但是一个行的ctid会在被更新或者被VACUUM FULL移动时改变。因此,ctid不能作为一个长期行标识符。OID或者最好是一个用户定义的序列号才应该被用来标识逻辑行。

OID是32位量,它从一个服务于整个集簇的计数器分配而来。在一个大型的或者历时长久的数据库中,该计数器有可能会出现绕回。因此,不要总是假设OID是唯一的,除非你采取了措施来保证。如果需要在一个表中标识行,推荐使用一个序列生成器。然而,OID也可以被使用,但是是要采取一些额外的预防措施:

  • 如果要将OID用来标识行,应该在OID列上创建一个唯一约束。当这样一个唯一约束(或唯一索引)存在时,系统会注意不生成匹配现有行的OID(当然,这只有在表的航数目少于 \( 2^{32}\) (40亿)时才成立。并且在实践中表的尺寸最好远比这个值小,否则将会牺牲性能)。
  • 绝不要认为OID在表之间也是唯一的,使用tableoid和行OID的组合来作为数据库范围内的标识符。
  • 当然,问题中的表都必须是用WITH OIDS创建。在PostgreSQL 8.1中,WITHOUT OIDS是默认形式。

事务标识符也是32位量。在一个历时长久的数据库中事务ID同样会绕回。但如果采取适当的维护过程,这不会是一个致命的问题,详见第 23 章。但是,长期(超过10亿个事务)依赖事务ID的唯一性是不明智的。

命令标识符也是32位量。这对一个事务中包含的SQL命令设置了一个硬极限: \( 2^{32}\) (40亿)。在实践中,该限制并不是问题 — 注意该限制只是针对SQL命令的数目而不是被处理的行数。同样,只有真正 修改了数据库内容的命令才会消耗一个命令标识符。

下一节:当我们已经创建了一个表并意识到犯了一个错误或者应用需求发生改变时,我们可以移除表并重新创建它。但如果表中已经被填充数据或者被其他数据库对象引用(例如有一个外键约束),这种做法就显得很不方便。因此,PostgreSQL提供了一族命令来对已有的表进行修改。注意这和修改表中所包含的数据是不同的,这里要做的是对表的定义或者说结构进行修改。