论Postgres的“已提交的而且 xmin’比当前事务的XID小的记录对当前事务才是可见的”

1.阐述

最近在网上看到这样一句话Postgres“已提交的而且 xmin 比当前事务的XID小的记录对当前事务才是可见的”。先不评断这句话的正确性;看下这句话的结构,因果关系;

按照此话的意思;要postgres中的数据可见必须满足两个必要条件:

  1. 事务已经提交(commit);
  2. 提交时插入记录的xmin 小于 当前current_txid(事务id)。

而网上对这句话的解释:“这意味着,你可以开始一个新事务然后插入一行记录,直到你提交(COMMIT)之前,你插入的这行记录对其他事务永远都是不可见的。等到提交以后,其他后创建的新事务就可以看到这行新记录了,因为他们满足了 xmin < XID 条件,而且创建哪一行记录的事务也已经完成”。看起来挺合理的,无懈可击似的。接下来我们来推敲推敲。要说记录的可见性;这还得从事务的隔离级别说起。

2. 举例验证

根据《PostgreSQL9.4.4-CN-v1.0.pdf》文档介绍: SQL标准定义了四个级别的事务隔离 { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED }; postgres目前只实现了 {SERIALIZABLE | REPEATABLE READ | READ COMMITTED }这三种。详细大家去看文档;这里不做介绍。

  • 事务隔离级别READ COMMITTED

事务隔离级别:读已提交(READ COMMITTED)这是postgres,greenplum默认的事务隔离级别。若从先事务隔离级别(读已提交)来解释:就是读已经提交的记录;是不是这样呢? 来验证下。

--session A  事务id为1844;
postgres=# begin;
BEGIN
postgres=# select txid_current();
 txid_current
--------------
         1844

--session B 事务id为1845;并在插入一条记录在lottu05表(未提交)
postgres=# begin;
BEGIN
postgres=# select txid_current();
 txid_current
--------------
         1845

postgres=# insert into lottu05 values (1001,'lottu');
INSERT 0 1

--在session A/B查看记录; session A读不到记录; session B可以读到记录。
postgres=# select * from lottu05;
 id | name
----+------
(0 rows)

--在session B提交插入的记录;在查看session A是否可以看到记录。
postgres=# select xmin,* from lottu05;
 xmin |  id  | name
------+------+-------
 1845 | 1001 | lottu
--表明session A(当前事务为ID:1844)可以读 插入记录事务id为1845 已经提交的记录。
--总结: 事务隔离级别为读已提交(READ COMMITTED)就是读已经提交的记录。
由此可见,对读已提交隔离级别而言"已提交的而且 xmin’比当前事务的XID小的记录对当前事务才是可见的"是不正确的。
而网上的解释:也是必要不充分条件。那该如何诠释这说话呢?请看下文讲解
是根据当前postgres系统的当前事务ID相比;目前系统下一个事务ID为1846
-- 我们现在看下当前postgres系统 下一个事务id
[postgres@localhost ~]$ pg_controldata |grep  NextXID
Latest checkpoint's NextXID:          0/1846
--意思是说这条记录后面开启会话从事务id:1846是可见的。不充分的是事务ID:1844也可以读到该记录。
--然而这句话来源何处;我想是有依据的。接下来我们做一个实验。模拟postgrs穿越到过去。 

--session C 现在插入1002-1008条记录;结果如下:
postgres=# select xmin,id,name from lottu05;
 xmin |  id  |  name
------+------+---------
 1845 | 1001 | lottu
 1846 | 1002 | lottu02
 1847 | 1003 | lottu03
 1848 | 1004 | lottu04
 1849 | 1005 | lottu05
 1850 | 1006 | lottu06
 1851 | 1007 | lottu07
 1852 | 1008 | lottu08   

--我们现在使用将数据库postgres回到 txid 为1849。注意:该动作不建议操作;
[postgres@localhost ~]$ pg_stop
waiting for server to shut down.......... done
server stopped
[postgres@localhost ~]$ pg_resetxlog -x 1849 $PGDATA
Transaction log reset
[postgres@localhost ~]$ pg_start
server starting
[postgres@localhost ~]$ psql
psql (9.5.0)
Type "help" for help.

postgres=# select xmin,id,name from lottu05;
 xmin |  id  |  name
------+------+---------
 1845 | 1001 | lottu
 1846 | 1002 | lottu02
 1847 | 1003 | lottu03
 1848 | 1004 | lottu04
 1849 | 1005 | lottu05
