29、undo_2_1(事务槽、延迟块清除、构造CR块、ora-01555)
事务槽(不同于事务表里面的槽位(这个事务槽在数据块的头部))
图解:
一个事务开始,要做的事情:
第一,事务表里面找槽位(undo段的段头块里有事务表,事务表有槽位,每一个槽位记录一个事务);
事务表里的槽位里记录的信息有:
1、xid(事务ID):(undo段的段号,段里面的第几个槽(槽号),覆盖数);
2、cflag(commit flag):提交标志;
3、SCN号(提交SCN号);
4、dba(数据块地址):指向事务使用的最后一个块;
第二,做DML操作,要修改某个数据块里面的一个数据行,在修改数据行以前,oracle会做一件事情:对于普通数据块来讲,在数据块的头部默认有两个事务槽,最多可以有255个。
事务槽里面含有的信息:
1、xid;
2、uba(undo block adress):undo块地址;
3、提交标志;
4、SCN号;
事务开始了,要修改数据块,必须先获取到数据块里面的事务槽;假设0号事务槽里面没有未提交事务(就是没有active事务槽的时候),这个事务槽就可以被覆盖;要修改多行数据的时候,用一个事务槽就可以了;然后将事务信息写入事务槽;
现在要修改数据行了,会在数据行的头部写入一个数字(比如:0(事务槽的槽号)),表示在数据行上加了一个锁(也就是说这个数据行正在被0号事务槽里面所对应的事务修改),然后指向0号事务槽,然后事务槽里面的xid指向这个事务的事务源;同一个事务可以修改数据块里面的多行数据(这里修改了3行数据),都指向了同一个事务;另外还修改了另外一个数据块,然后也指向同一个事务源(一个事务可以同时修改多个数据块);
关于事务的提交标志,在很多地方有,比如:在每一个数据块的事务槽里面有提交标志,在事务表里面的槽位里面有提交标志,并且都有SCN号;
现在描述一个场景:
假设,一个事务修改了100W个块,然后要commit提交;要提交的时候oracle会做几件事情:
1、清锁:需要把100W个块里面的每个数据行前面的锁标记清除了;
2、清理数据块的事务槽:就是把事务槽里面的信息清除了;
这两个清理的会很慢(非常消耗资源),因为涉及到100W个块;
3、清理undo段里面的事务表;
这个清理的比较快(不消耗资源);
用户提交的时候,希望马上提交成功,但是提交的时候第一和第二件事情很慢,很消耗资源,所以oracle在提交的时候,只清除事务表里面的信息(这个是必须要做的事情),记下提交时候的SCN号,然后第一和第二件事情oracle也会尽量的去做一些(比如,现在是100W个块,然后呢,只修改1000个块),意思意思;
事务表里面的清了,数据块里面的事务槽还没有清理完,然后oracle下次再访问块的时候,假设读到之前修改的一行数据时,发现上面有锁标记,表示上面有活动的事务,然后找事务槽里面的事务,显示事务没有提交,这时候再到事务表里面找对应的事务,但是已经显示提交了,oracle就知道当时提交的时候,数据块里的事务槽没清理,所以oracle下次再访问块的时候就顺便清了,把锁标记清了,事务槽里面的信息清了,清理完之后就接着访问
快速提交
所以,只要事务表里面的信息清了,数据块里面的信息有没有清没关系;oracle里,在提交的时候,把事务表里面的信息清了,其他的地方意思意思的清理一下,这种提交机制叫做:快速提交
延迟块清除
然后呢,再读到那个块的时候,顺便清了,然后修改数据块,修改数据块就要修改锁标记,也要修改事务槽里面的提交标记(修改为未提交),还有修改SCN号(改为null),修改的时候就会产生redo,这种情况叫做:延迟块清除
有这么一种情况:就是事务提交的时候,提交了以后,因为数据库的压力比较大,只清除了事务表里面的信息,其他的都没有清除;假设这时候,事务表里面的槽位是:5号段,2号槽位,第100次被覆盖,因为这个事务提交了,这时候就被覆盖了,就变成了:5号段,2号槽位,第101次被覆盖;然后数据块里面的事务槽因为没有清除,记录的还是:5号段,2号槽位,第100次被覆盖,这时候就去找,但是在undo事务表里面已经是:5号段,2号槽位,第101次被覆盖了,oracle就认为已经提交了,这时候接着就清除锁和事务槽,更改SCN号,更改提交状态,
快速提交和延迟块清除,都是为了提高提交的速度
构造CR块(consistent read)(读一致性)
图解:
一个undo段,假设里面有三个事务(T1、T2、T3),然后修改数据块里面的一行数据,修改数据之前,要把修改之前的数据放到undo里面事务T1对应的undo块里,修改前的值是1,修改后的值是2;
然后,select要访问这个数据块的这个数据行,oracle访问的时候,发现这个块上有事务槽,显示事务没有提交,然后oracle就根据xid找undue段里面的事务表对应的事务,看看这个事务是否已经提交,然后发现这个事务确实没有提交;
假设现在对于sp1来说,要读这个数据块,但是在这个数据块上sp2在修改并且还没有提交,这时候sp1是不能读未提交事务的,也就是说,对于任何的会话,任何的server process都是不能读未提交事务的;
这时候oracle会在buffer cache里面再找一个空块,把sp1正在修改的数据块里面所有行的数据取出来放到这个空块里,因为里面有一行有未提交事务,它就找事务槽的uba地址,然后找到undo数据,把修改前的数据取出来,还原事务修改前的值,再放到空块里面去,这就构造了一个块出来,这个块叫做:构造CR块
所以在oracle数据库里面,DML不阻塞select,也就是:修改不阻塞读;就是当oracle访问数据行的时候,去事务槽和undo事务表确认事务是否提交,未提交会在buffer中找到一个空块,找到undo中的源数据,构建一个CR,所以修改数据行的时候不会堵塞读。只读已提交事务,不读未提交事务。
崩溃恢复
图解:
数据库正在正常的运行着,一个undo段,里面有三两个事务(T1、T2、T3),T1对应修改三个块,T2修改了两个块;T1未提交,T2提交了;
这时候数据库突然崩了,数据库重新启动,重启以后呢,select要读T2事务对应的一个块,这个块是延迟块清除,然后显示T2这个事务没有提交,,然后去undo事务表的槽位发现事务已经提交,oracle知道该事务已经提交,马上清除锁和事务槽,更改SCN号,更改提交状态,然后直接读这个块;
读完以后,接着要读T1事务对应的一个块,发现T1事务之前没有提交,然后访问undo段的事务表里面的事务槽发现未提交,但是T1所对应的那个会话已经断开了,不存在了,因为数据库崩了,会话也都断开了,T1就不可能提交和回滚了,这时候select会帮助T1做一下回滚,强求回滚,然后T1这个事务就没了;
所以数据库突然崩了,数据库重新启动,在数据库突然崩的那一瞬间有很多的未提交事务,重启以后呢,这些事务不可能回来了,也不可能再提交,再回滚了,但是undo里面有undo数据在,这时候,select谁读到相应块的时候,就会把这个事务往前回滚一下,读的时候回滚一下,作为恢复的一个操作
访问以往事务修改过的数据块的数据
图解:
一个undo段,里面有一个事务T1,修改了一个数据块,然后T1提交了,还有一个事务T2,T2也要修改同样的数据块,因为事务槽所对应的事务T1已经提交,事务T2就可以覆盖事务T1在数据块中所对应的事务槽,要覆盖事务槽就要修改事务槽中的数据,就会产生undo,对于数据块来讲,修改任何数据都会产生undo;因为T2要覆盖事务槽就要修改数据,就要把事务槽里面的数据拿出来放到undo段的一个块里,然后新的事务槽的xid指向事务T2了,这时候T2也提交了;
我们就来找,找这个数据块数据修改的历史,对于这个数据块来说,被事务T1修改过,也被事务T2修改过,现在我们能看到事务T2修改后的数据,这时候,我们也可以看到事务T1修改过的数据,从T2往前推就可以找到T1修改前的数据;有T3,T4.....也是如此
假设数据库建立以后undo表空间足够大,没有边界的大;对于数据块来讲,数据库可以找到所有的数据块的修改信息,就是一个数据块被多个事务修改了
如果现在将undo returntion设置为:24小时,然后将表空间设置为:gurantee属性;也就是这个表空间一直存储24个小时的数据,那么可以访问24小时之内表的每个时刻的数据;
select * from t; 访问现在的数据;
select * from t as time of 13:30:01;访问13:30:01时修改过的所有数据块的数据
ORA-01555错误
图解:
比如,现在oracle有一个t表,t表比较大,下面有很多很多块;在8:50访问t表,在8:55的时候有一个事务修改了一个数据块,数据块里面的SCN被修改为8:55,然后提交了;
假设9:00的时候读到最后一个数据块的最后一行,但是8:55删除了一行数据;假设t表有一万行,8:00的时候开始读,到9:00的时候会读到多少行数据?
读取了一万行;
因为对于select来讲,读到最后一行数据时,这行数据对应的事务已经提交了,按道理,这一行上没有未提交事务,删除数据已经提交了,不能被读,但是还是读到了10000行数据。oracle在读select开始的时候,记住当时时间点所有数据块的SCN号:850,oracle做了一个假设,并且假设成立:就是将要访问的表在8:50这个时刻,所对应的所有数据块的事务槽,它们的SCN号都应该小于等于900,突然让时间停止,将所有数据块读一遍。当读到最后一个块的时候,发现SCN号是:855,然后找最后一条数据之前的数据,通过undo构建CR块,找出该行数据SCN号为:850时的数据;
在8:57的时候,8:55的undo块被覆盖了。导致8:50的select读数据的时候,去undo块中找,发现数据没了,无法构建CR块,oracle就会报出ora-01555错误,报出ora-01555错误的因为:snapshot too old(快照太旧)或者select读取的时间过长
导致ora-01555错误的原因:
可能是snapshot too old(快照太旧)或者select的执行时间太长,还有就是undo空间压力很大,undo数据被快速覆盖;该错误,会指定哪个SQL引起的问题
select访问的是生产表,触发ora-01555这个错误,原因可能是undo空间太小;
select访问的是字典表,oracle做ddl的时候,向系统表空间的数据字典做insert操作,会将修改信息写到系统表空间的undo段中专门给字典表做回滚;
所以访问的是字典表的时候,发生01555错误是系统表空间的undo段引起的,很可能是一个bug,mos中查找。
回滚
回滚的本质:
对某个表做delete的时候,忘了加where条件,然后删;假设这个表有1000万行,删除了30分钟还没结束,这时候这个过程产生了大量的undo数据;
然后后悔了,想结束这个事务,就是将窗口叉掉,然后刚才做的这个事务需要回滚;回滚的时候,oracle会读undo,将这30分钟删除的数据找出来,然后对表进行insert操作,这时候也会产生redo,但是这个可能需要花费60分钟;当然,如果不叉掉接着执行,可能再过2分钟就执行完了,或者回滚需要90分钟,这些都是有可能的;
因为误删了,必须回滚。假设操作是正常操作,表已经删除了20分钟,还未结束。很长时间不能访问这个表,因为在表上加了很多锁。想结束这个事务,这个事务就需要回滚,回滚可能需要更长的时间。在数据库中用SQL可以查某个事务还有多少时间结束。
几个操作所占用的undo和redo的情况:
insert操作主要消耗redo资源; delete操作主要消耗undo资源; update操作消耗redo和undo操作;
注意:对于oracle来说,DML主要消耗redo和undo资源
这两个资源需要注意:
假设有一个表T,有一个id列,现在想将表中的id列删除了:
做的第一件事,将T表用排他锁锁住,任何人不能访问这个表;
第二,将表里所有的块,假设有100万个块,里面id列的数据,全部删除,所有的块都是扫描一遍,删除一遍;
第三,执行的话,T表中所有的数据都要进行操作,产生大量的redo和undo;
第四,执行的时间太长;假如执行时间很长,生产扛不住了,叉掉窗口,这个事务就需要回滚,这时候可能需要更长的时间,这个表只能废掉了;
但是在表里面加一个不加默认值的列,一下子就完成了。只会在数据字典里面添加列。但是添加一个列的时候,设置了默认值,这个操作和删除一个列数据库进行的操作一样,同样危险。
29、undo_2_1(事务槽、延迟块清除、构造CR块、ora-01555)的更多相关文章
- About 静态代码块,普通代码块,同步代码块,构造代码块和构造函数的纳闷
构造函数用于给对象进行初始化,是给与之对应的对象进行初始化,它具有针对性,函数中的一种.特点:1:该函数的名称和所在类的名称相同.2:不需要定义返回值类型.3:该函数没有具体的返回值.记住:所有对象创 ...
- 10、代码块、构造代码块、静态代码块及main方法之间的关系
1.普通代码块: 在方法或语句中出现在{}之间的类容就称为普通代码块,简称代码块.普通代码块和一般的语句执行顺序由他们在代码中出现的次序决定--“先出现先执行”,即顺序执行. /*下面第一个类时合法的 ...
- Java中普通代码块,构造代码块,静态代码块区别及代码示例
//执行顺序:(优先级从高到低.)静态代码块>mian方法>构造代码块>构造方法. 其中静态代码块只执行一次.构造代码块在每次创建对象是都会执行. 1 普通代码块 1 //普通代码块 ...
- Java中普通代码块,构造代码块,静态代码块执行顺序
//执行顺序:(优先级从高到低.)静态代码块>mian方法>构造代码块>构造方法. 其中静态代码块只执行一次.构造代码块在每次创建对象是都会执行. 1 普通代码块 1 //普通代码块 ...
- Java提高篇——静态代码块、构造代码块、构造函数以及Java类初始化顺序
静态代码块:用staitc声明,jvm加载类时执行,仅执行一次构造代码块:类中直接用{}定义,每一次创建对象时执行.执行顺序优先级:静态块,main(),构造块,构造方法. 构造函数 public H ...
- 静态(static)代码块、构造代码块、构造函数、父类子类执行顺序
静态代码块:static修饰的代码块. 在类加载-初始化的时候进行,主要目的是给变量赋予初始值 构造代码块:直接在类中定义且没有加static关键字的代码块称为构造代码块. java会把构造代码块放到 ...
- 关于java中普通代码块、构造代码块与静态代码块
1.普通代码块 public static void main(String[] args) { /*普通代码块: *直接定义在在方法或语句中出现”{普通代码的执行语句}“的就称为普通代码块. *普通 ...
- Java中普通代码块,构造代码块,静态代码块的代码演示样例及区分
//运行顺序:(优先级从高到低.)静态代码块>mian方法>构造代码块>构造方法. 当中静态代码块仅仅运行一次.构造代码块在每次创建对象是都会运行. 1 普通代码块 <span ...
- Java中静态代码块、构造代码块、构造函数、普通代码块
在Java中,静态代码块.构造代码块.构造函数.普通代码块的执行顺序是一个笔试的考点,通过这篇文章希望大家能彻底了解它们之间的执行顺序. 1.静态代码块 ①.格式 在java类中(方法中不能存在静态代 ...
- 【Java学习笔记之十七】Java中普通代码块,构造代码块,静态代码块区别及代码示例分析
//执行顺序:(优先级从高到低.)静态代码块>mian方法>构造代码块>构造方法. 其中静态代码块只执行一次.构造代码块在每次创建对象是都会执行. 1 普通代码块 //普通代码块:在 ...
随机推荐
- 阿里云图床(PicGo+阿里云OSS)搭建
阿里云图床搭建方法: 1.登录阿里云,搜索对象存储oss,新用户免费使用3个月20G,到期后,一年也就9元左右,还是很划算的. 2.在左侧列表里,点击Bucket列表,创建Bucket 3.Bucke ...
- Java多线程并发之同步容器和并发容器-第一篇
Java多线程并发之同步容器和并发容器-第一篇 概述 本文主要讲解在Java多线程并发开发中,集合中有哪些支持并发的的.什么是同步容器(集合),什么是并发容器(集合)?并发容器分类有哪些?每个分类都有 ...
- containerd 拉取k8s.gcr.io/pause镜像i/o timeout
由于k8s.gcr.io 需要连外网才可以拉取到,导致 k8s 的基础容器 pause 经常无法获取.k8s docker 可使用代理服拉取,再利用 docker tag 解决问题 docker pu ...
- 小tips:nodejs请求接口超时使用中间件connect-timeout实现自动超时机制
如果在请求中不设置超时时间,那么一直处理loading卡屏状态,使用connect-timeout来设置自动超时时间. 安装: npm install connect-timeout -S 如下例子: ...
- iPay88 学习笔记
ipay88 学习笔记 之前弄过 MOLPay 现在弄 ipay88</p><p>差不多的概念 这里记入流程就好了 首先是做订单, 然后通过 merchant key + 订单 ...
- ASP.NET Core – Work with X509
前言 这篇主要是说如何用 ASP.NET Core 读写系统里的证书 Store 和创建一个证书, 还有使用证书做加密, 解密, 签名. 主要参考: C#数字证书编程总结 (读写证书 Store) E ...
- ASP.NET Core – 网站发布要做的事儿 Publish, Minification, Compression, Cache, HSTS, URL Rewrite Https & www, Close IIS Feature
前言 要发布网站需要做一些优化, 比如 cache, compression, minification 等等. 以前有写过相关的文章: Asp.net core 学习笔记 ( IIS, static ...
- EF Core – Library use EF
前言 写 Library 有时候会用到 database, 会想用 EF 来维护. 比如 Identity, IdentityServer, OpenIddict, 这些 Library 都有使用到 ...
- [rCore学习笔记 027]地址空间
写在前面 本随笔是非常菜的菜鸡写的.如有问题请及时提出. 可以联系:1160712160@qq.com GitHhub:https://github.com/WindDevil (目前啥也没有 引言 ...
- 【VMware VCF】使用 SoS 实用程序检查 VCF 环境的运行状态以及收集组件的日志信息。
VMware Cloud Foundation 解决方案中有一个叫 Supportability and Serviceability(SoS)可支持性和可维护性的实用程序,可能你在初始构建 VCF ...