问题描述

20231127上午客户反馈绩效系统20231125、20231126出现2次YAS-02020 snapshot too old的问题,测试也有类似问题。

该过程是客户新增的存储过程,目的是通过PRO_RUN_JOB作为主控,调度其他存储过程,后续不用其他调度引擎。

原因分析

错误信息收集分析

分析存储过程报错日志,核查UNDO_RETENTION、undo表空间

看了相应的优化建议,可以增大参数UNDO_RETENTION的值,或者使用更大的undo表空间。

客户环境目前UNDO_RETENTION配置了600,该参数单位是秒。临时修改客户测试环境的配置为3000,试图规避问题。

正常理解,MVCC用于高并发的情形,会出现该错误,而该存储过程执行是串行的,不符合预期!需要继续分析。

UNDO、MVCC机制分析

了解背后机制,snapshot too old是由于db需要做多版本控制(mvcc),在数据commit之后,仍然会保留undo一段时间,在超过这段时间之后undo的空间会被复用,如果需要还原的数据超过了这个时间,则还原不了,触发该错误。

崖山db快照隔离级别的核心就是MVCC(Multi-Version Concurrency Control),多版本并发控制

快照本质上就是一个时间点。记录版本的时间点为事务提交的时间点。

可见性可分为2类情况:

1、事务内的语句可见性

2、事务间的可见性

由于老版本保留时间的限制,我们可能无法读取到某些很老的版本,这时就会有snapshot too old错误。

事务功能梳理 - YashanDB

可以确认:

  • 不同事务间,特别是长查询,容易出现该问题;

  • 另一个是专门的快照读,如Oracle的快照读select count(*) from tableA as of timestamp to_timestamp('2013-10-16 08:46:57','yyyy-mm-dd hh24:mi:ss');

疑点一

分析测试环境出现过类似的问题,看到报错的时间点:

2023/11/23 13:21:52执行的是PRO_DAILY_DPSIT

2023/11/23 12:04:00执行的是PRO_SYS_USER_POST_REL

有个共同点:

PRO_SYS_USER_POST_REL用的是merge,同时读和写同个表

PRO_DAILY_DPSIT用的是insert into select,insert 和select的表有相同的

开始怀疑这里有并发机制,读写自同个表,但是作为同个事务内的,undo不应该被释放掉,不符合预期!

确认问题

剩下的就是长查询的可能。只有在查询的时候才会报这个错误,update的时候是不会报这个错误的。

继续分析游标loop的结果,如果在游标读取的时候报错,则remark也是:更新跑数任务明细表:单个任务成功结束的相关信息

fetch在一开始就拿到scn(SCN即系统改变号(System Change Number)),每次fetch都用的open时的scn,由于loop过程中还是update RUN_JOB_DETA表更新了db存储的某一个block,commit之后undo的数据会保留undo_retention的时间,当超过这个时间undo的空间会别其他任务复用。

而一个block不止一条数据,在后续loop的过程,如果继续读取到这个block的数据,需要对这个block还原到scn对应的状态再读取,由于undo已经被复用,就会报snapshot too old的错误。

undo机制、MVCC机制,在Oracle、DB2中都是有的,该问题也会存在。崖山的数据块不会存2个表的数据,可以使用下面方法规避:

PRO_RUN_JOB这个存储过程使用游标读取RUN_JOB_DETA表做为配置表,loop过程中需要更新的结果数据放到历史表(主要更新任务状态,开始、结束时间,耗时),配置表和历史结果分开存储,彻底解决问题。

经验教训

  • Undo机制中,undo_retention是一个不容易理解的参数项。设置之后,Oracle会根据自动undo管理的原则进行调节,进行空间拓展,来适应实现用户的期间要求。而崖山db需要根据实际的业务频繁度和数量量、以及undo表空间设置情况进行综合评估。

  • 存储过程存在游标遍历,需要注意更新目标表不是fetch的表,否则存在类似问题。

