高并发控制肯定是数据必须达到的一个标准, 在并发操作中,对于同一个数据,同时读和写的两个回话有可能产生不一致,所以出现了在高并发情况下如何保持性能又保持一致出现了MVCC,多版本并发
实现MVCC的方法有两种:
1)写数据时,将旧数据移到一个单独的地方,比如回滚段中,从回滚段把旧数据读回来
2)写数据时,旧数据不删除,而是插入新数据,旧数据写文件。
MySQL,Oracle基本上是通过第一种方式操作,而PostGres则通过第二种操作,
针对第一种来说第二种的劣势:旧版本的数据块需要清理,旧版本的数据因为在文件中,访问可能会造成I/O及扫描更多的数据块,
优势:数据可以进行很多更新,不必担心没有回滚段或者回滚段装不下数据,
事物回滚可以立即完成,无论事物进行了多少操作,
针对多版本并发介绍几个要的术语
表中的隐含字段
oid tableoid ctid xmin xmax cmin cmax 后四个字段实现控制数据行是否对用户可见
事物ID回卷问题
Postgres的事物ID 0 代表无效 1 初始化 2 代表冻结 3才是正式开始的事物ID值,
pg的id值一直从3一直增加 达到4字节整数的最大值,然后再回头从3开始,pg比较新旧事物到底是前还是后,通过事物id值来看,如果现在达到最大值,那么比价9》3 他就认为9是最新的事物ID,其实这是有问题的,为了解决这个问题,pg规定两个事物id差的最大值不得超过2的31次幂,这样就不会产生回卷问题,比如(int32(id1-id2))<0 这个结果id1=9 id2=3 肯定成功,但是id1=3 id2= 9肯定就是负数不成功,
pg物理存储术语
Relation 表示表或者索引
Tuple表示行即MYSQL中的ROW 记录了版本控制的几个值,
Page 表示磁盘中的数据块
Buffer表示内存中的数据块
数据块默认8k最大32k,
数据块的空闲空间的管理
如果一个数据更新删除插入,肯定会缠上旧版本的数据,那么在数据块就会产生空闲的空间,那么这些空闲的空间如何回收利用,比如插入一个数据是如何选择空间的空间块的,
首先记录每个数据块空闲空间的大小,实现快速的查找合适的空闲空间块,每个表都会有oid,如果某个oid出现了空闲的空间块,那么就会产生表oid_fsm文件,这个文件就是记录了空闲块的信息
可见性映射表文件
Tuple更新之后,数据块不会马上清理掉,而是需要等待vacuum命令是清理,而_vm的文件就是记录了哪些需要清理,方便进程清理的时候只需要扫描这个表即可,另外一个就是该表记录的是行对全部事物是否可见,还是行对部分事物可见,
这里根据上面的可见性映射表文件引出一个Index-only-scans技术,就是因为此文件记录的是事物的可见性,所以根据此表判断从索引取回的数据是否对当前事物可见,就不需要再去访问表中的行了,个人理解这个就是不去扫描表了,直接扫描了这个_vm表,有待考究
另一个新技术HOT技术
更新后的新行与旧行在同一个数据块内,旧行会有一个指针,指向新行,这就不必更新索引了,这里涉及一个填充因子,好像是控制这个是不是要指向新的一个指针,