背景

书接上文,我们很好的理解了xmin和xid的区别。我们继续上文《KingbaseESV8R6不同隔离级下xmin的区别》来讨论 snapshot too old 的功能。

当kingbaseES中有事务长时间持有backend_xmin,就会通过参数old_snapshot_threshold把快照中的lsn和当前事务数据块中的lsn做对比判断快照是否过旧。

它并不关心是否存在backend_xid。

[](javascript:void(0)

test=# show old_snapshot_threshold ;
old_snapshot_threshold
------------------------
-1
(1 row) test=# alter system set old_snapshot_threshold= 1;
ALTER SYSTEM

[](javascript:void(0)

修改后重启数据库生效

第一种情况: 包含xmin,没有申请xid的只读事务

当持有xmin的query执行时间超过old_snapshot_threshold设置的阈值,并且读取到数据块的LSN大于快照存储的LSN时,报snapshot too old错误。

[](javascript:void(0)

test=# create table e1(id int);
CREATE TABLE
test=# insert into e1 select generate_series(1,10000);
INSERT 0 10000
test=# create index idx_e1 on e1(id);
CREATE INDEX session A:
test=# begin transaction isolation level repeatable read;
BEGIN
1号数据块的数据
test=# select ctid,* from e1 where id=2;
ctid | id
-------+----
(0,1) | 2
(1 row)
另一个数据块的数据
test=# select ctid,* from e1 where id=800;
ctid | id
--------+------
(3,122) | 800
(1 row) session B:
更新1号数据块的某条记录
test=# update e1 set id=0 where id=2 returning ctid,*;
ctid | id
---------+----
(44,57) | 0
(1 row)
UPDATE 1 1分钟后
session A:
访问未发生变化的数据块正常(因为id=1000走索引,所以不会扫描变更的数据块,这也是前面测试要建立索引的原因)
test=# select ctid,* from e1 where id=800;
ctid | id
--------+------
(3,122) | 800
(1 row)
访问发生变化的数据块, 报错snapshot too old
test=# select ctid,* from e1 where id=6;
ERROR: snapshot too old
test=# end;
ROLLBACK

[](javascript:void(0)

第二种情况:已申请xid的写,在隔离级别repeatable read/serializable事务,由于持有了xmin,并且repeatable read隔离级别,事务只要不结束,xmin不会变化。这种情况一样可能出现snapshot too old。

[](javascript:void(0)

session A:
test=# begin transaction isolation level repeatable read;
BEGIN
test=# insert into e1 values (1) returning ctid,*;
ctid | id
---------+----
(44,60) | 1
(1 row) session B:
修改10号数据块的记录,导致10号数据块LSN变大
test=# update e1 set id=1 where ctid::text ~ '^\(10,' returning ctid,*;
ctid | id
----------+----
(44,60) | 1
(44,61) | 1
(44,62) | 1
(44,63) | 1
......
UPDATE 226 1分钟后
session A:
访问变更的数据块,报错
test=# select * from e1 where ctid::text ~ '^\(10,';
ERROR: snapshot too old
test=# end;
ROLLBACK

[](javascript:void(0)

第三种情况:已申请xid的,在隔离级别read committed写事务,由于query开始时会重新生成快照,所以通常query持有的快照lsn大于或等于访问到的PAGE的LSN,则不会出现snapshot too old。因为这种情况不用去读取快照

[](javascript:void(0)

session A:
test=# begin transaction isolation level read committed;
BEGIN
test=# insert into e1 values (1) returning ctid,*;
ctid | id
----------+----
(46,1) | 1
(1 row) session B:
修改44号数据块的记录,导致44号数据块LSN变大
test=# update e1 set id=2 where ctid::text ~ '^\(44,' returning ctid,*;
ctid | id
----------+----
(45,60) | 2
(45,61) | 2
(45,62) | 2
(45,63) | 2
......
UPDATE 225 1分钟后
session A:
访问变更的数据块,不会报错
test=# select * from e1 where ctid::text ~ '^\(44,';
id
----
0
0
0
0
0
...... 但是如果QUERY本身访问时间长,并且访问到了快照创建以后被修改的页,还是会报错的。也就是访问到被修改的块的时候发现快照号lsn大于数据块lsn。这时候再去找以前的快照lsn已经发现超过1min过于旧。
模拟长SQL
session A:
with t as (select pg_sleep(100) ) select * from e1,t; 立即执行如下
session B:
test=# update e1 set id=7 where ctid::text ~ '^\(4,' returning ctid,*;
ctid | id
----------+----
(47,59) | 7
(47,60) | 7
(47,61) | 7
........
UPDATE 226
长SQL报错
session A:
ERROR: snapshot too old

[](javascript:void(0)

总结

哪些情况可能导致snapshot too old

包含了backend_xmin的事务,SQL的执行时间超过old_snapshot_threshold阈值,并且该SQL读取到了LSN超过快照存储的LSN的数据块时。

\1. snapshot too old报错通常出现在非常耗时的SQL,同时读取的数据块在不断的变化。当读取时间在10点,但10:03分另外的事务更改了查询中的某个数据块,这时候,查询进行到10:04分时候发现这个数据块中的lsn大于快照中的lsn,就要去快照中读取过去版本,这是为了保证一致性读,如果查询开始到这个时刻超过snapshot too old就会报snapshot too old报错。

\2. snapshot too old也可能出现在sys_dump备份数据库时,因为sys_dump使用的是repeatable read隔离级别,快照是在事务启动后的第一条SQL创建的,备份时间长的话,极有可能在备份过程中读取到LSN大于快照LSN的数据块,导致snapshot too old报错。

快照与隔离级别

  • 已提交读:在该事务的每条SQL执行之前都会重新获取一次快照
  • 可重复读和可串行化:该事务只在第一条SQL执行之前获取一次快照

最后我们比对理解oracle中undo机制和kingbaseES中的snapshot too old。

undo表空间的其中一个功能就是实现一致性读,当我在15:00开始查询,15:00的SCN号记录假设为100。那么在15:00这个时刻100就是最大的SCN,

这里需要引入一个ITL的概念,ITL全称为 Interested Transaction List,是Oracle中数据块的组成部分,用来记录在这个数据块上发生的所有事务,一个ITL可以记录一个事务不论这个事务是否已经提交,一个数据块可以有多个ITL。如果这个事务已经提交了那么这个ITL的位置就可以被反复使用了,因为ITL类似记录,所以,有的时候也叫ITL槽位。ITL槽中会记录对应undo块的地址。可以说上面记录的100SCN号在15:00的时候大于所有的数据块上ITL记录的SCN(多个ITL取最大SCN)

执行查询时,服务器进程扫描这个表中的数据块时,会把每个数据块ITL槽中最大的SCN与100进行比较,如果比100小则说明这个数据块没有被修改服务器进程直接进行数据读取即可。如果数据块ITL槽中的SCN大于100那么说明这个数据块在发起查询后被修改了,需要借助undo去获取15:00那个时刻数据块的数据。

根据上面的例子,我是在15:00开始的查询,而数据是在15:03的时候被修改(这里不用考虑有没有提交,因为ITL只要数据块被修改就会有记录,那么这个查询就会去读undo数据块)。我们假设这个被修改的数据块是n号数据块,修改后n号数据块的ITL中记录的SCN是120,当服务器进程扫描到这个数据块进行SCN比较时发现这个数据块的SCN要大于100,服务器进程就知道了这个数据块在发起查询后被修改了,于是服务器进程到n号数据块的头部找到120对应的ITL槽,然后找到对应undo块的位置。将undo块中所存放的n号块修改前的数据取出再结合n号块里的当前数据行进而构建15:00这个时间点未被修改的数据块,这个被新构建的数据块被称为CR块(Consistant Read)。然后服务器进程扫描这个块,得到15:00一致性的数据,返回正确的数据。这就是一致性读

因为我们的修改操作是delete,那么undo中对应的信息就是insert,insert将被删除的数据插入到CR块中,实现一致性读。undo记录的是buffer_cache中对应修改的前镜像,所以undo记录buffer修改的反向操作。

好了,我们把undo中记录的事务槽中scn号比作snapshot中的记录lsn号。结合案例3,第三种情况最符合oracle中的场景应用,因为我们数据库默认的隔离级别也是read committed。如果QUERY时间很长,也就是访问到被修改的块的时候发现快照号lsn大于数据块lsn。也就是相当于oracle中buffer_cache中数据块的scn大于undo中对应这条记录的scn,就需要读取前镜像,在我们数据库就需要读取snapshot。而snapshot保存多久靠old_snapshot_threshold这个参数设置,在oracle中undo表空间保留策略靠undo_retention参数,默认15分钟。

下文我们讨论垃圾回收受到参数old_snapshot_threshold参数的影响。

KingbaseESV8R6 snapshot too old的配置和测试的更多相关文章

  1. 四步完成NodeJS安装,配置和测试

    四步完成NodeJS安装,配置和测试 NodeJS 官网地址: http://nodejs.org/ 第一步:在官网点击 ’ INSTALL ’,下载相应的版本(我的机器是Win7专业版 64bit) ...

  2. WIN7环境下CUDA7.5的安装、配置和测试(Visual Studio 2010)

    以下基于"WIN7(64位)+Visual Studio 2010+CUDA7.5". 系统:WIN7,64位 开发平台:Visual Studio 2010 显卡:NVIDIA ...

  3. freeRadius 基础配置及测试

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...

  4. myBatis 基础测试 表关联关系配置 集合 测试

    myBatis 基础测试 表关联关系配置 集合 测试 测试myelipse项目源码 sql 下载 http://download.csdn.net/detail/liangrui1988/599388 ...

  5. ubuntu10.10 tftp安装,配置,测试

    ubuntu10.10 tftp安装,配置,测试 成于坚持,败于止步 虽然ubuntu/centos/redhat都是linux,但是内核其中存在一定的修改,所以对于tftp服务器的安装存在不同的命令 ...

  6. 大数据测试之hadoop集群配置和测试

    大数据测试之hadoop集群配置和测试   一.准备(所有节点都需要做):系统:Ubuntu12.04java版本:JDK1.7SSH(ubuntu自带)三台在同一ip段的机器,设置为静态IP机器分配 ...

  7. Oracle RAC 11g DG Broker配置和测试

    Oracle RAC 11g DG Broker配置和测试 之前在<RHEL6.4 + Oracle 11g DG测试环境快速搭建参考>已经简单说过. 本篇在实验环境中实际配置 环境: R ...

  8. Eclipse For JavaEE安装、配置、测试

    Eclipse For JavaEE安装.配置.测试(win7_64bit) 目录 1.概述 2.本文用到的工具 3.安装与配置 4.JavaSE开发测试(确保JDK已正确安装) 5.JavaEE开发 ...

  9. Genymotion安卓模拟器和VirtualBox虚拟机安装、配置、测试

    Genymotion安卓模拟器和VirtualBox虚拟机安装.配置.测试(win7_64bit) 目录 1.概述 2.本文用到的工具 3.VirtualBox虚拟机安装 4.Genymotion安卓 ...

随机推荐

  1. 从开发一款基于Vue技术栈的全栈热重载生产环境脚手架,我学到了什么

    浏览文章前 这一期,我分享给大家三点看源码的小技巧,这也是从别的大佬那总结的. 被反复使用的代码 这样的代码是一个软件的重点函数,一个大神的写法有很多精华值得学习. 穿越时间的代码 如果一段代码10年 ...

  2. VisonPro · 视觉定位工具包示例

    一.概述 视觉定位工具包一般包含: 1.相机取像: 2.图像九点标定: 3.Mark点粗定位: 4.建立粗定位坐标系: 5.Mark点精定位 6.输出Mark点坐标,角度等信息. 二.分类 1.单特征 ...

  3. 6G显卡显存不足出现CUDA Error:out of memory解决办法

    ​ 从6月初开始,6G显存的显卡开始出现CUDA Error:out of memory的问题,这是因为dag文件一直在增加,不过要增加到6G还需要最少两年的时间. 现在出现问题的原因是1.内核太古老 ...

  4. StringJoiner的使用

    1.添加字符串 add()方法 StringJoiner sj = new StringJoiner(","); sj.add("我爱你"); sj.add(& ...

  5. 基于Mybatis插件方式实现数据脱敏处理

    一.项目介绍 1.项目背景 有时候我们数据库中存储一些敏感的信息比如手机号.银行卡号,我们希望我们查询出来的的时候对一些敏感信息做一些脱敏处理. 当面项目是基于自定义Mybatis插件方式实现数据脱敏 ...

  6. Tomcat深入浅出——最终章(六)

    前言 利用了六天的时间,对Tomcat的内容进行了整理. 学习不易.整理也不易,自己坚持的更了下来,很不错. 希望每一位在努力前行的小伙伴,都要相信坚持就会有收获. 本次Tomcat就探寻到这里,明年 ...

  7. IP地址和端口号

    IP地址 IP地址:指互联网协议地址(Internet Protocol Address),俗称IP.IP地址用来给一个网络中的计算机设备做唯一的编号.加入我们吧"个人电脑"比作一 ...

  8. @Convert 注解在jpa中进行查询的注意事项

    如果要实现实体类中属性的类型和数据库表中字段的类型相互转化,则需要使用 @Convert 注解 package javax.persistence; import java.lang.annotati ...

  9. mysql like 命中索引

    反向索引案例:CREATE TABLE my_tab(x VARCHAR2(20)); INSERT INTO my_tab VALUES('abcde'); COMMIT; CREATE INDEX ...

  10. for(int i=0;i<1000;i++)与 for(int i=1;i<=1000;i++)。 if ( i%500){}//前者表示0-501一个循环,后者1-500一个循环

    `package com.Itbz; import java.sql.Connection; import java.sql.PreparedStatement; /** 向mysql数据库批量添加数 ...