--可以看到上面的xmin:(1850-1852)是不可见的。
--等数据库的事务ID超过1852;这些数据可以展示出来。
postgres=# select txid_current();
 txid_current
--------------
         1850

postgres=# select txid_current();
 txid_current
--------------
         1851

postgres=# select txid_current();
 txid_current
--------------
         1852

postgres=# select xmin,id,name from lottu05;
 xmin |  id  |  name
------+------+---------
 1845 | 1001 | lottu
 1846 | 1002 | lottu02
 1847 | 1003 | lottu03
 1848 | 1004 | lottu04
 1849 | 1005 | lottu05
 1850 | 1006 | lottu06
 1851 | 1007 | lottu07
 1852 | 1008 | lottu08 

--从这个实验看来 确实是需要满足网上所说的两个条件。上面也提过;该操作不建议操作。设想;当前时代若可以穿越到历史上各个时代;那历史不乱套了吗?同理如此。
所以说对隔离级别为READ COMMITTED而言;如同它字面解释一样;只要记录COMMITTED;就可以读到。
 注意:
--1.该操作不等同 oracle的flashback操作;虽然回到了历史;历史上已经发生的还是会发生。
--2.该操作并不能做数据恢复操作。若对数据做删除进行恢复;可以参考--http://www.cnblogs.com/lottu/p/5761885.html  

总结:对隔离级别为READ COMMITTED而言;如同它字面解释一样;只要记录COMMITTED;就可以读到

  • 事务隔离级别:REPEATABLE READ

事务隔离级别:REPEATABLE READ;是不是如同它而言呢?接下来拭目以待吧。

--开启SESSION A; ctid为1857。
postgres=# truncate table lottu05;
TRUNCATE TABLE
postgres=# begin;
BEGIN
postgres=# select txid_current();
 txid_current
--------------
         1857

--开启session B;隔离级别为REPEATABLE READ。事务id为:1858
postgres=# begin ISOLATION LEVEL REPEATABLE READ;
BEGIN
postgres=# select txid_current();
 txid_current
--------------
         1858  

--在session A插入 10条记录并提交
postgres=# insert into lottu05 select generate_series(1001,1010),'lottu'||generate_series(1,10);
INSERT 0 10
postgres=# commit;
COMMIT

--在session B查看是否可以读到记录
postgres=# select * from lottu05;
 id | name
----+------
(0 rows)       

--结果表明session B 读不到 已经提交且 事务ID:1857比session B的事务ID为1858要小的记录。

3.总结

对Postgres记录的可见性;对网上这句话“已提交的而且 xmin 比当前事务的XID小的记录对当前事务才是可见的”可以修正为“已提交的而且 xmin 比当前系统事务的XID小或者等于的记录对当前事务才是可见的”。而对它的解释(这意味着,你可以开始一个新事务然后插入一行记录,直到你提交(COMMIT)之前,你插入的这行记录对其他事务永远都是不可见的。等到提交以后,其他后创建的新事务就可以看到这行新记录了,因为他们满足了 xmin < XID 条件,而且创建哪一行记录的事务也已经完成”)是充分不必要;

--参考文献

http://blog.163.com/digoal@126/blog/static/163877040201183043153622/

http://www.cnblogs.com/lottu/p/5761885.html

时间: 2024-09-09 12:55:48

论Postgres的“已提交的而且 xmin’比当前事务的XID小的记录对当前事务才是可见的”的相关文章

SQL Server误区:CheckPoint只会将已提交的事务写入磁盘

误区 #15:CheckPoint只会将已提交的事务写入磁盘 错误 这个误区是由于太多人对日志和恢复系统缺少全面的了解而存在已久.CheckPoint会将自上次CheckPoint以来所有在内存中改变的页写回磁盘(译者注:也就是脏页),或是在上一个CheckPoint读入内存的脏页写入磁盘.无论事务是否已经提交,其所影响的页都会在Checkpoint时写回磁盘.但对于TempDB来说例外,因为TempDB的Checkpoint的事件周期中并不包含将脏页写回磁盘的步骤. 如果你想了解更多,请阅读下

ajax-使用$.post,数据已提交,但回调函数不执行