【YashanDB知识库】存储过程报错snapshot too old的更多相关文章

  1. TFDStoredProc执行sql server的部分存储过程报错,有的是好的。

    TFDStoredProc执行sql server的部分存储过程报错,有的是好的. Invalid character value for cast specification 暂时无解.用fdque ...

  2. Mybatis调用存储过程报错

    Mybatis调用存储过程 贴码 123456 Error querying database. Cause: java.sql.SQLException: User does not have ac ...

  3. mysql 创建存储过程报错

    在创建存储过程前把结束符定义为 delimiter // 然后再创建就不会报错

  4. C# 调用存储过程 Sql Server存储过程 存储过程报错,程序中的try

    C#程序调用Sql Server存储过程,存储过程中报错情况,返回值... 0.SQL存储过程 USE [Opos] GO /****** Object: StoredProcedure [dbo]. ...

  5. java 执行mysql 8.0.11存储过程报错The user specified as a definer ('root'@'10.%.%.%') does not exist解决办法

    执行存储过程,报错 java.sql.SQLException: The user specified as a definer ('root'@'10.%.%.%') does not exist ...

  6. 执行存储过程报错——ora-01031:权限不足

    1. 执行DDL报错 在oracle存储过程中,默认是可以直接执行DML和DQL的,但是执行CREATE这种的DDL则需要借助EXECUTE IMMEDIATE ···了,如下备份表语句 --抄表表备 ...

  7. 在mybatis中使用存储过程报错java.sql.SQLException: ORA-06550: 第 1 行, 第 7 列: PLS-00905: 对象 USER1.HELLO_TEST 无效 ORA-06550: 第 1 行, 第 7 列:

    hello_test是我的存储过程的名字,在mapper.xml文件中是这么写的 <select id="getPageByProcedure" statementType= ...

  8. navicat创建存储过程报错

    搞了半天这个恶心的报错,最后发现竟然是存储过程的一个varchar类型的参数没给长度,如varchar(64)长度必须指定不然就会报错: mark一记

  9. Oracle执行存储过程报错——ora-01031:权限不足

    执行DDL报错 在oracle存储过程中,默认是可以直接执行DML和DQL的,但是执行CREATE这种的DDL则需要借助EXECUTE IMMEDIATE 如: create or replace p ...

  10. PHP多次调用Mysql存储过程报错解决办法

    PHP多次调用Mysql数据库的存储过程会出现问题,主要问题为存储过程中执行多次SQL语句不能一一释放导致的,网上找了一些解决办法,比如使用 multi_query 然后一个一个释放,但是发现根本不适 ...

随机推荐

  1. 能说下 vue-router 中常用的 hash 和 history 路由模式实现原理吗?

    这个router有两种模式:hash模式(默认).history模式(需配置mode: 'history') 然后,我们来研究下两者的原理: 我们先来认识下这位朋友#,这个#就是hash符号,中文名哈 ...

  2. C#计算两个日期的天数

    private int DateDiff(DateTime dateStart, DateTime dateEnd) { DateTime start = Convert.ToDateTime(dat ...

  3. 一套基于 Ant Design 和 Blazor 的开源企业级组件库

    前言 今天大姚给大家分享一套基于Ant Design和Blazor的开源(MIT License).免费的企业级组件库(喜欢Ant Design风格的同学推荐使用):Ant Design Blazor ...

  4. thinkphp5 关于跨域的一些坑

    1.首先在tp5的入口文件:public/index.php 在里面添加三行: // [ 应用入口文件 ] header("Access-Control-Allow-Origin:*&quo ...

  5. [oeasy]python0010_怎么用命令行保存文件

    编写 py 文件 回忆上次内容 上次 真的输出了 程序员的浪漫 Hello world!   print函数 可以输出 字符串 但是 print这个词 别拼错 就连 大小写 也别能错 错了就改 也没事 ...

  6. PHP 程序员为什么依然是外包公司的香饽饽?

    大家好,我是码农先森. PHP 唯一的爽点就是开发起来「哇真快」这刚好和外包公司的需求相契合,在 Web 领域的芒荒年代 PHP 以王者姿态傲视群雄.如果 PHP 敢说第二,就没有哪门子语言敢称第一, ...

  7. 学习笔记--Java方法基础

    Java方法基础 那么什么是方法呢? public class MethodTest01{ public static void main(String[] args){ // 需求1:编写程序计算 ...

  8. Pandas库学习笔记(5)---Pandas Panel

    Pandas Panel Pandas Panel基本操作 Panel数据3D容器. 术语 Panel data 源自计量经济学,名称来之于pandas − pan(el)-da(ta)-s. 3个轴 ...

  9. docker cmd和entrypoint

    FROM scratch 很多镜像都是从他开始 创建自己的centos FROM centos 基于官方的centos开始写 构建自己的centos [root@docker dockerfile]# ...

  10. UDP协议测试

    UDP协议测试 我们一般想到测试连通性时第一考虑到的就是使用ping命令. 但是我们知道ping命令使用的是icmp协议,属于tcp/ip协议中的一个子协议,所以我们可以用ping或tcping命令来 ...