我们已经知道oracle多版本机制能够提供一致性的答案,而且还有高度的并发性。但是真的就没有其他不好的一面吗?
案例1:
假设有一个资源调度程序(可以用来调度会议室,投影仪等资源),业务规则是:在给定的时间段不能将一种资源分配给多人。这里涉及到资源表(Resources)与资源调度表(Secludes)。
我们一般的实现方式是,先查询某一时间段的某一资源是否已经被分配,如果没有被分配,我们就可以使用。
查看是否被分配SQL语句:
select count(*) from schedules where resource_name = :room_name
and (start_time <= :new_end_time) and (end_time >= :new_start_time)。 ---SQL1
然后插入分配记录(如果得到结果为0)
insert into schedules ( resource_name, start_time, end_time )
values ( p_resource_name, p_start_time, p_end_time ); ---SQL2
但是如果我们让2个人同时预定13:00到14:00期间的投影仪资源,可能都会预定成功。假设一个人是事务A,另外一个人是事务B,在事务A执行SQL1语句的时候,事务B也开始执行SQL1语句(因为oracle里面查询是不会被阻塞的)。那么事务A与事务B查询的结果都是0,于是都可以申请到投影仪资源了。
解决方案:
应该在查询之前先锁定要申请的资源,使得事务A与事务B在执行SQL1与SQL2语句的时候串行。
在执行SQL1语句之前先执行如下SQL语句:
select * from resources where resource_name = :room_name FOR UPDATE; ---SQL3
这样当事务A执行完SQL3之后,事务B执行SQL3的时候就会被阻塞。除非事务B申请资源跟事务A不同。
案例2:热表上超出期望的I/O
在生产环境中在一个大负载条件下,一个查询使用的 I/O 比你在测试或开发系统时观察到的 I/O 要多得多。造成这种现象的原因是:在你测试系统中,由于它是独立的,所以不必撤销事务修改。不过,在生产系统中,读一个给定的块时,可能必须撤销(回滚)多个事务所做的修改,而且每个回滚都可能涉及I/O来获取undo信息并应用于系统。
因为oracle提供多版本机制的原理是,读取数据的时候判断这个数据是不是已经被修改了,如果被修改了就从undo段去获取修改前的数据。如果发现这个修改前的数据还不是想要的数据,继续找更老的数据,直到找到开始执行SQL语句那一刻这个数据的值。
所以在oracle里面如果一个表经常被修改,查询,会发生这样的情况。因为查询的时候,如果被修改的数据越多,需要读取undo段的信息就越长,I/O操作自然也会越多。对于这种热表的查询,最好能够把查询的时间压缩到最短,以便在查询期间,这个数据被其他事务修改的概率最低,从而需要从undo段读取的数据最少,最大限度减少I/O操作的概率。
运维网声明
1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网 享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com