ITPub博客

首页 > 数据库 > PostgreSQL > 浅析PostgreSQL事务处理机制

浅析PostgreSQL事务处理机制

PostgreSQL 作者:www_xyove 时间:2019-02-28 10:18:44 1 删除 编辑

背景说明:

以 ACID 为特征的事务是关系数据库的一项重要的也是基本的功能。了解事务的实现原理不仅对数据库产品本身的开发,对使用数据库的应用程序的开发也有一定的益处。因此本次以 PostgreSQL 为对象简单介绍了其事务实现的原理。

内容概述:

事务的实现原理可以解读为 DBMS 采取何种技术确保事务的 ACID 特性。 PostgreSQL 针对 ACID 的实现技术如下表所示。

 

表 1: 事务的 4 个特征 ACID 及响应的实现技术

ACID

实现技术

原子性

MVCC

一致性

约束(主键,外键等)

隔离性

MVCC

持久性

WAL

 
可以看到 PostgreSQL 中支撑 ACID 的主要是 MVCC 和 WAL 两项技术。 MVCC 和 WAL 是两个比较成熟的技术,通常的关系数据库中都有相应的实现,但每个数据库具体的实现方式又存在很大差异。下面介绍一下PostgreSQL中 MVCC 和 WAL 的基本实现原理。

 

1.  MVCC

MVCC(Multiversion Concurrency Control) 即多版本并发控制,它可以避免读写事务之间的互相阻塞,相比通常的封锁技术可极大的提高业务的并发性能。 PostgreSQL 中的 MVCC 实现原理可简单概括如下:

1 )数据文件中存放同一逻辑行的多个行版本(称为 Tuple )

2 )每个行版本的头部记录创建以及删除该行版本的事务的 ID (分别称为 xmin 和 xmax )

3 )每个事务的状态(运行中,中止或提交)记录在 pg_clog 文件中

4 )根据上面的数据并运用一定的规则每个事务只会看到一个特定的行版本

通过 MVCC 读写事务可以分别在不同的行版本上工作,因此能够在互不冲突的情况下并发执行。

 

图 1: 基于 MVCC 的数据更新举例



2.  WAL

当系统意外宕机后,恢复时需要回退未完成事务所做的更改并确保已提交事务所作的更改均已生效。在 PostgreSQL 中通过前面提到的 MVCC 很容易做到的第一点,只要把所有 pg_clog 文件中记录的所有“运行中”的事务的状态置为“中止”即可,这些事务在宕机时都没有结束。对于第二点,必须确保事务提交时修改已真正写入到永久存储中。但是直接刷新事务修改后的数据到磁盘是很费时的,为解决这个问题于是引入了 WAL(Write-Ahead Log) 。

WAL 的基本原理如下:

1 )更新数据页前先将更新内容记入 WAL 日志

2 )异步刷新数据 Buffer 的脏页和 WAL Buffer 到磁盘

3 ) Buffer 管理器确保绝不会先于对应的 WAL 记录刷新脏数据到磁盘

4 )事务提交时,将 WAL 日志同步刷新到磁盘

5 ) Checkpoint 发生时,将数据 Buffer 的所有脏页刷新到磁盘

   

图2:数据更新时的Buffer修改




图 3: 更新提交和 Checkpoint 时的磁盘同步


Q&A :

1 、 Q:PostgreSQL 中 DDL 支不支持事务?

A: 支持。 PostgreSQL 中对 DDL 的处理方式和普通的 DML 类似,也是支持事务的。

 

2 、  Q:PostgreSQL 中对 BLOB 数据的处理支不支持事务?

A: 支持。对 BLOB(bytea 或 large object) 数据的事务处理和普通数据的差别不大,但由于 BLOB 数据较大涉及 BLOB 的事务会产生很大的 WAL 日志文件。

 

3 、 Q:PostgreSQL 中很大的数据,比如 BLOB 如何在数据页面中存储?

A: 默认数据页面的大小是 8K ,当有很大数据时可能导致一个页面放不下整个数据行。针对这种情况, PostgreSQL 采取一种叫做 TOAST 的技术,对于比较大的列只在行中放一个类似指针的东西,完整的数据放在另一个单独的 TOAST 表中。在 TOAST 表中数据被切割成若干个 chunk, 每个 chunck 以一个数据行的形式存放。

 

4 、 Q:PostgreSQL 中可重复读和可串行化隔离级别都不会出现幻读那它们的区别是什么?

A:  根据 SQL 规约,能够回避幻读就已经满足了“可串行化”隔离级别的要求。但是 SQL 规约定义的“可串行化”并不是严格意义上的可串行化,仅仅能回避幻读不等于可以把并发执行的几个事务转化为几个事务严格按某个顺序先后执行   。 PostgreSQL 中的可重复读可以回避幻读但不是严格意义上的可串行化,但是可串行化就是。顺便说一下, Oracle 中的可串行化也不是严格意义上的可串行化,实际上它等价于 PostgreSQL 中的可重复读。

 

5 、 Q:PostgreSQL 中事务 ID 分配完了怎么办?

A: 从头开始重新分配(实际上从3开始重新分配,0,1,2已做为特殊用途,这称之为事务回卷)。但这样可能形成事务 ID 冲突的问题, PostgreSQL 中解决这个问题的措施有两个。第一,定期清理留在数据文件中的过老的事务 ID ,将它们统一设置为一个特殊值(2),在做事务 新旧 比较时,这个特殊的事务 ID 永远比其他普通的事务 ID 旧。这就保证了系统中事务 ID 的范围跨度不会过大。第二,在做事务 新旧 比较时不是简单的比较两个事务 ID 的算数值大小,而且考虑到了特殊事务ID和事务 回卷 的情况。比如根据内部的比较规则,无符号 INT 类型的事务 ID 0x00000005 比 0xFFFFFFFF新 。因为第一个措施已经保证了系统中事务 ID 间的跨度不会过大(不超过2^31),所以 0x00000005 一定是事务 ID回卷 后的结果而 0xFFFFFFFF 还没有发生回卷(或者说比 0x00000005 少回卷一次)。


来源:http://blog.chinaunix.net/uid-20726500-id-4040024.html

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31543044/viewspace-2637152/ ,如需转载,请注明出处,否则将追究法律责任。

上一篇: RU RUR
下一篇: 没有了~
请登录后发表评论 登录
全部评论

注册时间:2018-06-20

  • 博文量
    2
  • 访问量
    2906

最新文章