4 Nodes Oracle10g RAC on Linux x86-64

用时两天给客户安装完了4节点的Oracle10g RAC on Linux x86-64,使用了OCFS2存储数据文件以及ocr和voting disk。概括一下碰到的问题。

1. 基本上完全按照Oracle官方安装文档,但是其中kernel.shmall内核参数的设置,如果按照默认值2097152的话,最多只能使用到8G内存,当配置SGA过高的时候,就会在启动实例的时候报错。

SQL> startup nomount 
ORA-27102: out of memory
Linux-x86_64 Error: 28: No space left on device

需要将此参数值修改为shmmax/PAGE_SIZE值(通过getconf PAGE_SIZE获取),在此次实施中,客户机器为64G内存,PAGE_SIZE = 4096,因此应该设置kernel.shmall = 16475728。

2. 在安装CRS之前文档中要求运行rootpre.sh,但是却会报“No OraCM running”这样的错误。按照Metalink Note: 405986.1,这个错误可以忽略。

3. 安装CRS最后运行root.sh的时候,报错:
PROT-1: Failed to initialize ocrconfig
Failed to upgrade Oracle Cluster Registry configuration

重新mount OCFS2文件系统之后,再次运行root.sh,故障消失。

umount /u02/oradata/system
mount -L "vol_system" /u02/oradata/system -o nointr,datavolume

4. 服务端的Service Load Balance问题依旧,还是得将remote_listener参数置空之后,才能正常连接。

DUL is Life

系统情况如下:
1. Oracle版本是10.2.0.1,操作系统是Linux x86-64
2. 数据文件存储在OCFS2上
3. 需要恢复的表是普通表
4. 未知故障引起online日志文件损坏,使用隐含参数启动数据库之后,已经将大部分表通过exp导出到新库中,但是个别表无论是使用exp还是使用select都会报ORA-01555 snapshot too old错误,很明显回滚段数据存在不一致。

由于只有小部分数据无法导出,因此决定使用DUL直接从数据块中读取数据。

对于OCFS2文件系统无需特殊处理,在control.dul中按照路径写入系统表空间数据文件和故障表所处的用户表空间数据文件即可。

由于system表空间正常,数据字典都存在,因此unload table的过程很简单,bootstrap之后直接unload table即可。

这次unload出的表中最多记录数为580万多。

最后将生成的dat文件通过SQL Loader加载回新建的数据库中,对于中文的处理需要将操作系统NLS_LANG环境参数设置为跟数据库字符集相同。

本来这次想测试老熊的ODU执行效率,很可惜,在执行linux版本的odu时报无法找到某lib,因此作罢(由于时间充裕,在等待后续处理的过程中,将系统表空间文件和其中一个数据文件ftp到windows中,然后使用windows版本的odu测试了一下,unload table功能完全正常)。

Adaptive Cursor Sharing in Oracle Database 11g

还记得2007年时候遭遇过一次由于cursor_sharing = similar导致的系统问题,大量游标无法共享,产生巨大的version count,最终让整个系统崩溃。

在这个案例中我提到有4个条件导致了问题的发生:
1. cursor_sharing = similar
2. 收集了列上的histogram
3. SQL中使用到了此列作为条件,并且条件是“等于”
4. 这个SQL是没有绑定变量的

在最近Optimizer Development GroupWhy do I have hundreds of child cursors when cursor_sharing set to similar in 10g文章中又再次提到这个现象。

This is in fact the expected behavior when
1. CURSOR_SHARING is set to similar
2. Bind peeking is in use
3. And a histogram is present on the column used in the where clause predicate of query

在Oracle10g中这是正常的现象,如果在某列上收集了histograms信息,那么就等于告诉CBO这一列上的数据是不平衡的,如果都使用同一个执行计划那么就可能产生问题,因此对于每一个distinct值,CBO都会产生一个child cursor,这一点无法避免。当然,由于这是child cursor,因此比cursor_sharing = exact时候产生的parent cursor还是要节省内存空间,至少SQL语句本身不需要重复存储了。

在Oracle10g中解决方法是:
1. 去掉这列上的histograms统计信息,或者
2. 将CURSOR_SHARING = FORCE

虽然源于对Oracle Database的热爱,我们无条件接受了10g中这个方式,并且不认为这是bug,但是实际上心里一定暗暗骂过,傻啊,收集了histogram就要每个值产生1个cursor吗?如果是一样的执行计划何必要用不同的cursor空间呢?

我想Oracle自己也一定意识到了这点,于是在Oracle11g中这一切有了变化,Oracle推出了称为Adaptive Cursor Sharing(自适应游标共享)的游标共享机制,可以阅读这几篇相关文章。

Optimizer Development Group:Adaptive Cursor Sharing
Optimizer Development Group:Update on Adaptive Cursor Sharing
Arup Nanda:Adaptive Cursors and SQL Plan Management
Tim Hall:Adaptive Cursor Sharing in Oracle Database 11g Release 1

什么是Adaptive Cursor Sharing就不重复叙述了,上面的几篇文章说的非常清楚,那么ACS机制对于之前在10g中碰到的child cursor过多的情况有何种改善呢?

简单地说,在Oracle11g中我们可以保留cursor_sharing=similar并且也保留列上的histograms统计信息 [参考ADS with cursor_sharing] 应该设置cursor_sharing=force并收集倾斜列上的histograms统计信息,ACS机制将不会对每一个distinct值都产生一个child cursor,而是对每一个不同的执行计划产生一个child cursor,这大大减少了子游标的数量。这种处理方式无疑是合理的,只有在执行计划确实需要不相同的时候才产生额外的child cursor,当然,在bind peeking之后,CBO是否确实能够选择一个最优的执行计划那另当别论,是另外的话题。

注意,实际上产生的child cursor数量仍然是会大于execution plan数量的,也就是假如对于一个绑定变量的SQL一共有2种执行计划,那么child cursor数量会大于2,因为CBO始终在监控SQL的执行效率,如果认为变量的某一个真实值跟其它值的分布情况有很大的不同,那么CBO就会让这个SQL再做一次hard parse,这样就会产生出来一个新的child cursor,即使最终这个cursor的执行计划还是跟之前的相同。但是我们不用担心这些多余的cursor,因为这些cursor被标志为无法共享(可以通过v$sql.is_shareable字段得知),在需要的时候将会被age out出去。