2008中国IT技术精英年会是由IT168、ITPUB、IXPUB每年共同主办的中国IT技术精英年会,是业界新趋势、新技术发布的核心平台。详细信息可以参考:
http://ciec.it168.com/2008/index.shtml
我的这个奖绝对是拣来的,感谢老杨yangtingkun的谦让与支持,他本来排第一,但是他选择了最佳BLOG写作奖。我们团队就有2个获奖:
我获得了数据库大版最佳版主奖
ningoo获得最佳技术回答奖
还有支付宝的fenng也获得了数据库大版最佳版主奖
2008中国IT技术精英年会是由IT168、ITPUB、IXPUB每年共同主办的中国IT技术精英年会,是业界新趋势、新技术发布的核心平台。详细信息可以参考:
http://ciec.it168.com/2008/index.shtml
我的这个奖绝对是拣来的,感谢老杨yangtingkun的谦让与支持,他本来排第一,但是他选择了最佳BLOG写作奖。我们团队就有2个获奖:
我获得了数据库大版最佳版主奖
ningoo获得最佳技术回答奖
还有支付宝的fenng也获得了数据库大版最佳版主奖
同事去交违章罚款,系统突然跳出ORA-00257错误,然后就什么也做不了。一直等了半个多小时,后面的队伍排起了老长,这个问题才解决掉。
那ORA-00257是什么错误呢?
估计是归档的磁盘空间满了,这么一个错误就需要半个小时来解决,其内部办事效率也可见一斑。
当初,Oracle ACE也是红火一时,现在,在Oracle官方网站,已经找不到直接的入口链接了,起码,我找了半天还没有找到。
在Taobao,我们很多人都错过了第一,二批成为Oracle ACE的机会,不是没有收到邀请,而是错误的估计了ACE的价值。因为就算我们自己不认可Oracle ACE的价值,但是,别人是认可的。
就跟当初biti_rainy第二批,成为中国第8个,全球第100个ACE,有人写信祝贺说,“恭喜你成为中国第八,真厉害啊”。我相信biti_rainy除了苦笑,不会认为这是表扬吧。
第三批Oracle ACE汪海与我都添了表,不过,从处理速度上来看,就知道Oracle的重视程度已经严重不如以前了,现在在Oracle的官方网站已经能查到我们的信息了。
这样一来,Alibaba起码有4位Oracle ACE,所谓的Oracle ACE,其实,就是Oracle找的一群免费讲师,没有什么值得祝贺的,不过是Oracle把握了大家的心理而已。
Logmnr在Oracle 9i以后做了众多的改进,如可以不需要build flat文本文件就可以分析日志了,也就表示可以不需要修改参数utl_file_dir就可以分析日志了,避免了修改参数utl_file_dir导致的重起数据库问题。另外也开始支持把字典信息build到联机日志中,在异地分析归档日志。
在flashback也不能帮上忙的时候,logmnr却是非常有用的。因为只要误操作时期的归档日志存在,就可以通过归档日志来恢复误删除(delete)的数据。
如果在Oracle 9i以上,采用在本地的在线数据字典分析归档日志,就这么简单:
可以看到,在线分析其实就只需要这两步,添加日志并分析日志。注意以上OPTIONS => DBMS_LOGMNR.NEW,表示添加第一个日志,如需要另外添加更多的日志,可以用如下方式即可。
如果日志分析完成,可以把需要的信息保存到临时表,如
然后,终止日志分析过程。
对于临时表中的SQL_UNDO,可以选择性的恢复,如采用如下的脚本来恢复,这里为了减少阻塞,每1000条提交一次。另外,需要注意的是,SQL_UNDO中的分号,如果想用动态SQL来执行的话,是需要去掉的。
以上的PL/SQL代码其实还可以加强,如恢复成功一条,就设置状态值为1,否则,设置状态值为-1,方便跟踪那些记录恢复成功,哪些记录恢复失败了。
另外,需要注意的是,在Oracle 10g以下,LOGMNR的临时表v$logmnr_contents,使用的是system表空间,在Oracle 10g以后改为sysaux表空间。可以使用如下的命令,更改logmnr的特定表空间,防止system表空间出现空间不够。
从Oracle 9i开始,oracle standby就开始可以实现“滚动”升级,如升级一个小的补丁(patch)或者是一个补丁集(patch set),如图:
如果升级小的补丁,并不涉及到数据字典的升级,这个方式问题不大,但是,一旦涉及到升级数据字典,就存在一些问题了
1、在oracle 10gR2以前,如果存在一个或多个物理standby,因为物理Standby是只读的,只有升级软件的时候是可以在线升级的,升级standby数据字典的时候必须要switch over或者是failover之后,在停机时间来进行,这个过程耗费的时间可能也比较长。
2、在oracle 11gR1以前,主备库之间最多只能是跨小版本的补丁集,而不能是主版本的跨越,如9i到10g的standby,导致这个升级的功能也很有限。
至于问题1,在Oracle 10gR2以后,推出了一个全新的方法,如果主库存在一个或者多个物理Standby,可以先把其中一个物理Standby转换为逻辑Standby,执行升级操作,升级完成以后再转换为物理Standby。这个过程不会影响到其它的物理standby,完全可以平滑进行,这样的话,连升级数据字典的时间也可以在线完成了。
至于问题2,在Oracle 11gR1以后,可以跨大版本做Standby,如从Oracle 10gR2到Oracle 11g,所以,如果Standby升级到11g,依然可以接受Oracle 10gR2的日志,并应用,这个对大版本的数据库升级非常有用。
所以,有了以上的一些技术,就可以完全实现在线安装新版本的软件,在线升级了,整个升级过程最终仅仅是Standby切换的时间那么长而已。
最后,如果再结合如下2个技术点,整个过程就非常完美了
1、SQL重演(SQL replay)技术,可以在升级以后的standby目标数据库上,运行主库的完全的负载压力,看看目标数据库是否符合现在负载压力的要求,特别是SQL语句的执行计划,在新的数据库版本中,是否有所变化。
2、结合前面结束到的falsh database或者是slapshot database技术,可以在升级以后的standby目标数据库上做完压力测试,或者是SQL replay之后,继续回到Standby恢复状态,对整个系统不造成任何影响。
从Oracle 11g开始,又提供了一个全新的flashback方式,叫闪回数据归档,ningoo这里已经有所描述。与以前的绝大部分flashback不一样的是,flashback data archive不再依赖于undo来构造历史数据,而是依靠现有的表空间来存放历史数据。
flashback data archive并不是记录数据库的所有变化,而只是记录了指定表的数据变化,所以,flashback data archive是针对对象的保护,是flashback database的一个有力补充。
通过flashback data archive,可以查询指定对象的任何时间点(只要满足保护策略)的数据,而且不需要利用到undo,这个在有审计需要的环境,或者是安全性特别重要的高可用数据库中,是一个非常好的特性。缺点就是如果该表变化很频繁,对空间的要求可能很高。
下面,将做一个测试,来证明flashback data archive。首先创建一个数据归档区,每一个数据归档区都可以有一个唯一的名称,这个名称对应了一定的数据保留策略,如假定数据归档区一的数据可以保存1年,而数据归档区2的数据仅仅是保留2天,以后把表放到对应的数据归档区,则按照该归档区的策略来保留数据的历史。
一个系统中,可以有一个默认的数据归档区,可以有很多其它的数据归档区,这里的数据归档区其实也是一个逻辑的概念,表示从一个或者多个表空间中拿出一定的空间,来保留表的修改历史,方便表不利用undo就可以flashback到归档策略内的任何一个时间点上。
一个归档区可以不仅仅对应一个表空间,可以采用如下的命令增加或者删除该归档区的表空间的个数,也就是增加或者是减少该归档区空间的一种方法。如,给数据归档区1增加一个表空间
或者删除这个表空间,注意的是,这个删除仅仅是表示从数据归档区删除,并不是删除该表空间。
也可以直接修改现有的表空间,可以分配给数据归档区的空间,注意的是,这个配额空间可以大于表空间的大小。
也可以修改该归档区的保留策略,如为一个月,这里把默认归档区的保留策略修改为一个月。
以上的一些工作做完,现在就可以在业务用户下,指定特定的表,对应到特定的数据归档区了。把表指定到对应的数据归档区,有2种方法,一是在创建的时候直接指定归档区,一种是对现有的表指定一个归档区。
注意,如果不指定归档区的名称,则指定到默认归档区,否则,就属于指定的数据归档区。以下创建了3个表,一个指定到默认归档区,一个指定到数据归档区data_test2,另外一个为了做对比,没有指定到任何数据归档区。
现在,把时间打开,并往这两个表中插入一些数据,看看数据归档区怎么生效。
可以看到,这些数据是在9:33分左右写进去的,最新数据保留策略应当是,表test1对应的是默认的数据归档区data_test1,数据保留策略是一个月,表test2对应的是数据归档区data_test2,数据保留策略是2天,而表test3没有数据保留策略。
然后,对这三个表再做一些操作,如删除现有记录,并插入一些新记录,最后,只要证明没有经过undo,我们查询时间点2007-09-04 09:33:52,能找回原来的数据即可证明数据归档区是真正有效的。
现在,先利用flashback 功能去查询数据,均可以获得正确的数据,但是,不能确认的是,这些数据的获得到底是经过undo获得的还是数据归档区获得的。
如果我们把undo 表空间swith一下,看情况有什么变化。为了确保生效,我们先重起该db,等重起完成以后,完成如下操作:
切换到新的undo表空间,如果没有,需要新创建
删除原来的undo表空间
然后,再执行如下的查询:
可以看到,没有设置数据归档策略的表test3,查询的时候会报01555错误,但是,设置过数据归档策略的test1与test2,都能正常查询到数据,可以看到,数据归档是生效了。
这里是一个简单的实验,时间可能远远没有达到设置的策略期,但是,却可以证明数据不是经过undo查询而获得的。
最后,可以简单的说一下数据归档区的管理,如清除所有归档区的数据,如果数据归档空间如果不够,将会导致表DML出错,错误信息为ORA-55617。
清除一天以前的数据
清除特定SCN之前的数据
也可以把指定的表不再设置数据归档
或者是删除这个数据归档区
不过,如果放入了数据归档区的表,是不能执行如下操作的
·删除,重令名,或者修改列
·做分区或者子分区操作
·转换long到lob类型
·ALTER TABLE …… UPGRADE TABLE 操作
·drop、rename、trunacte表
如
上一篇说了oracle 11g中,add column的时候,其实并没有真正去修改以前的块,Oracle只不过采用了类似nvl(null,default value)的方法来处理这个问题,但是,如果再次去掉这个默认值,那会怎么样呢?
下面将做一个简单的实验,来说明这个问题,这里的实验,完全接着上一篇的实验,所以,具体情况,还是请先参考上一篇:Oracle 11g增加列,并带默认值的新特性
上一篇说到了,新添加的列,如果指定了默认值,并没有修改以前的块,读取以前的行的时候,可能发生一个转换过程。但是,如果对于已经设置过默认值的情况,插入新值的时候,这么默认值是怎么处理的呢:
之前的情况:
插入新记录:
可以看到,新插入的1000条记录,块的个数发生了非常大的变化,证明了在新的记录中,Oracle实际上是真正把默认值添加到块中去了。但是,只有以前的记录依然是没有值的,需要靠转换来完成。
现在有2000条记录,是分2次插入进去的,这个时候,如果去掉默认值,会发生什么情况?是一半有值,一半没有值,还是都有值呢?我们再看:
可以看到,虽然解除了默认值,块的个数也没有任何变化,以前的记录依然是没有真实的写入任何数值到块中的,但是,Oracle 依然能把以前的默认值显示出来,因为is null查不出来任何记录,而且查询记录就可以看到实际的值就是以前的默认值。
最后,再增加1000条记录,这个时候可以发现,因为去掉了默认值,现在在另外一个列上,写入的为null。
所以,对于整个过程分析下来,可以这么认为,oracle在add column default的时候,只是记录了一个标记,标记为这个点之前的所有块,如果是NULL的话,是需要转换的,反之取出实际的值。而这个点之后的块,就是按照实际的值来处理,如果中途反复修改,则以修改为准。
因为add column default,对于一个列,最多发生一次,所以,一个列只记录一个参照点即可。
但是,对于这个特性,有人想问,如果想保持以前的值为null,不要强行转换,但是,又想把新增加的列设置一个默认值,怎么办?其实也很简单,跟以前一样,分2步走即可,这样的话,以前的值还是null,新的值将为默认值。
老和尚在他的blog中描述了了这个问题,我这里做一个详细的测试来说明这个问题。
在oracle 11g以前,如果需要在一个表中执行类似如下的命令,而且这个表本身已经有很多数据,那么,这个操作将可能花费很长的时间,并且可能阻塞应用:
因为这个操作需要修改以前所有的行,并把他们都修改为默认值,如以上的0。但是,这个情况在oracle 11g中有了巨大的改变,oracle 11g中,如果对一个表增加一个列,并带有默认值,Oracle并没有真实的去修改以前的列,只不过通过查询的时候,采用类似NVL(null,新值)的方法转换一下,让以前的列看起来象有值一样。
这个过程在select 的时候就转换好了,所以,对于使用者看来,他们是有值的,这个细小的改动将大大减少这个语句的执行时间,使得这样的语句在oracle 11g中不会引起任何阻塞,更不会影响性能了。
下面看一个简单的对比说明:
首先是Oracle 10g的测试
可以看到的是,在增加默认值的列以后,该表的使用空间发生了巨大的变化,也证明数据库修改了以前的所有的块中的数据,让他们都生效。
以下是Oracle 11g的操作
这里可以看到,同样的记录,做了同样的操作,增加新列,并设置默认值以后,表的使用空间没有发生任何变化,也同样证明了Oracle没有修改以前的块中的数据。
这里的例子只有1000条记录,主要是为了体现了空间的变化。如果是几是万条,或者几百万条以上的表,同样的操作,oracle 11g是马上就结束了,不会有任何影响,而oracle 10g可能需要非常长的时间,这个时间表是被锁住的,不能执行任何DML操作,对于写频繁的应用来说,将会导致应用的阻塞。
没有什么特别的地方,记录一下,方便查找。
第一个用户Piner:
创建一个测试表
创建一个测试索引
如果是Oracle 10g以上,索引创建完成,就自带统计信息了。
创建一个表,存放export出来的统计信息
刚创建完成,记录数为0
收集表的统计信息
如果是oracle 10g以下,如9i,以上的分析是没有分析到索引的,可以在上面的分析中增加cacade=>true,或者是单独分析索引。
我们导出统计信息
切换到另外一个用户test
如果直接执行当前的用户与表名,可以执行成功,但是,没有统计数据导入,需要把原来的导出用户更新成导入用户。
然后再导入成功,导入信息包括表统计,索引统计信息,列的分析信息
kamus在他的blog 10gRAC培训 - 2 and last。说到了这个cpu time,具体可以看正文以及下面我与他的留言,他的意思其实就是:
CPU Time相对于其它等待事件,应当先忽略CPU Time,处理其它等待事件。而且cpu time高一般代表是好事情,因为系统并没有把时间耗费在Wait上。Elapsed Time = CPU Time + Wait Time,所以甚至我们可以说CPU Time越高越好。
不是说他的不对,只是比较觉得这句话太容易误导别人,所以,给一些补充建议,我同意如果有很明显的其它事件,而cpu time不明显的时候,可以优先处理其它事件。但是,还有以下2个地方需要注意:
1、cpu time高一般代表系统的逻辑读大,或者是高计算型的东西,如case函数,decode函数,自定义的计算类型函数等等,把cpu给耗光了,但是这个时候可能根本没有其它等待事件。这样是否证明这个系统很好呢?很可能是,非常不好,因为他很有可能没有必要有这么多的逻辑多,或者是,没有必要有这么多的cpu密集型计算就可以完成的任务,现在消耗这么CPU Time就是不正常的,很容易导致系统负载异常。
2、至于wait time,比如OLTP环境上最典型的db file sequential read引起的等待,是因为发生了物理io而引起的,而很多时候,物理读是随逻辑读增加而增加的,而逻辑读可能会导致cpu time高,也就是说,cpu time与wait time一般是同时增加的。特别是比较高访问量,大数据量,大SGA的系统,逻辑读与物理读都比较高,除了cpu time与db file sequential read,可能不会有很明显的其它等待事件,而优化的结果可能是cpu time与wait time同时减少。
既然说到了db file sequential read,也解释一下这个事件,与cpu time一样,很多时候说明系统是比较正常的,一个优化非常良好的系统,很可能第一个等待事件就是它。因为没有一个系统,不会发生任何物理IO,既然有物理IO,当然db file sequential read就是最好的了,一般表示读数据正常。同样的理由,db file sequential read大了,也可能预兆系统有不该有的物理读发生了。
如一个看起来很正常的sql语句,单个语句效率看起来并不差,执行时间已经小于0.01秒。假定原来逻辑读每个语句平均是100个,物理读平均10个,执行次数每小时50万次,优化完成以后,逻辑读降低为平均50个,物理读平均5个,那么,每小时降低的逻辑读总量就是50*50w=2500w个,降低的物理读为5*50w=250w个。那么再假定每个cpu每秒处理100000个逻辑读就达到了极限,每个物理读需要等待8ms,那么,就可以减少约2500w/100000*3600=7%的CPU使用率(单CPU),可以减少250w*8ms=20000秒的总io wait time。
同理,如果能采用同样的方法,减少执行次数从每小时50w到每小时25w,则收到的效果是一样的。
评价这个cpu time与db file sequential read是否正常,需要很多调优的经验,不过,需要记住的是,任何情况下,不要绝对的说好还是不好。最好的方式就是从statspack或者是awr上看看,排在cpu time,或者是物理读top的语句,他们是否应当有这么大的消耗,他们是否应当执行这么多的次数。