【独家首发】冯柯《我的ORACLE笔记一:关于基本协议》全新修订版连载中!

【独家首发】冯柯《我的ORACLE笔记一:关于基本协议》全新修订版连载中!

冯柯后来去了蚂蚁金服  OceanBase

神舟通用

南大通用

 

【独家首发】冯柯《我的ORACLE笔记一:关于基本协议》全新修订版连载中!

2014-08-12 冯柯 云和恩墨

由神舟通用技术总监冯柯写作的文章《我的ORACLE笔记》全新修订版本将在此独家首发连载!文章重点讲述作者与Oracle的接触中所思考的问题:包括基本协议、回滚段、ITL、Cleanout、保留空间和有限CR等。欢迎大家持续关注!

 

您对文章内容有任何疑问时,欢迎您点击原文链接,填写阅读反馈表。我们不仅会邀请作者来回答问题,还会从中抽取一位粉丝赠送精美超值礼品一份哦~(每期一位,共六位,将在后续统一公布获奖名单)

 

【作者简介】


冯柯

天津神舟通用数据技术有限公司技术总监

 

数据库技术的分享者,关注高性能和高可用性。新浪微博@神通冯柯

 

《我的ORACLE笔记一:关于基本协议》


好吧,现在做回文艺青年。

 

我决定把自己对ORACLE MVCC(注:MVCC是多版本并发协议,ORACLE MVCC是其实现读写并行,支持高并发的核心技术)的理解分享出来。毕竟前期折腾了这么长时间,现在算是利用一下剩余价值吧。其实你如果要做一些多用户环境下的数据管理,数据库中的许多技术都值得你去借鉴,尽管你不一定需要ACID。MVCC就是这样一种技术,它可以在保证数据一致性的同时,实现最大的并发。其实我觉得ORACLE中最有价值的就是MVCC和RAC,至于其它的,都属于“强者更强”的自然发展吧。

 

试图用最直白的自然语言把MVCC说清楚,对我来说可不是一件容易的事情。但我仍然对当年研究DSI(注:DSI是ORACLE的内部培训文档,你可以在网络上找到相关的链接,和MVCC关系较密切的是DSI402)时的痛苦记忆尤深,希望我的介绍对大家有所帮助,毕竟DSI是写给SUPPORT同志们看的,更多的时候,它只是告诉你How,而不是Why。

 

从协议上看,MVCC很简单,就是你总是只能看到数据库在某个时间点的状态(ReadConsistency-RC),而不管其后那些数据是否发生了更新,所以实际上你是看到了数据的某个历史版本。在ORACLE中,这个点就是你(事务)开始的时间。这样我们就实现了所谓的读写并行,也就是你的读总是能成功(而且你每次读到的都是同一个数据),即使数据正在被人更新(因为你们其实操作的是不同的版本)。(Comment By 云和恩墨杨廷琨:当Oracle中资源不足时也可能导致读操作失败,这时会出现著名的ORA-1555:shapshot too old错误。)

 

然而任何好处都必须有代价,不是吗?你所付出的代价就是所谓的写写串行。没错,写被严格串行了。记住,尽管你可以读取数据的任意历史版本,但写只会作用于数据的当前版本,或者叫最新版本。所谓写写串行,就是说如果在你开始事务和写数据之间,数据已经被其它人改了,或者说的准确点,当你看到的版本不是当前版本时,You Have Been Killed(事务回滚)。所以你会注意到,ORACLE本质上并不适合于写写冲突剧烈的应用(听到这,DB2或SQL Server们笑了)。

 

为了更准确地描述协议,我们需要引入一个关于时间点的术语:SCN。关于SCN,有人叫它System Change Number,也有人叫System Commit Number(它们的含义实际上是不同的)。好吧,我并不在意这个。SCN就是一种时间序,系统会维护一个GlobalSCN表示当前的时间。每个事务开始时(严格地说,是你开始发出第一条SQL时),你会获得当前时间,那就是你能够看到的时间。ORACLE中,这个时间叫做快照时间(SnapshotSCN)。也就是说,就好像你在这个时候给数据库拍了个快照。当事务提交的时候,你会获取当前时间并把GlobalSCN+1,这个时间叫做提交时间(CommitSCN)。当你更新数据时,你会产生一个新的版本,并把你的CommitSCN赋给这个版本(注意这里的问题,由于事务还没有提交,实际上这时候你还没有拿到CommitSCN)。这个问题我们以后再说。

 

所以,事务有快照SCN和提交SCN,数据也有SCN。接下来我们可以准确地定义ORACLE的MVCC:

关于读,你能够看到这个数据,如果:

1)它是你自己的更新,或者

2)它是已经提交的数据,并且SCN <= 你的SnapshotSCN

 

关于写,你能够更新这个数据,如果:

1)它是最新的,并且

2.1)它是你自己的更新,或者

2.2)它是已提交的数据,并且SCN <= 你的SnapshotSCN

 

前面说到,在关于写写串行中,如果你看到的版本不是当前版本,你会被Killed。我承认这样说对ORACLE不公平,事实上有两点:

1)如果当前版本尚未提交,那么你可以等待,如果那个事务最后回滚了,那么你有很大的机会能过关。

2)ORACLE实际上定义了两个时间点,或者说两种隔离级别:一种是事务级RC,也就是你只能看到本事务开始时数据库的状态;另一种是语句级RC,你只能看到本条语句开始时数据库的状态。在语句级RC中,在你被Killed之前,你可以重启当前语句,于是你便获得了一个更大的SnapshotSCN(比那个数据的SCN更大),然后再试一次,你过关了。

 

所以感谢上帝,在ORACLE中,除非你特别指定,否则你总是在语句级RC中幸福地徜徉。因此只要你愿意不断地去重试(如果我们不去考虑重试的代价),事实上我们就实现了一种理论上最佳的并发协议,事务永不被Killed。

 

但是现实总是残酷的,后面我们将看到,再好的协议,落地的时候总是会.....

 

好吧,先说到这吧。

 

后续将为您带来《我的ORACLE笔记二:关于回滚段》,敬请期待!

 

【推荐关注】

神通官方微信:shentongdata

神通新浪微博:神通数据库

神通官网:www.shentongdata.com

 


DF

posted @ 2014-08-13 22:06  huangchaolilli  阅读(691)  评论(0)    收藏  举报