oracle何时checkpoint,我对checkpoint曾经的误解和现在的理解(一)

本帖最后由 jayli426 于 2013-2-14 01:52 编辑

因为从前我只是写程序的人,也不是计算机专业出身,所以对Oracle的checkpoint有过很多误解

现在想来,有些甚至是让人哭笑不得。

现在我来描述一下我从前的误解,我相信这也是很多初学者的误解。

我在这里描述一下,避免后来的初学者踏入同一条河流

1)第一个误解,redo log只是理解成log,没有理解redo

这是什么一回事呢?

大家做应用系统的都知道,日志只是记录系统中的变化历史。

其中最重要的目的,主要是当系统报错时,能够查看具体的报错信息和当时的上下文

这样能够方便我们定位问题和排错

可是,如果带着这个思路去理解redo log,显然是南辕北辙。

oracle中redo log某种程度上来讲,是实际数据的一部分。

更确切的说如果没有redo log,就无法保证数据的一致性

其实Oracle也有类似(我刚刚提到的)应用系统的日志,例如alert.log。

所以建议初学者 看到redo log的时候,不要只看到log,而忽视了redo

而且这个redo 是真正会redo的,而不是简单记录操作历史的。

2)第二个误解:写入数据文件的只会是commit过数据

程序员最初接触Oracle,自然都是从SQL语句开始的,

例如执行

insert table_A values('XX','YY',...);

commit;

update table_A set column_1='ZZ';

commit;

总而言之看见commit,就知道之前执行(在同一个事务中)的insert 或者update,或者delete涉及到的数据 已经完成了持久化。

OK

当看到DBWR负责将数据写入Datafile这样一个描述后

我的第一感觉DBWR 只会将 commit过的数据写入data file

(这是误解二)

实际却是 DBWR 会写一切被修改的数据块 (说一切被修改过的数据,可能不妥)。

同时还以为执行commit动作的时候,就会把对应数据写入到数据文件

(这是误解三)

其实是不会,是先写redo log,然后再找时机往数据文件中写 (具体什么时机,则要看参数配置了)。

为何会这样呢?

因为写数据文件时随机写,代价太高。

而写redolog 是顺序写,相对代价低很多

是否又有初学者问;什么是随机写

我建议可以先了解harddisk的原理出发,去了解随机写和顺序写

不过可以简单理解为,假设现在有1万个房间,每一层有100个房间,假设现在要访问801,1001,3003这3个房间,

分别放上桔子,苹果,香蕉

我们得跑上8楼,10楼,30楼,然后再找对应的房间号

这就是DBWR写数据文件做的动作

而redo log只是记录我们要去801号房间去放桔子,1001号房间去放苹果,3003号房间去放香蕉

这么几个需要做的动作。

至于什么时候放?那当然等DBWR有空了再放。

这个技术有个专有名词,叫write head logging

即日志优先写,或者优先写日志。

回到误解二

说实话,我敢担保初学者看到这里依然会有疑惑的 DBWR 怎么会写一切会修改的数据块呢?

那么岂不是未提交过的数据也被写入了数据文件了?

可事实却是如此

那为何未提交过的数据也被写入数据文件呢?那么岂不是数据的一致性发生问题了?

(

这就是Oracle 知识的特点

我们不能只关注一个知识点,而是需要将各个知识点串起来,才会有对Oracle真正理解。

因为只关注一个的时候,就会容易走入死胡同。

所以我们要做得真的就是如白鳝大师所言“像Oracle一样思考”,而且是全盘和系统的思考

)

言归正传

那为何未提交过的数据也会被写入数据文件呢

注意:Oracle读写的最小原子单位是数据块,不是记录

性急的兄弟又会立马出来打断,这个我知道啊,但是这和我的问题有什么关系呢?

哈,关系大着呢?

因为DBWR只是按数据块被更新的顺序的依次写入到数据文件中

那么存在这么一种可能,就是这个数据块上既有commit过记录,也有正在被某个事物处理的数据,

那么当这个数据块被写入到数据文件的时候,很明显,此时被修改但是未被提交过的数据也被写入了数据文件。

3)第4个误解:redo log只记录了commit过的数据变化

前面提到write head logging,也就是说commit过的数据,应当会被redo log 记录下来。

那么从前我的理解是redo log只会记录commit过的数据,而不记录未提交的数据

现在回想,这个理解其实还颇有些道理的

是啊,那些没有提交过但是被修改过的数据,为何要被写入到日志里面呢?

让他好好在内存里呆着,等到事务rollback的时候,自然将这些数据给扔掉算了(其实就是不care,不管就得了)。

我为何有这个思路呢?

就是一直是以SQL的逻辑处理方式来理解oracle的内部处理机制

SQL处理数据的单位是基于记录的

而Oracle 处理数据,DBWR是基于数据块的,后台进程写redo log record是基于redo log block的

好像处理control file 的单位也不同的

但是总而言之,都不是基于记录的。

考虑一下之前提到过的场景

当一个数据块上既有commit过记录,也有正在被某个事物处理的数据,

那么当这个数据块被写入到数据文件的时候,很明显,被修改但是未被提交过的数据也被写入了数据文件。

那么Oracle 怎么知道这个数据块里面的数据是提交了还是没有提交的呢?

数据块里面虽然是记录是事务编号,但是并没有记录哪个数据是和哪个事务相关,即我们只能知道这个数据块和哪些事务关联

但是我们无法知道这些事务和这个数据块中的哪个数据关联。

这个关联靠什么, 靠的是redo log record

所以只有把未commit过的记录相关联的redo log record记录也写入到redo log file中。

我们才能在数据库crash后,恢复数据的时候(确切的说是instance recovery),知道哪些数据是commit过的,哪些数据是未commit过的,需要rollback的

4)redo log记录数据变化是基于记录的

这个误解其实还是源于      SQL处理数据的单位是基于记录的

例如执行了一条sql

insert table_A values('XX','YY',...);

redo log里面就记录这条SQL

insert table_A values('XX','YY',...);

可是是这样的吗?

想一想,redo log可是要负责recovery的

试想

如果我们执行了

delete from table_A

但是我们没有提交,

而相应的数据块也被写入了,如果这个时候数据库crash

那么再次启动恢复的时候,如何找回之前的数据呢?

(

这里我有疑问,感觉解释不下去了

貌似这个时候也可以通过undo 表空间找回啊?

因为这个时候对应undo 表空间的数据也是写入了的啊

因为修改实际业务数据块的时候,也修改了undo 表空间的数据块

这个时候SCN应当是相同的,那么实际业务数据库写入了的时候,undo表空间也是写入了的。

)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值