34、检查点及崩溃恢复
log buffer space
多个sp连接上数据库,每个sp有一个PGA,修改数据,在PGA里面都生成了日志,然后把日志写到log buffer里;这时候由于lgwr的性能问题或者是IO比较差,或者存储的性能比较差,没有来得及把日志从log buffer里面写到redo log里面,使得log buffer的压力比较大,把log buffer存满了,这种情况我们称为:log buffer space(等待事件)
崩溃恢复
第一种情况:事务已提交,但是对应的数据还未写入磁盘
一个用户修改了一个数据块,这就成了一个脏块,这个事务已经提交,但是修改的数据还没写入磁盘,但redo log肯定已经写入磁盘了;这时候,数据库崩溃了,oracle就会使用redo log将脏块给跑出来,就是使用redo log来把数据库崩溃的那个时刻的脏块构造出来,就要找最早脏的数据块的LRBA地址,然后数据库崩溃的那个时刻的脏块的日志一定在LRBA地址之后,
第二种情况:事务未提交,但是对应的数据已经写入磁盘
一个用户修改了一个数据块,这就成了一个脏块,这个事务还没提交,但是修改的数据已经写入磁盘,因为dbwr进程会完全根据lgwr,适当的参考ckpt,把修改的脏块写到磁盘上,这时候,dbwr不管脏块上有没有未提交事务;修改的数据已经写入磁盘,redo log也一定写入磁盘上了;
因为数据库里记录着所有未提交事务的事务信息,事务所对应的数据块信息,事务的undo数据;这时候数据库崩了,oracle就会根据数据块里事务的信息,找到事务的信息,发现事务确实没有提交,这时候,就成了一个死事务;
死事务就是:事务没有提交,并且对应的会话没有了;
然后sp访问到这个数据块的时候,使用undo信息,把这个数据块回滚一下,这个未提交事务也就被回滚了
第三种情况:事务未提交,对应的数据也还没写入磁盘
一个用户修改了一个数据块,这就成了一个脏块,这个事务还没提交,对应的日志也还在log buffer里面,还没写入到磁盘;这时候数据库崩了,数据和日志都还写入磁盘,这种情况没必要恢复了,丢就丢了
buffer cache里面,每个buffer数据块有一个LRBA地址,ckpt检查点队列会将这些数据块按照最早脏的时间链接起来,这个链叫做:ckpt检查点队列
数据库里面最早脏的那个数据块所对应的LRBA地址,ckpt进程每隔3秒,会将最早脏的数据块的LRBA地址写入到控制文件中
oracle数据库崩溃以后,oracle会根据这个最早脏的LRBA地址,使用redo log,将redo log里面在LRBA地址之后的所有日志前滚,将崩溃那一个时刻的所有脏块重新构造出来
日志空跑的情况
使用日志来跑出脏块的时候,会出现一种情况:空跑
就是日志有:SCN号、dba地址、相应的操作、对哪一行做的操作,数据块的事务槽里有SCN号;数据库崩溃恢复的时候,oracle就会拿着redo log里面日志的SCN号去跟数据块里面事务槽里的SCN号比较,如果,数据块里面事务槽里的SCN号比日志的SCN号小,说明数据块比日志要新,这条日志就空跑,接着下一条日志;然后这条日志也是修改的同一个数据块的日志,日志的SCN号比数据块里面事务槽里的SCN号都大,说明数据块没有日志的新,就需要这条日志来构造出这个脏块
等待事件:
1、free buffer waits :
就是sp把一个数据从数据库读到buffer里面的时候,就找LRU,找了半天没找到,就抛出free buffer wiats,这时候说明数据库好脏,还有就是数据块被频繁的访问
2、log file parallet waits:
日志从log buffer往redo log写的时候lgwr进程的一个写的性能
3、log file sync :
一个sp执行一个事务,然后事务提交了,提交以后,触发lgwr把日志写到磁盘,然后lgwr又将日志写到磁盘的这一个过程响应回来给sp,这一个过程就是:log file sync
4、log file switch(check point incomplete:检查点不完全):
log file切换(switch),然后要使用下一个log file的时候,dbwr还没有将日志对应的数据写到磁盘上;log file的状态为active,这样的redo log还没能被覆盖使用,就没有可以使用的log file (可以将日志文件增大,增多文件),导致数据库短暂的夯住(挂起)了
5、log file switch (archived needed) :
redo log被覆盖以前,要先归档到归档日志里面,如果日志文件没有被归档到归档日志,日志文件就不能被覆盖,就可能会导致没有可以使用的log file文件,数据库就会夯住了(可能是归档日志空间满了,这是长时间的夯住)
6、buffer buzy waits :
就是一个sp正在修改一个数据块,然后另外一个sp也要读这个数据块,就产生了锁等待:1、正在从磁盘读到内存的时候;2、其他进程正在修改
市场机制
buffer cache里面的buffer,可用块按照冷热(根据TCH来判断的)的顺序链起来,LRU链起来;脏块也按照冷热链接起来,LRUW链;然后想要把数据从磁盘读到buffer里面的时候,它就覆盖冷的块;dbwr写的时候,也是先把冷的脏块先写到磁盘;
也就是说,你冷就经常被覆盖,你不冷就经常在buffer里面
TCH:数据块冷热的一个判断依据
一个sp正在访问一个数据块,这个数据块的头部有一个TCH(touch),访问一次这个数据块,touch就加一,如果touch值很高的话,就说明这个数据块经常被访问,这个块就是热块
全表扫描,6个块全部调到内存中,很读很多的block到buffer cache 中。当一个表发生全表扫描时,将块放到冷端很快就被置换出来。虽然有6个块,一边向里面调,一边置换出来,虽然产生大量的io,但是并不一定占用大量的buffer。
keep池和recsql池
对于一个经常被全表扫描的小表,oracle要把表的全部数据调到buffer里面去,这些数据被放在冷的一端,然后刚调进去就被换出来了,因为其他sp在访问一个块的时候,先覆盖冷的块,刚调进去就被换出来,刚调进去就被换出来,对于这种情况可以使用keep池;
从表面上看,数据库单独从buffer cache里面拿出一个空间来做keep池;然后将经常全表扫描的小表做成keep表,这时候不访问这个keep表的时候,也不会使用这个keep池;然后访问这个表的时候,就调到keep池里;访问keep表的时候,就会自动被调到keep池里去
keep:其实是将数据无论是全表扫秒还是索引访问都会放到热端,不容易被置换出来,但是就造成了一个对空间的浪费;然后其他表用到的keep池的空间就小了,同时IO也起来了
recsql池:就是将表放到buffer cache的冷端,就容易被置换出来;
比如:对于一个只是晚上才访问的大表,但是也会走索引,频繁的访问,这时候就会导致buffer cache被这个表过多的占用,然后第二天白天的时候,这个表是要被访问的,但是这个表过多的占用buffer cache了,访问其他表的时候,其他的表就会被被挤出来,挤出来以后,数据库的物理IO就会很高:因为访问其他表的时候,这些表都被挤出来了,访问的时候就要从磁盘往内存里读,就导致物理IO很高,这时候就可以做一个recsql池,将表放到冷端,这样就容易被置换出来,就不会过多的占用buffer cache的空间了,所以对一些技术使用的时候要谨慎