Dec
15
2007
在Oracle10g就已经推出了Compressed Backupset。
There is some CPU overhead associated with compressing backup sets. If the database being backed up is running at or near its maximum load, you may find the overhead from using AS COMPRESSED BACKUPSET unacceptable. In most other circumstances, compressing backupsets saves enough disk space to be worth the CPU overhead.
今天在自己机器上的Oracle 11.1.0.6版本中测试了一下,压缩效果还是很让人满意的,不但存储空间变小,甚至备份所需要的时间也有所加快。
不使用压缩的备份:
backup database plus archivelog delete all input;
Size Elapsed Time
---------- ------------
652.77M 00:01:25
使用压缩的备份:
backup AS COMPRESSED BACKUPSET database plus archivelog delete all input;
Size Elapsed Time
---------- ------------
84.87M 00:00:48
在CPU并不是主要瓶颈的系统中,建议启动压缩备份。
Update:
Oracle11g中新增的zlib压缩算法和之前bzip2压缩算法之间的测试比较可以参看Oracle11g新特性:RMAN压缩备份 from Ningoo 。
Oracle 


RMAN 


Dec
14
2007
在之前的一篇 - Oracle 11g New Feature - Partition 文章中曾经提到虚拟列的概念,但是当时自己也有些疑问,今天在Oracle 11.1.0.6 上简单测试了一下。
- CREATE TABLE tb_v
- (col_1 number(6) not null,
- col_2 number not null,
- col_v as (col_1+col_2));
-
- -- 由于虚拟列的存在,所以即使指定了全部的实际列的值也会报值不足的错误
- SQL> insert into tb_v values(1,2);
-
- insert into tb_v values(1,2)
-
- ORA-00947: not enough values
-
- -- 虚拟列中不允许显示插入值
- SQL> insert into tb_v values(1,2,4);
-
- insert into tb_v values(1,2,4)
-
- ORA-54013: INSERT operation disallowed on virtual columns
-
- --必须明确指定列名,才能正常插入数据
- SQL> insert into tb_v(col_1,col_2) values(1,2);
-
- 1 row inserted
-
- --检索表,已经自动计算虚拟列的值
- SQL> select * from tb_v;
-
- COL_1 COL_2 COL_V
- ------- ---------- ----------
- 1 2 3
-
- --选取该行ROWID
- SQL> select rowid from tb_v;
-
- ROWID
- ------------------
- AAAEdcAAEAAAC3/AAA
-
- -- 获得该行数据存放得到数据文件号
- SQL> select dbms_rowid.rowid_relative_fno(row_id => 'AAAEdcAAEAAAC3/AAA') from dual;
-
- DBMS_ROWID.ROWID_RELATIVE_FNO(
- ------------------------------
- 4
-
- --获得该行数据存放的block号
- SQL> select dbms_rowid.rowid_block_number(row_id => 'AAAEdcAAEAAAC3/AAA') from dual;
-
- DBMS_ROWID.ROWID_BLOCK_NUMBER(
- ------------------------------
- 11775
-
- -- Dump这个数据块
- SQL> alter system dump datafile 4 block 11775;
-
- System altered
下面是dump内容的节选,可以看到确实只保存了两个字段,也就是虚拟列的值并没有存储在block中
block_row_dump:
tab 0, row 0, @0x1f8f
tl: 9 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] c1 02
col 1: [ 2] c1 03
end_of_block_dump
继续在虚拟列上创建索引,然后再看看索引的存储是否有不一样的地方。
- SQL> create index idx_v on tb_v (col_v);
-
- Index created
-
- -- 获得索引存储的文件号和block号
- SQL> exec show_space(p_segname_a => 'idx_v',p_type_a => 'INDEX');
-
- Total Blocks............................8
- Total Bytes.............................65536
- Unused Blocks...........................4
- Unused Bytes............................32768
- Last Used Ext FileId....................4
- Last Used Ext BlockId...................11777
- Last Used Blocks........................4
- Last Used BlockId.......................11780
- FIRST LEVEL BITMAP BLOCK................11777
- SECOND LEVEL BITMAP BLOCK...............11778
- PAGETABLE SEGMENT HEADER................11779
- FIRST Trans Data BLOCK..................11780
- Dump SQL: alter system dump datafile 4 block 11780;
Dump 索引块,下面是Dump内容的节选,c1 04就是3,因此可见在创建索引的时候,Oracle会先去计算虚拟列的值,然后再根据结果创建索引。
row#0[8024] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 04
col 1; len 6; (6): 01 00 2d ff 00 00
----- end of leaf block dump -----
实际上基于虚拟列的索引就是一个函数索引,可以从DBA_INDEXES.FUNCIDX_STATUS=’ENABLED’这个条件得到验证。
其它的一些测试可以参看Oracle11g新特性:虚拟列virtual column from Ningoo。
下一篇计划测试虚拟列的性能。
Oracle11g 


Virtual Column 


Dec
06
2007
这个问题的研究是一步一步来的。
最开始,客户想知道对于一个已经kill掉的数据库会话,如何评估SMON需要多久才能回滚成功这个会话之前做过的事务,其实也就是这个会话多久才会被完全kill掉。
由于被kill掉的会话所打开的事务已经无法在v$transation视图中查询到,因此需要从数据库基表x$ktuxe中查询。
- SELECT ktuxesiz FROM x$ktuxe WHERE ktuxesta != 'INACTIVE';
可以获得这个会话还在使用的undo block数量,然后过10秒钟,再查询一次,之后两次得到的数值相减,就是10秒内SMON回滚成功的undo block数量,这样再跟当前的ktuxesiz 值比较一下,就可以估算出大概还需要多长时间才能完成整个工作。
Metalink Note:43653.1详细描述了x$ktuxe的各列含义,Eygle的一篇文章也描述了这个方法。
然后,我在自己的机器上实验对这个基表的查询,忽然发现自己的机器上也有一个仍然active的transaction。但是我自己机器上的数据库我并没有做什么DML操作,为什么会有一个active transaction呢?这个transaction还使用了2个undo block。
- SQL> SELECT ktuxesiz FROM x$ktuxe WHERE ktuxesta != 'INACTIVE';
-
- KTUXESIZ
- ----------
- 2
继续检查自己机器上的情况,确实是有一个active的事务。
- SQL> select addr,xidusn,xidslot,xidsqn,status from v$transaction ;
-
- ADDR XIDUSN XIDSLOT XIDSQN STATUS
- -------- ---------- ---------- ---------- ----------------
- 45270E48 4 14 371 ACTIVE
查一下这个事务当前在执行什么SQL,SQL_ID是null(SQL_ID是Oracle10g以后才有的字段),也就是无从判断这个事务到底在做什么。
- SQL> select sid,username,sql_id,sql_hash_value from v$session where taddr='45270E48';
-
- SID USERNAME SQL_ID SQL_HASH_VALUE
- ---------- ------------------------------ ------------- --------------
- 132 SCOTT 0
其实后来发现虽然SQL_ID没有值,但是PREV_SQL_ID还是有值,并且通过这个值从v$sql中就可以查到刚才这个事务做了什么。
其实SQL是:DELETE FROM PLAN_TABLE WHERE STATEMENT_ID=:1
恩,没错,从PLAN_TABLE中删除记录,这是一条recursive sql。
当时并没有想到可以去查PREV_SQL_ID值(因为这个字段中查出来的SQL往往都是没太大意义的递归SQL),但是从username = scott上我个人可以判断基本上是因为我做了SQL的trace,因为当时我只登陆了scott用户,只运行过查看SQL执行计划的autotrace,那么因为autotrace功能其实就是使用了PLAN_TABLE表来存储中间结果,在显示完执行计划以后再删除相应记录。
所以如果Oracle在显示完执行计划,并且删除了PLAN_TABLE的相应记录以后,并没有做commit,那么就会有一个active transaction存在。但是这仅仅是一个猜测,如何验证呢?
可以想到的,是dump undo block,来查看里面到底存了什么。
- SQL> SELECT * FROM V$ROLLNAME WHERE USN = 4;
-
- USN NAME
- ---------- ------------------------------
- 4 _SYSSMU4_1195301203$
-
- --仅仅是为了查看undo block的dump,不需要dump出undo heander,这里只是给出语法
- SQL> ALTER SYSTEM DUMP UNDO HEADER "_SYSSMU4_1195301203$";
-
- System altered
-
- SQL> ALTER SYSTEM DUMP UNDO BLOCK "_SYSSMU4_1195301203$" XID 4 14 371;
-
- System altered
然后查看trace文件。找到如下这部分
* Rec #0x3 slt: 0x0e objn: 18002(0x00004652) objd: 18002 tblspc: 4(0x00000004)
* Layer: 11 (Row) opc: 1 rci 0x02
其中objn就是这个undo record上记录的相关对象ID,从dba_objects视图中就可以查到到底是什么了。
- SQL> select owner,object_name,object_type from dba_objects where object_id=18002;
-
- OWNER OBJECT_NAME OBJECT_TYPE
- ------------------------------ ------------------------------ -------------------
- SCOTT PLAN_TABLE TABLE
确实是SCOTTPLAN_TABLE,至此已经可以验证确实是因为set autotrace并且显示了执行计划之后产生了active transaction。
文章到这里其实就可以结束了,但是记得前面x$ktuxe基表中显示这个transaction需要2个undo block,那么下面就继续来看看是不是2个undo block以及为什么需要2个undo block。
上面这两个问题很简单。
1. 在trace文件中我们可以看到确实dump出了两个undo block,即使不去仔细看trace,从trace文件的最后总结也可以知道是2个。
Total undo blocks scanned = 2
Total undo records scanned = 8
Total undo blocks dumped = 2
Total undo records dumped = 8
2. 为什么是2个?因为1个undo block放不下delete PLAN_TABLE之后的记录前镜像。
undo 


x$ktuxe 


Dec
02
2007
收到一个命题,2TB容量的数据,1000并发,7*24的系统,如果就可维护性,可扩展性和系统性能几方面考虑,该如何进行系统设计。
这是一个很大的题目,牵涉到从硬件到软件,从应用设计到数据库设计的方方面面,足够写一本厚厚的书,其实,我们的梦想不就是有一个维护简单,扩展性良好,性能优秀的系统吗?
7*24意味着对于高可用性的要求严格,那么Oracle数据库在高可用性方面的选项包括哪些呢?
1. RAC
也许很多人仍然对于RAC抱有怀疑,就跟很多人对于RAC抱有迷信一样,持有RAC的性能还不如单节点这样论调的人跟持有性能不好实施RAC就能解决这样论调的人恐怕人数不相伯仲。
其实RAC在性能因素上对于应用的提升仅仅是一个方面,RAC对于高可用性的贡献才是真正无可替代的,目前我还不知道有任何其它一种技术可以当Oracle数据库的一个实例损坏的时候(比如主机的网卡出现故障或者主机根文件系统被充满导致机器没有响应等等)另外一个实例可以立刻顶上并提供服务。普通的HA做不到,Data Guard做不到,Streams也同样做不到。
RAC多节点能够提供数据库软件滚动升级,对于Oracle11g之前的数据库来说这个功能大大减少了系统down机时间,当然实际上Data Guard也可以做到这点,不过即使是Data Guard也仍然有一个Switchover的过程,这仍然需要更多一些的down机时间。
2. Data Guard
RAC的所有节点持有同样一份数据文件,那么对于RAC来说,致命的故障可能发生在盘阵的损坏或者连接盘阵的光纤交换机损坏,这种情况下有多少个节点也无济于事,因为数据文件出问题了。而Data Guard弥补的是这方面的需求,两个或者多个实例,两份或者多份存储,在一个实例一份存储坏掉的情况下,可以通过Failover或者Switchover命令来进行主备角色的互换。同时延时Apply功能在Oracle还没有大大增强Flashback的前几个版本中也同样有很大的实用价值。
3. Streams
个人认为Streams终将取代Advanced Replication,即使不提及Streams使用AQ技术而AR使用数据字典表来做延迟队列这两种技术的孰优孰劣,仅仅从最近几个版本的Oracle数据库对AR没有做任何加强这一点上也可以求得佐证。当然,物化视图的刷新由于其操作的简单性以及技术的成熟性在今后很长一段时间内应该还会继续成为多个数据库实例之间同步数据的有效手段。
4. Partition
为什么这里要提到分区?因为大多数人认为分区带来的是性能提升,但是实际上我们认为分区带来的最大好处是高可用性的提升,诚然,正确地使用分区以及分区索引会带来性能上的提升,带来扩展性的提升,但是即使这些不是我们考虑的问题,为了一个系统能够有优越的高可用性,仍然强烈建议使用分区技术来规划数据库。举一个最简单的例子,当我们要卸载历史数据的时候,分区的DDL操作比起对于整表数据的DML操作而言带来的高可用性的提升无疑是巨大的。
那么对于上面那样一个系统,我的建议数据库架构是双节点RAC + Physical Standby + Partition,也许应用只会使用到RAC中的一个节点,但是仍然需要RAC;也许这份健壮的存储永远不会坏,我们仍然需要Data Guard,至少RMAN备份不用占据产品数据库的资源;也许单表数据只有几G,即使索引全扫描也仍然可以接受,我们仍然要分区。
更加Detail的一些设计和维护准则:
1. 并发度1000,这并不代表会有1000进程同时操作同一个data block,所以对于表和索引的inittrans设计可以参考V$SEGMENT_STATISTICS视图中的ITL waits值,V$SEGMENT_STATISTICS是Oracle9i之后很有用的但是经常被大家忽略掉的性能视图。
2. Segment使用LMT且uniform size,避免system automatic size可能产生的空间碎片,这要求我们能够对于Segment的可能大小在设计阶段就又预估,大小相差悬殊的Segment分配到uniform size不同的表空间中去。
3. 对于高并发的操作在应用层面予以控制,详细的文章可以参见Piner的这篇 - 并发容易出现的问题和并发的控制。
4. 注意约束和索引之间的互相影响,对于一个业务繁忙,任何维护操作都可能是在业务繁忙期进行的系统,尽量避免约束和索引之间的相互影响。比如创建唯一性约束,我们可以先创建普通索引,再创建唯一性约束using index,这样操作的好处在于删除约束的时候不会影响索引,这里的关键思想是,约束用于控制商业逻辑,索引用于控制系统性能,逻辑和性能是要分开的,商业逻辑可能发生变化,然后性能不能因为商业逻辑的变化而受到影响。这小小的一点考虑却涵盖了可维护性,可扩展性和系统性能三个方面。
5. 如果分区表Local Index能够满足性能需求,那么首选Local Index,即使Global Index可能带来更少的Consistent Gets。因为Global Index最大的问题是分区操作时候必须rebuild index,通常这在性能和可维护性上都无法接受。
6. 使用Oracle10g吧,从Oracle10g到Oracle11g,高可用性的提升有目共睹,各种online操作增强,各种阻塞的影响面减少,各种性能诊断工具的易用性,不是说9i不好,而是10g更强(这句话说的太像Oracle员工了,抱歉)。
高可用性 