问题描述 使用$.post,数据已提交,但回调函数不执行 我用$.post希望实现异步提交的功能,代码如下: $.post(addURL, {pid : id}, function (data) { alert("回调函数"); alert(data["status"]); }, "json") .success(function () {alert("success");}) .error(function () {aler

SQL Server误区30日谈 第15天 CheckPoint只会将已提交的事务写入磁盘

误区 #15:CheckPoint只会将已提交的事务写入磁盘 错误 这个误区是由于太多人对日志和恢复系统缺少全面的了解而存在已久.CheckPoint会将自上次CheckPoint以来所有在内存中改变的页写回磁盘(译者注:也就是脏页),或是在上一个CheckPoint读入内存的脏页写入磁盘.无论事务是否已经提交,其所影响的页都会在Checkpoint时写回磁盘.但对于TempDB来说例外,因为TempDB的Checkpoint的事件周期中并不包含将脏页写回磁盘的步骤. 如果你想了解更多,请阅读下

兴称美团网已发布Android版手机客户端同时iPhone版本已提交

3月4日消息(记者 尚婧)3月4日,团购网站美团网CEO王兴在网站上线一周年发布会上表示,预计2011年美团网将开团超过300个城市,年销售额达到16亿.同时将用5000万人民币收购国内超过50家团购网站. 美团网于2010年3月4日上线,一年来美团网总销售额2.3亿元,为用户节省8.4亿元,商品平均折扣为2折.平均营收月复合增长率71%,目前注册用户量为700万.王兴介绍,目前美团网在全国开城53个,每日页面访问量750万,累积参与消费用户量超过600万. "我们下一步会和手机结合的非常完美&

git学习------&amp;gt;如何修改git已提交的记录中的Author和Email?

一.背景 最近搭建好GitLab后,准备陆陆续续的将之前在SVN仓库中保存的代码迁移到GitLab上,昨天顺利将三个Android组件的代码迁移到GitLab后,其他同事发现迁移是成功了,但是pull下来命令后查看git log 发现所有人的有些都配置成了我的邮箱,尴尬啊. GitLab上面全部变成了我的提交记录,尴尬. 二.原因分析 下面具体分析下为什么产生这个的原因. 具体原因是因为再做SVN–>Git迁移准备的时候,第一步要建议SVN用户到Git用户的映射文件.而这个映射文件最终我将所有用

台积电已提交文件申请参股中芯国际10%

北京时间3月29日早间消息,据国外媒体今日报道,台积电已向台湾当局提交文件申请参股中芯国际,取得10%的股权,作为后者就商业机密剽窃案进行的补偿. 台积电此前起诉中芯国际使用其65项商业机密,去年底双方达成国际和解协议,除了现金赔偿之外,中芯将授予台积电8%的中芯股权,台积电可在3年内以每股1.3港元认购2%的中芯股权,未来台积电将持有中芯国际10%的股份,成为后者一大股东. 自台积电起诉中芯国际以后,双方曾历经九周的当庭对抗,法院于去年11月判定台积电胜诉. 台湾当局曾一度禁止台科技企业投资大

SQL Server 已提交读快照 测试

原文:SQL Server 已提交读快照 测试 1. 打开数据库 已提交读快照 选项   2. 数据库 已提交读快照 模式下的测试   a) 测试表 Test   b) 开启事务1,更新数据C2 = '200'(未提交) BEGIN TRAN UPDATE Test SET C2 = '200' WHERE C1 = 'A' -- COMMIT   c) 查询数据(查询没有被阻塞,C2 = '100') SELECT * FROM Test   d) 开启事务2,更新数据C2 = '300'(未

本人为巨杉数据库(开源NoSQL)写的C#驱动,支持Linq,全部开源,已提交github

一.关于NoSQL的项目需求      这些年在做AgileEAS.NET SOA 中间件平台的推广.技术咨询服务过程之中,特别是针对我们最熟悉的医疗行业应用之中,针对大数据分析,大并发性能的需求,我们也在慢慢的引用NoSQL技术来满足数据分析与性能等多方面的需要,也进一步完善我们的SOA基石架构风格:      在早些年,对NoSQL不是很了解这前,后端数据存储都是存储的单一的关系数据库之上,但是在很多时间,这并不是最优的,比如在医疗用户之中针对一个病人的相关数据展示,及相关性分析,关于数据库

雅虎已提交竞购方案

摘要: 上周董事会刚刚被批准了11亿美元收购轻博客Tumblr的交易,雅虎又加入视频网站Hulu的竞购战局.但这次雅虎至少面临6位实力派对手,其中包括时代华纳有限公司.私募公司KKR Co.(下称 上周董事会刚刚被批准了11亿美元收购轻博客Tumblr的交易,雅虎又加入视频网站Hulu的竞购"战局".但这次雅虎至少面临6位实力派对手,其中包括时代华纳有限公司.私募公司KKR &Co.(下称"KKR").银湖等. 目前,Hulu还没有进入正式并购流程,它只是要