PostgreSQL
中
的
MVCC
概
述
为什么
需
要
MVCC?
并
发
读
写
在
数据
的
并
发
读
写
过
程
中
,
由
于
写入
并
不
是
原
子
性
的
,
因
此
当
一个
线
程
正
在
写
时
,
如
果
另
一个
线
程
进
行读
操
作
的
话
就
很
有
可
能
产
生
数据
不一
致
的
问题
比
如
数据
的
前
半
部
分写入
了
,
但
是
后半
部
分
尚
未
写入
,
那
么
在
读
取
时
就
会
取
到
中
间
值
,
也
就
是
脏
数据
,
典
型
案
例
就
是
64
位
整
型
的
写入
将
会
分
为
两
次
写入
虽
然
可
以使
用
读
写
锁
来
解
决
并
发
读
写
的
问题
,
但
是
会
导
致
数据
库
的
并
发
性
能
降
低
,
并
且
对
于
绝
大多
数
应
用
而
言
,
都
是
读
多
写
少
的
,
每
一个
更
新操
作
都
会
阻
塞
读
取
操
作
,
这
是
我
们
不
能
接
受
的
并
发
控
制
手
段
悲
观
并
发
控
制
即
严
格
的
两
阶
段
锁
(
S2PL
),
语
句
执
行
时
获
取
锁
,
事
务
结
束
后
释
放
锁
乐
观
并
发
控
制
尝
试
进
行
更
新
,
若
更
新
失
败
则
重
试
多
版
本
并
发
控
制
(
MVCC
)
每
一个
写
操
作
都
会
创
建
一个
新
版
本
的
数据
项
,
并
保
留
其
旧
版
本
,
当
事
务
读
取
对
象
时
选
择
一个
合
适
的
版
本
,
已
确
保
各
个
事
务
之
间隔
离
性
的
正
确
性
实
现
方
式
写入
数据
时
将
旧数据
迁
移
到
另
一个
地
方
例
如
MySQL
中
的
回
滚
段
(
undolog
),
其
他
线
程
在
读
取
改
行
数据
时
,
从
回
滚
段
中
将
旧数据
读
出
来
直
接
将
新数据插
入到
相
关
表
页
中
在
同
一个
存
储
区
域
中保
存
数据
的
多
个
版
本
Tuple
结
构
事
务
ID
PostgreSQL
使
用
了
一个
32
位
无
符
号
自
增
整数
来
作为事
务
标
识
以
比
较
新旧
程
度
可
以
通过
`txid_current()`
函
数
来
获
取
当
前
事
务
的
标
识
selecttxid_current();
HeapTupleHeaderData
上
图
为
一
条
数据
(
元
组
)
在
磁
盘
中
的
实
际
存
储
结
构
,与
MVCC
相
关
的
字
段
主
要
包
括
4
个
t_xmin
保
存
了
插
入
该
元
组
的
事
务
的
txid
t_xmax
保
存
删
除
或
者
是更
新
该
元
组
的
事
务
的
txid
,
若
一个
tuple
既
没
有
被
更
新
也
没
有
被
删
除
的
话
,
该
字
段
的
值
为
0
t_cid
即
CommandID
,
表
示
在
当
前
事
务
中
,
执
行
当
前
命
令之
前共
执
行
了
多
少
条
命
令
,
从
0
开
始
计
数
。
t_cid
的
主
要
作
用
就
在
于
判
断
游
标
的
数据
可
见
性
t_infomask
位
掩
码
,
主
要
保
存
了事
务
执
行
的
状
态
,
如
XMIN_COMMITTED
、
XMAX_COMMITTED
等
。
同
时
也保
存
了
COMBOCID
这
一
非
常
重
要
的
标
识
位
,
也
是
和
游
标
相
关
的
字
段
插
入
t_xmin
与
创
建
相
关
,
当
我
们
insert
一
条
数据
时
,
t_xmin
就
会
被设
置
成执
行
事
务
的
txid
,
并
且一
旦
设
置
,
便
不
会修
改
删
除
t_xmax
与
删
除
有
关
,
当
我
们
删
除
一
条
数据
时
,
t_xmax
就
会
被设
置
成执
行
事
务
的
txid
更
新
在
PostgresSQL
中
,
元
组
的
更
新
并
不
是
原
地
的
,
也
就
是
说
新数据
不
会
覆
盖
旧
有
的
数据
,
而
是
通过
将
旧数据
标
记
为
删
除
,
新插
入
一
条
数据
的
方
式
来
完
成
更
新
。
也
就
是
说
,
假
如
说
我
们
对
100
条
数据
进
行
更
新
的
话
,
最
终
会
在
文
件中产
生
200
条
数据
,
其
中
有
100
条
被
标
记
为
删
除
事
务
快
照
与
基
本
可
见
性
判
断
事
务
快
照
事
务
快
照
是
一个
数据
集
合
,
保
存
了
某
个
事
务
在
某
个
特
定
时
间
点
所
看
到
的
事
务
状
态
信
息
,
包
括
哪
些事
务
已
经结
束
,
哪
些事
务
正
在
进
行
,
以
及
哪
些事
务
还
未
开
始
,
我
们
可
以
通过
txid_current_snapshot()
函
数
来
获
取
当
前
的
事
务
快
照
txid_current_snapshot()
的
文
本
表
示
含
义为
xmin:xmax:xip_list
,
其
中
xmin
表
示
所
有
小
于
它
的
事
务
要
么
已
提
交
,
要
么
已
经
回
滚
,
即
事
务
结
束
。
xmax
则
表
示第
一个
尚
未
分
配
的
txid
,
即
所
有
txid>=xmax
的
事
务
都还
没
有
开
始
。
而
xip_list
则
是
使
用
逗
号
分割
的
一
组
txid
,
表
示
在
获
取
快
照
时
还
是
进
行
的
事
务
基
本
可
见
性
判
断
(
排
除
游
标
)
可参
考
:https://smartkeyerror.com/PostgreSQL-MVCC-01
评论0