learning_notes

学习笔记

View project on GitHub

事务

事务和隔离级别

怎么实现的事务

MVCC:即多版本控制(Multi-Version-Control),通过增加的系统列 oid、tableoid、xmin、cmin、xmax、cmax来进行事务的隔离 PostgreSQL的mvcc实现是比较简单的。只需要通过对比tuple header中xmin,xmax,cmin,cmax与当前的xid,就可以得到在scan tuple时,此tuple对于当前查询的可视性 并发控制的目标是为所有会话提供高效的访问,同时还要维护严格的数据完整性

  • 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或者最好是一个用户定义的序列号才应该被用来标识逻辑行

VACUUM

PG没有回滚段(undo),旧版本和新版本放在一起,不断增大而带来空间膨胀问题,使用VACUUM回收,回缩空间

vacuum的功能

  • 回收空间: dead tuple清理掉,不会释放空间,新的数据会存放在这里,如果需要释放,执行vacuum full,但是需要exclusive lock。一般不太建议,一般合理设置vacuum参数,进行常规vacuum也就够了
  • 冻结tuple的xid: transactionID的最大值为2的32次, 当transactionID超过此最大值后,会循环使用,将过老的tuple的header中的事务ID进行冻结。冻结事务ID,即将事务ID设置为“2”(“0”表示无效事务ID;“1”表示bootstrap,即初始化;“3”表示最小的事务ID)
  • 更新统计信息: vacuum analyze时,会更新统计信息,让PG的planner能够算出更准确的执行计划.autovacuum_analyze_thresholdautovacuum_analyze_scale_factor参数可以控制analyze的触发的频率
  • 更新visibility map: 减少IO操作,提高性能

MVCC的实现方法有两种:

  • 写新数据时,把旧数据移到一个单独的地方,如回滚段中,其他人读数据时,从回滚段中把旧的数据读出来;(oracle和mysql innodb)

  • 写数据时,旧数据不删除,而是把新数据插入。(postgres)

PostgreSQL的MVCC实现方式的优缺点如下

  • 优点:
    • 事务回滚可以立即完成,无论事务进行了多少操作
    • 数据可以进行很多更新,不必像Oracle和MySQL的Innodb引擎那样需要经常保证回滚段不会被用完,也不会像oracle数据库那样经常遇到“ORA-1555”错误的困扰
  • 缺点:
    • 旧版本数据需要清理。PostgreSQL清理旧版本的命令成为Vacuum
    • 旧版本的数据会导致查询更慢一些,因为旧版本的数据存在于数据文件中,查询时需要扫描更多的数据块