2010-03-06 Sat
在过去的6年间,我在北京做过不少公开的活动,将我有限的经验与知识分享出去,这些活动每次都有很多新的面孔出现,有些成为我的朋友,有些真的就踏上了DBA之路,这些积极的促进是我一直乐于去做这样活动的主要原因。
可是做一点"公益"的事情并不容易,直到最近,当我觉得可以解决这其中的所有问题之后,这一切成为可能。
ACOUG 正是基于这样一件事情我们发起的一个站点,ACOUG的含义是All China Oracle User Group,这个名字太过大了,存粹是为了定义这样一个域名而得来的,所以请不要计较我们最终能够涉及到多少产品与内容,我们只是想尽力去做一件想了很久而一直没有做的事情。
所以要做一个用户组,是因为在几次去美国期间,在OOW上见到各个国家或地区的Oracle用户组组织了非常多的活动,而国内最活跃的是论坛,ITPUB.NET是首屈一指的,但是国内没有类似国外的用户组的组织。CNOUG也是一个非常不错的地方,但是CNOUG实际上是另外一个ITPUB,以论坛为主的社区,而社区也正是一个中国的特色。
ACOUG,其实开始我想也许成为BJOUG可能会更为确切,因为我们的初始活动可能只能在北京开始尝试。只是后来借鉴了一个印度的新闻组域名,得来了ACOUG的名字。
ACOUG,首先我们并不会做论坛,ITPUB在Oracle技术方面,在国内已经无可超越,技术问题的探讨那里仍然是最为合适的地方,我们想做的是一些地面活动,一直以来,我想搭建一个平台,那些热爱技术的、有一技之长的朋友,可以到这个平台上来演讲、分享、交流,我们通过这个平台提供一个分享和展现的机会,如果你乐于分享,并且享受过程,那这里就是你的舞台;而对于那些刚刚开始学习Oracle技术,又想接触和深入了解一下这个圈子的朋友,在这个平台下,我们为你准备好了位置,你可以来聆听和探讨。
ACOUG,这个站点的存在意义,最终我们设计将这个站点做成一个"技术博客",我们希望邀请那些国内数据库领域的爱好者们加入,会有一些简单的规则,大家可以定期提供一些自己深入研究的技术文章,将这个站点作为一个统一的展现平台聚合起来,这个作用和国外的很多站点类似。这样的一个想法,没有什么新奇之处,我们只是希望,能够在朋友们的支持下,做一点新的事情、做一点有益的事情,基于爱好,基于那一直存在的理想主义。
这个想法,在年初和Kamus提起时,两个人达成了惊人的一致,就连想到的ACOUG的名字都是同样的,然后Kamus尝试用不同的程序搭建了网站的后台,最后或者说暂时我们选择了WP。Kamus在这件事情上投入了很多精力,感谢他!
搭建这个平台,我想,其实北京有众多的技术高手,如果每个人都能够分享一个主题,那么每两个月搞一次活动,我想应该是不难的,而以前一直存在的场地、费用问题,现在有我的恩墨科技做一点支持,靠朋友们的一点赞助,以及来自Oracle官方的一些支持,这些问题不再存在。
有时候我们不去做一件事情的借口是忙,事实上不是,我想即便我自己每个月抽出一两天,花费1~2小时去分享一个技术主题是非常容易的,唯一的借口是我们的懒惰。另外一个问题是,很多人不愿意为没有收益的事情付出,而我的观点是,有付出一定是有回报的,虽然这个回报可能在很久之后。而我愿意做这件事,更主要的是如前所述,在赤裸裸的为了追逐金钱而努力之外,我们还一直保有一点理想主义,我相信大家都有。如果缺少一个组织者,那我们愿意来试试看。
在我们这个消息传出去之后,我在美国认识的一位ACE Director - Ameed Taylor 已经发来邮件说愿意到现场来支持我们的活动,我说给点时间我们尝试一下,如果ACOUG能够发展下去,我希望有机会请更多的人来北京,或者在外地开展活动。
最后,我想,也许会有人质疑我们关于"公益"的动机,那么是的,我心里面窃窃的以为,如果我们搞的成功,那么也许我们这个舞台可以让一些具有真正技术的人凸显出来,所以乐于分享的人,也许会有些意想不到的收获,当然这些活动的组织者,也许有机会在更广泛的领域为业者所知,我说的有付出就一定有回报,某种程度上与此有关。而如果组织有价值,活动有价值,其他的交给时间吧。
在我的设想里,以后,我不是主要的演讲者了,越来越多的年轻人、技术专家涌现出来,如果你们愿意,这里有你的位置,当然我们目前还无法给出报酬。
第一次活动我们定在了3月20日,时间有点紧张,我的意思是,给我们一点压力,让这件事情尽快动起来,有开始才有未来,我跟Kamus说,行动有时候比思想更重要。
好了,这个活动,对于参与者,也许唯一的要求是一个详尽的注册流程,我们希望,我们的每一次活动所抵达的地方和人群都能够被记录下来,这是对我们这些尝试的鼓励和纪念。
关于ACOUG的网站,由于我们都不是专业的人士,如果有朋友碰巧懂得PHP或WP运用得好,我们诚挚的邀请志愿者加入这个站点的维护工作,谢谢。
就写这么多,让我们动起来吧!
-The End-
相关文章|Related Articles
- 2009 北京 - 继续暂住在我自己的房子里
- 我的个人Eygle新闻组 - 欢迎读者、朋友加入
- 结束《深入解析Oracle》技术访谈交流会
- 北飞的候鸟-Kamus北京庭审现场
- 一场即将到来的费解官司-声援Kamus
评论数量(1)|Add Comments
本文网址:http://www.eygle.com/archives/2010/03/acoug_starting.html
有感于国外Oracle用户组的发达,我跟eygle从今年开始尝试组建中国的Oracle用户组,All China Oracle User Group。我们的站点是acoug.org。
我们希望能够为全中国的Oracle技术爱好者提供一个交流与活动的平台,我们希望能够激发更多人对于Oracle技术以及相关知识的兴趣,我们希望沉浸在这些技术中的人员获得更多的乐趣。
我们认识到中国目前掌握Oracle技术的人员广度和深度都跟美国、欧洲甚或是印度存在着较大差距,这需要我们更有热情的去付出,但愿在不久的将来ACOUG在全球Oracle用户组中占据一席之地。
ACOUG计划定期举行线下活动,而线下活动也将是ACOUG未来工作的重点,邀请著名的业内人士(不仅限于国内)来进行主题演讲,并围绕相关主题进行广泛的讨论从而使更多人获益。
预计在这个月的3月20日(周六)开展ACOUG第一次线下活动,详细的地点、场地以及演讲主题还未确定,但是请有兴趣的朋友时刻关注ACOUG网站,欢迎参加。
2010-03-05 Fri
看到Kamus对SQLULDR2的留言后, 破有感触. 人们应当比较关注, 他们想要的功能用起来方便是否, 关键并不在于功能的多少. 而SQLULDR2的众多的命令行选项, 也确实有些让人发晕, 包括我自已.
为了方便大多数人使用, 简化了SQLULDR2的命令行帮助, 简化到如下所示.
SQL*UnLoader: Fast Oracle Text Unloader (GZIP), Release 3.0.1
(@) Copyright Lou Fangxin (AnySQL.net) 2004 - 2010, all rights reserved.
Usage: SQLULDR2 keyword=value [,keyword=value,...]
Valid Keywords:
user = username/password@tnsname
sql = SQL file name
query = select statement
field = separator string between fields
record = separator string between records
read = set DB_FILE_MULTIBLOCK_READ_COUNT at session level
sort = set SORT_AREA_SIZE at session level (UNIT:MB)
hash = set HASH_AREA_SIZE at session level (UNIT:MB)
array = array fetch size
rows = print progress for every given rows (default, 1000000)
file = output file name(default: uldrdata.txt)
log = log file name, prefix with + to append mode
text = output type (MYSQL, CSV, MYSQLINS, ORACLEINS, FORM, SEARCH).
parfile = read command option from parameter file
for field and record, you can use '0x' to specify hex character code,
\r=0x0d \n=0x0a |=0x7c ,=0x2c, \t=0x09, :=0x3a, #=0x23, "=0x22 '=0x27
对于专家而言, 可以用如下方式得到以前全部的命令行选项.
sqluldr2 help=yes
通过引入一个TEXT选项, 来针对不同格式的导出进行相关选项的设置, 不仅方便了大家使用, 也可以对SQLULDR2的功能有一个很直接的了解, 例如SQLULDR2可以导出数据给MySQL用, 或导出成Excel可以打开的标准CSV文件, 或是生成MySQL和ORACLE上的INSERT语句, 也可以按列显示记录, 或为一些特殊的搜索程序生成数据源.
再次感谢Kamus的好建议, 今年是支付宝的用户体验年, 应当从用户角度进行反思.
Relative Posts:
本文主要翻译自Jonathan Lewis的Blog Entry Log File Switch, 最后关于checkpoint部分,我添加了部分我自己的注释(以斜体字显示).
日志文件切换
几天前,我发布一个简单的查询语句,它通过查询v$log_history视图展示日志文件切换之间的时间间隔.如果你运行这个脚本,并且认为你的系统的日志文件切换频率不合适,那么你该如何处理呢?
如果时间间隔太短(由于日志文件频繁切换引发的checkpoint动作可能会导致DBWR进程过于活跃),可以通过新增新的更大的日志文件并删除旧的日志文件来解决.
如果切换的时间间隔太久,或者是时间间隔波动太大,而你希望使日志切换更加有规律,那么可以使用参数archive_lag_target(在Oracle 9i中引入)来为日志文件切换设置一个超时值(单位为秒).如果日志文件没有在指定的时间间隔内发生切换,那么系统会强制其切换日志,并且归档对应的已经使用的在线重做日志.
在此之前,人们一般使用类似于cron或者dbms_job一类的工具来实现(通过执行一条”alter system switch logfile“命令).从Oracle 9i开始,利用这个参数来实现就简单多了.
附录
- Instance Recovery Checkpoint
- Media Recovery Checkpoint
- Thread Checkpoint
- Interval Checkpoint
- Tablespace Checkpoint
- PQ Tablespace Checkpoint
- Close Database Checkpoint
- Incremental Checkpoint
- Local Database Checkpoint
- Global Database Checkpoint
- Object Reuse Checkpoint
- Object Checkpoint
实例恢复触发的检查点
介质恢复触发的检查点
单个instance关闭以及log file switch触发的检查点
log_checkpoint_timeout参数超时触发的检查点
表空间online/offline/read only/read write操作对应的检查点
不清楚具体原因
常规的检查点动作
对应于alter system checkpoint
对应于alter system checkpoint all命令的检查点.
对应于truncate table操作的检查点
对应于drop table的检查点操作
Oracle支持多种不同类型的checkpoint,这个列表会随着Oracle版本的不同而有所不同.Oracle 10.2.0.3的对应的checkpoint看似有如下这些:
在这些中间,我认为日志文件切换时引发的checkpoint可能是ThreadCheckpoint.
No related posts.
2010-03-04 Thu
本文完全参考MySQL Manual,毫无新意。
从MySQL5.5之后,版本的信息会像这个样子:MySQL-5.5.2-m2,Why?
以前MySQL开发进程是将大量特性加入到MySQL代码库进行测试开发,然后分发5.1.0……5.1.44等版本。缺点是某个小特性(代码)的测试有可能会影响到整个版本。这也是MySQL6.0迟迟没有RC的一个原因。
现在使用“里程碑模式”(milestone mode),而每一个milestone版本则仅关注某一小部分特性进行开发测试,这样可以让MySQL能够更快的放出对应的RC。下一个milestone则在原来(上一个milestone)基础上进行开发,仅关注某一小部分特性进行开发和测试,并对这一小部分特性进行全面、彻底的测试。
例如,MySQL 5.5.0-m2 是Milestone 2的第一个版本。该milestone专注于代码基本的稳定性。在m2发展历程中,我们还会看到MySQL 5.5.1-m2,MySQL 5.5.2-m2等。
为什么不是m1呢?(认为5.4就是m1)。
© orczhou for 一个故事@MySQL DBA, 2010. |
Permalink |
No comment |
Add to
del.icio.us
Post tags: MYSQL
Feed enhanced by Better Feed from Ozh
为了查询出保存在员工表(SCOTT.EMP)中, 每个部门工资最高的三个人, 如果是Oracle数据库, 大家可以使用Windows分组汇总函数来轻松地实现, 如下所示.
SELECT * FROM (
SELECT DEPTNO, EMPNO, ENAME, SAL,
RANK() OVER (PARTITION BY DEPTNO ORDER BY SAL DESC) RNK
FROM EMP ) WHERE RNK <= 3
但如果员工表存放在MySQL数据库, 或其他数据库, 如SQLLite中, 要实现同样的功能, 就比较复杂了, 至少我现在都还不会. 但利用DataReport以前开发的功能, 及刚增加的条件过滤功能, 就可以轻松实现这个需求.
webchart.query_1=select deptno, empno, ename, sal from emp
webchart.express_1=rank|x|rnk::sal|deptno
webchart.filter_1=3.5-x|rank
webchart.sort_1=deptno,rank
webchart.group_1=1
如果Filter中的公司算出来的值小于0, 那么这条记录就会被删除, 在这个例子中, 如果排名这一列的值大于3, 这个公式算出来的值就为负数, 所以只保留了前三名, 达到了我们的业务要求. 页面输出如下所示的表格:
deptno empno ename sal rank 10 7839 KING 5000.0 1 7782 CLARK 2450.0 2 7934 MILLER 1300.0 3 20 7788 SSCOTT 3000.0 1 7902 FORD 3000.0 2 7566 JONESS 2975.0 3 30 7698 BLAKE 2850.0 1 7499 ALLEN 1600.0 2 7844 TURNER 1500.0 3
将这些处理放在应用服务器端实现, 不仅让SQL变得通用, 如果访问频率极高, 还可以减轻数据库端的压力.
Relative Posts:
Votedisk can’t be add & remove while CRS is running, or else it would corrupt something.
OCR can be added & replaced while CRS is running.
ENV: Oracle Clusterware 10.2.0.4
Detailed logfile:
While CRS is still running…
# ./crsctl add css votedisk /dev/rdsk/ c4t60060E80056F160000006F1600000669d0s1
Cluster is not in a ready state for online disk addition
# ./crsctl add css votedisk /dev/rdsk/ c4t60060E80056F160000006F1600000669d0s1 -force
Now formatting voting disk: /dev/rdsk/ c4t60060E80056F160000006F1600000669d0s1
successful addition of votedisk /dev/rdsk/c4t60060E80056F160000006F1600000669d0s1.
# ./crsctl query css votedisk
0. 0 /dev/rdsk/c4t60060E80056F160000006F1600000469d0s1
1. 0 /dev/rdsk/c4t60060E80056F160000006F1600000669d0s1
located 2 votedisk(s).
Looks good, continue add another one.
# ./crsctl add css votedisk /dev/rdsk/c4t60060E80056F160000006F1600000869d0s1
Cluster is not in a ready state for online disk addition
# ./crsctl add css votedisk /dev/rdsk/c4t60060E80056F160000006F1600000869d0s1 -force
Now formatting voting disk: /dev/rdsk/c4t60060E80056F160000006F1600000869d0s1
successful addition of votedisk /dev/rdsk/c4t60060E80056F160000006F1600000869d0s1.
It’s corrupted. Entry 1 and entry 2 both point to “*869d0s1”.
# ./crsctl query css votedisk
0. 0 /dev/rdsk/c4t60060E80056F160000006F1600000469d0s1
1. 0 /dev/rdsk/c4t60060E80056F160000006F1600000869d0s1
2. 0 /dev/rdsk/c4t60060E80056F160000006F1600000869d0s1
located 3 votedisk(s).
Has to stop CRS on all nodes.
# ./crsctl stop crs
Stopping resources. This could take several minutes.
Successfully stopped CRS resources.
Stopping CSSD.
Shutting down CSS daemon.
Shutdown request successfully issued.
Then I want to delete corrupted entry 1 and entry 2.
# ./crsctl delete css votedisk /dev/rdsk/c4t60060E80056F160000006F1600000869d0s1
Cluster is not in a ready state for online disk removal
# ./crsctl delete css votedisk /dev/rdsk/c4t60060E80056F160000006F1600000869d0s1 -force
no votedisk found matching path specified /dev/rdsk/c4t60060E80056F160000006F1600000869d0s1.
It shows “0” for entry 1 and entry 2.
# ./crsctl query css votedisk
0. 0 /dev/rdsk/c4t60060E80056F160000006F1600000469d0s1
1. 0 0
2. 0 0
Add another 2 votedisk while CRS is down.
# ./crsctl add css votedisk /dev/rdsk/c4t60060E80056F160000006F1600000669d0s1 -force
Now formatting voting disk: /dev/rdsk/c4t60060E80056F160000006F1600000669d0s1
successful addition of votedisk /dev/rdsk/c4t60060E80056F160000006F1600000669d0s1.
# ./crsctl add css votedisk /dev/rdsk/c4t60060E80056F160000006F1600000869d0s1 -force
Now formatting voting disk: /dev/rdsk/c4t60060E80056F160000006F1600000869d0s1
successful addition of votedisk /dev/rdsk/c4t60060E80056F160000006F1600000869d0s1.
# ./crsctl query css votedisk
0. 0 /dev/rdsk/c4t60060E80056F160000006F1600000469d0s1
1. 0 0
2. 0 0
3. 0 /dev/rdsk/c4t60060E80056F160000006F1600000669d0s1
4. 0 /dev/rdsk/c4t60060E80056F160000006F1600000869d0s1
located 5 votedisk(s).
Delete “0” votedisk. Looks good.
# ./crsctl delete css votedisk 0 -force
successful deletion of votedisk 0.
# ./crsctl query css votedisk
0. 0 /dev/rdsk/c4t60060E80056F160000006F1600000469d0s1
1. 0 0
2. 0 /dev/rdsk/c4t60060E80056F160000006F1600000669d0s1
3. 0 /dev/rdsk/c4t60060E80056F160000006F1600000869d0s1
located 4 votedisk(s).
# ./crsctl delete css votedisk 0 -force
successful deletion of votedisk 0.
# ./crsctl query css votedisk
0. 0 /dev/rdsk/c4t60060E80056F160000006F1600000469d0s1
1. 0 /dev/rdsk/c4t60060E80056F160000006F1600000669d0s1
2. 0 /dev/rdsk/c4t60060E80056F160000006F1600000869d0s1
located 3 votedisk(s).
Want to add mirrored OCR while CRS is down. It reports error “PROT-1”.
# ./ocrconfig -replace ocrmirror /dev/rdsk/c4t60060E80056F160000006F1600000669d0s5
PROT-1: Failed to initialize ocrconfig
After start CRS on all nodes. Mirrored OCR can be added.
# ./ocrconfig -replace ocrmirror /dev/rdsk/c4t60060E80056F160000006F1600000669d0s5
# ./ocrcheck
Status of Oracle Cluster Registry is as follows :
Version : 2
Total space (kbytes) : 1151724
Used space (kbytes) : 4608
Available space (kbytes) : 1147116
ID : 1986342521
Device/File Name : /dev/rdsk/c4t60060E80056F160000006F1600000469d0s5
Device/File integrity check succeeded
Device/File Name : /dev/rdsk/c4t60060E80056F160000006F1600000669d0s5
Device/File integrity check succeeded
Cluster registry integrity check succeeded
# cat /var/opt/oracle/ocr.loc
#Device/file getting replaced by device /dev/rdsk/c4t60060E80056F160000006F1600000669d0s5
ocrconfig_loc=/dev/rdsk/c4t60060E80056F160000006F1600000469d0s5
ocrmirrorconfig_loc=/dev/rdsk/c4t60060E80056F160000006F1600000669d0s5
local_only=false#
[detached]
2010-03-03 Wed
最近又遇到类似错误,错误出现在INSERT操作时,错误出现,进程crash,任务失败,重新执行可以通过。
kcbgtcr 是Oracle数据库最重要的函数之一,其含义为:Kernal Cache Buffer GeT Cosistents Read,也就是数据库的一致性读操作,后面的代码有很多种,代表在不同的层面上出现问题。
Metalink 的 Note 415773.1 - Diagnostics and Solutions for kcbgtcr() Related Internal Errors记录了与此相关的很多问题。
不讨论具体的问题,根据代码的含义实际上可以知道,出现这类错误,基本上都是由于CR读异常导致的,CR读涉及的各个层面出现问题,如DataBlock,Undo Header,Undo Block出问题,都可能导致异常。
kcbgtcr_13号错误是指在构造一个CR读时,检查Buffer时发现其SCN不可用,判断出错导致代码异常,进程Crash掉,这类错误可能是Buffer过小,重用过快导致的,也可能是数据变更过于频繁导致。
这类错误极其少见,一旦出现要非常慎重的处理,有些Bug与此有关,需要通过Metalink确认,数据库在部署时最好应用最新的PSU。
下面是这次故障的错误堆栈摘要:
*** 2010-03-03 14:15:04.436
ksedmp: internal or fatal error
ORA-00600: internal error code, arguments: [kcbgtcr_13], [], [], [], [], [], [], []
Current SQL statement for this session:
INSERT INTO CT_INFO (RPT_DATE, RGN_CODE, .......
----- PL/SQL Call Stack -----
object line object
handle number name
700000206d666a0 338 procedure CT_INFO_S
7000001a89a3f30 3 anonymous block
----- Call Stack Trace -----
calling call entry argument values in hex
location type point (? means dubious value)
-------------------- -------- -------------------- ----------------------------
ksedst+001c bl ksedst1 FFFFFFFFFFED73C ? 000000006 ?
ksedmp+0290 bl ksedst 104A48040 ?
ksfdmp+0018 bl 03F326DC
kgerinv+00dc bl _ptrgl
kgeasnmierr+004c bl kgerinv 000000000 ? 10566823C ?
100000013 ? 225D0C00130000 ?
000000000 ?
kcbassertbd+0074 bl kgeasnmierr 1101955E0 ? 110450040 ?
105668AC4 ? 000000000 ?
000000000 ? 700000206F807C0 ?
000000000 ? 000000051 ?
kcbgtcr+2a68 bl kcbassertbd 105668AC0 ? FFFFFFFFFFEC608 ?
ktspgfbs+0144 bl kcbgtcr 102147B38 ? 000000000 ?
70000002EB3F448 ? 000000001 ?
ktspfsrch+00b8 bl ktspgfbs FFFFFFFFFFEE028 ? 000000000 ?
000000000 ? 000000000 ?
1101FFEF8 ? FFFFFFFFFFEDA78 ?
000000000 ?
ktspscan_bmb+021c bl ktspfsrch 700000010018078 ?
FFFFFFFFFFEE028 ?
ktspgsp_cbk1+07c4 bl ktspscan_bmb 1FE800000001 ?
ktspgsp_cbk+00a8 bl ktspgsp_cbk1 1130D0A00 ? 000000000 ?
1028F3668 ? FFFFFFFFFFEDF40 ?
11022A548 ? 110266D40 ?
000000000 ? 000000014 ?
kdtgsp+0504 bl ktspgsp_cbk 000000000 ? 000000000 ?
000000000 ? 000000000 ?
000000000 ? 000000000 ?
000000000 ? 000000000 ?
kdtgsph+02f8 bl kdtgsp 10500E820 ? 110195760 ?
kdtFlushBuf+0288 bl kdtgsph 1105F8E40 ? 000000000 ?
insflush+0348 bl kdtFlushBuf 1105F8E40 ?
insrow+0384 bl insflush 1105F8E40 ? 000000000 ?
1101BECF0 ? FFFFFFFFFFF13E0 ?
2C000100000004 ?
insdrv+0428 bl insrow 1105F8E40 ? FFFFFFFFFFF13E0 ?
000000000 ?
inscovexe+02b8 bl insdrv 1105F8E40 ?
insExecStmtExecIniE bl 01FA0954
ngine+005c
insexe+02f8 bl insExecStmtExecIniE FFFFFFFFFFF2318 ?
ngine FFFFFFFFFFF2310 ? 110527020 ?
opiexe+2738 bl insexe 1105942B8 ? FFFFFFFFFFF2978 ?
opipls+185c bl opiexe FFFFFFFFFFF3CC0 ?
FFFFFFFFFFF3DA8 ?
FFFFFFFFFFF3C60 ?
opiodr+0ae0 bl _ptrgl
rpidrus+01bc bl opiodr 66FFFF5A80 ? 6025E14E0 ?
FFFFFFFFFFF6B80 ? CE9A84B20 ?
skgmstack+00c8 bl _ptrgl
rpidru+0088 bl skgmstack 10233AE20 ? 000000000 ?
000000002 ? 000000000 ?
FFFFFFFFFFF6348 ?
rpiswu2+034c bl _ptrgl
rpidrv+095c bl rpiswu2 70000020458E188 ? 11052E3A0 ?
11046AA58 ? 000000000 ?
FFFFFFFFFFF6120 ?
3C00000000 ? 000000000 ?
000000000 ?
psddr0+02bc bl 03F32174
psdnal+01d0 bl psddr0 CFFFF6DB8 ? 6600000000 ?
FFFFFFFFFFF6B80 ?
30100BA3A8 ?
pevm_EXECC+01f8 bl _ptrgl
pfrinstr_EXECC+0070 bl pevm_EXECC 70000019DB5AC60 ? 000000000 ?
7000001C12D897A ?
pfrrun_no_tool+005c bl _ptrgl
pfrrun+1014 bl pfrrun_no_tool FFFFFFFFFFF6EE0 ?
7000001A89A3F30 ? 3100EAA30 ?
plsql_run+06b4 bl pfrrun 11048A228 ?
peicnt+0224 bl plsql_run 11048A228 ? 1000000000418 ?
000000000 ?
kkxexe+0250 bl peicnt FFFFFFFFFFF81F8 ? 11048A228 ?
opiexe+2ef8 bl kkxexe 110483218 ?
kpoal8+0edc bl opiexe FFFFFFFFFFFB814 ?
FFFFFFFFFFFB588 ?
FFFFFFFFFFF99E8 ?
opiodr+0ae0 bl _ptrgl
ttcpip+1020 bl _ptrgl
opitsk+1124 bl 01FA3344
opiino+0990 bl opitsk 000000000 ? 000000000 ?
opiodr+0ae0 bl _ptrgl
opidrv+0484 bl 01FA2198
sou2o+0090 bl opidrv 3C02DB56BC ? 44065F000 ?
FFFFFFFFFFFF750 ?
opimai_real+01bc bl 01F9FAB4
main+0098 bl opimai_real 000000000 ? 000000000 ?
__start+0098 bl main 000000000 ? 000000000 ?
--------------------- Binary Stack Dump ---------------------
-The End-
相关文章|Related Articles
- ORA-00600 3020 错误案例一则
- ORA-600 kcbzpbuf_1 坏块的恢复案例一则
- ORA-600 17285 错误 与 PL/SQL Developer
- Oracle HowTo: How to deal with Ora-600 4193 error
- Oracle Diag:如何处理ORA-600 2662错误
评论数量(0)|Add Comments
本文网址:http://www.eygle.com/archives/2010/03/kcbgtcr.html
换手机号码了,原号码永久保留电话功能,不再支持短信功能;
新号码,要知道我新号码,可以继续打原来号码问我的,嘿嘿。

最近有同事向我求救:Netscaler 管理IP配置老是失败,问我到底怎么配。他提供了如上的错误页面,这个页面提示IP错误,具体啥错误无法从这里看出,我让他再确定下IP地址是否可用,答案是肯定的,而且有一台服务器已经配置了同一段的IP地址,可用访问。我按照他的方法在GUI上配置了一遍,一样报错。
我开始以为是GUI上不能配置管理IP,虽然我以前经常这么配,但这个错误让我开始对之前的操作持怀疑态度。于是决定尝试在CLI下进行配置:
ERROR: Invalid argument
返回一样的错误,我纳闷了。最终我决定修改Netscaler配置文件/nsconfig/ns.conf,因为这是最直接的,但是很遗憾,修改完成后重启发现配置居然恢复到默认的配置了,非常无语-_-
我再次修改ns.conf,但这次并没有选择粗暴的reboot,而是手动执行每一步,命令如下:
(危险动作,切勿在生产环境模仿)
#nsstart.sh
Reading the NetScaler configuration from the file /nsconfig/ns.conf
ERROR: NSIP is a network address, falling back to defaults.
$initpe()=FFFFFFFF
0 bytes in 0 blocks
Startup failed - writing dmesg to the log file...
终于明白是什么错误了,原来netmask应该是255.255.255.224,结果他一直在使用255.255.255.254,我也没怀疑过,回过头一想确实满搞笑的,254是啥掩码,呵呵:)
这个问题说明了Netscaler在GUI的错误输出上的一些不人性化,同时也让我第一次尝试用这种方式来调试这个问题。
你还可以在这里看到本文章:http://www.sapub.net/html/y2010/netscaler-err-mgmt-ip.html
Related posts:
- NetScaler — How to Configure NetScaler to Utilize NTP for Clock Synchronization
- NetScaler — File System and Directory Structure
- NetScaler --How do I configure RNAT for specific hosts?
推荐几个ronald bradford发布在SlideShare上的ppt.
No related posts.
2010-03-02 Tue
正文主要来自MynoSQL网站.
ILoggable 博客提出了6非常有趣的问题, 这些问题对于决定使用新的存储解决方案(是否NoSQL并不重要)的项目都有一定的参考意义.
- 1. 可以诊断其中的性能问题吗?
- 2. 基于非主键查找的并发性如何?
- 3. 有哪些工具可以用来帮助恢复损坏的数据文件?
- 4. 有什么样的备份策略?
- 5. 如何确认备份是有效的?
- 6. 系统管理员是否认同这一点?
每一个RDBMS都一定的剖析工具以及相关的方法来诊断其性能问题..
例如: Oracle提供了Wait Interface以及基于10046/10053的诊断事件来分析Oracle的性能问题.
在任何RDBMS系统中,都有工具可用来帮助恢复损坏的数据文件或者索引文件.
大部分数据库都有非阻塞模式的数据备份方式. 几乎所有RDBMS都支持复制功能. 都有有效的机制来做备份.
例如: Oracle支持适用Rman做备份, 适用DataGuard做数据库物理/逻辑复制.
是否有工具或者其他手段帮助你确认复制是有效的并且是最新的, 而且并没有将损坏的数据复制进去.
如果你认为你不需要关系所有这些问题, 可能是有其他人已经帮你做好这些事情了.
你期望的NoSQL方案有如上这些问题的答案吗?
No related posts.
最近遇到某省的legato备份问题,这个问题在春节后一来就遇到了。在legato界面,我们看到的报错是:
02/24/10 12:01:00 nsrd: savegroup info: starting db_arch (with 1 client(s))
02/24/10 12:01:15 nsrd: Jukebox 'msl6000' failed: Input/output error
02/24/10 12:01:15 nsrd: Jukebox 'msl6000' failed: Input/output error
02/24/10 12:01:53 nsrd: Jukebox 'msl6000' failed: No such file or directory
02/24/10 12:01:53 nsrd: Jukebox 'msl6000' failed: No such file or directory
02/24/10 12:01:54 nsrd: media info: suggest mounting QWB507L2 on ah-db01 for writing to pool 'miscdb'
02/24/10 12:01:54 nsrd: media waiting event: Waiting for 1 writable volumes to backup pool 'miscdb' tape(s) on ah-db01
02/24/10 12:01:56 nsrd: Jukebox 'msl6000' failed: No such file or directory
02/24/10 12:01:56 nsrd: Jukebox 'msl6000' failed: No such file or directory
02/24/10 12:02:05 nsrd: Jukebox 'msl6000' failed: Input/output error
02/24/10 12:02:05 nsrd: Jukebox 'msl6000' failed: Input/output error
02/24/10 12:02:14 nsrd: Jukebox 'msl6000' failed: Input/output error
02/24/10 12:02:14 nsrd: Jukebox 'msl6000' failed: Input/output error
02/24/10 12:02:21 nsrd: Jukebox 'msl6000' failed: Input/output error
02/24/10 12:02:21 nsrd: Jukebox 'msl6000' failed: Input/output error
02/24/10 12:02:40 nsrd: Jukebox 'msl6000' failed: Input/output error
02/24/10 12:02:40 nsrd: Jukebox 'msl6000' failed: Input/output error
02/24/10 12:02:44 nsrd: shutting down remote daemons
02/24/10 12:02:45 nsrd: Jukebox 'msl6000' failed: Input/output error
02/24/10 12:02:45 nsrd: Jukebox 'msl6000' failed: Input/output error
02/24/10 12:02:45 nsrd: media info: Suggest manually labeling a new writable volume for pool 'dbreport'
02/24/10 12:02:45 nsrd: media event cleared: Waiting for 1 writable volumes to backup pool 'miscdb' tape(s) on ah-db01
02/24/10 12:02:45 nsrd: media waiting event: Waiting for 1 writable volumes to backup pool 'miscdb' tape(s) on ah_bak01
02/24/10 12:02:53 savegrp: group db_arch aborted.
……
基本看到的情况是在备份的时候,开始做verify label的时候,报错No such file or directory和Input/output error,这个很有可能是在legato的界面中还能看到配置的driver,但是在调用这个driver的时候找不到实际的物理设备了。
于是在备份服务器上点开“硬件”-“设备管理器”,发现里面的磁带驱动器和介质变换器确实没有了!
请在机房的同事帮忙查看带库是否有问题,同事说带库已经down掉了。
重启带库,发现在备份服务器里面还是看不到driver,但是在client端,也就是数据库服务器上通过inquire还是能看到的。重启server,能看到driver了。再次尝试备份,备份到一半,一个driver消失了,备份卡住,再过一会儿,另一个driver也消失了,介质变换器也消失。
请机房的同事查看带库的情况,带库还是down了,是电源模块有问题,导致带库不稳定。等待设备厂家来更换电源模块。
更换完成电源模块后,启动带库,在备份主机只能看到一个driver,重启备份主机也是只能看到一个。厂家关闭备份主机后重新插拔了光纤卡,再次启动备份主机后,识别到了2个driver。但是测试备份时,只能一个driver备份,另一个driver会卡住。
尝试用清洗带清洗2个带子,但是发现报错:
02/24/10 15:49:14 nsrmmd #3: Cannot set \\.\Tape0 block size: 信号灯超时时间已到。
02/24/10 15:49:14 nsrd: media critical: TapeAlert flag "Expired cleaning media" has been posted for \\.\Tape0
02/24/10 15:49:14 nsrd: media warning: \\.\Tape0 reading: read open error: drive status is Drive reports no error - but state is unknown
Blat v2.4 w/GSS encryption (build : Jan 15 2005 08:32:11)
这个是清洗带过期的报错。于是更换清洗带。
更换之前尝试重新用jbconfig配置jukebook。
再次备份,发现2个driver都不能备份了!此时报错:
02/24/10 17:15:51 nsrmmd #3: Diagnostic: Tape device \\.\Tape0 is empty
02/24/10 17:15:52 nsrd: media warning: \\.\Tape0 reading: read open error: drive status is There is not a tape in the drive
02/24/10 17:15:52 nsrd: \\.\Tape0 1:Label without mount operation in progress
drive status is There is not a tape in the drive——难道是机械臂的问题?没有将磁带load到driver,请在机房的同事看了,确定是已经load进了driver。为什么会识别不到?
这个报错,在网上查资料是(见此链接)
Customer has redundant fibre connections to drives and when they changed FC cables, they missed something, so NW worked with wrong devices scidev@4.0.0 instead scidev@2.0.0. Correct cabling solved the problem!!
请机房的同事检查光纤线的连接情况,结果确认从带库到光纤交换机的连接都正常。
问题出在哪里?我们再来回顾一下当前的情况:
(1)、备份服务器和备份client均能识别driver。在备份服务器端看到driver正常,驱动也正常安装。没有出现driver消失或者driver无法识别的硬件问题。通过inquire或者ioscan -fnCtape都能看到driver的情况。
(2)、备份无法正常进行,做inventory清点没有问题,但是做label标签,甚至做一个mount磁带,都会报错drive status is There is not a tape in the drive。但是检查光纤连接正常。
电源模块已经换过,硬件也能识别到。所以不太好确定硬件是否有问题。如果确定不了硬件问题,也就不好让设备厂家进行更换,因为之前设备厂家说在更换完电源模块之后,已经进行了一次硬件检查,说没有问题的。那我们如何检查硬件是否真的正常呢?这个时候,就要请出hp带库检测的专业工具,也就是本文的重点:LTT出场了。
HP LTT的全称是HP StorageWorks Library and Tape Tools,是HP用来检查HP带库的一个非常有用的工具。ltt可以安装在备份服务器端,模拟磁带的读写情况,来检查driver或者media是否正常。各个os的版本都有,可以在这里免费下载。
我们在备份server安装好LTT之后,就开始测试了。注意此时的测试是脱离legato的,我们要在备份主机上证明带库的硬件是否存在问题。只有证明了硬件没有问题,才能配置调试后续的legato。
我们启动LTT之后,点击其中一个driver,让读取这话driver的信息,我们发现在测试过程中,经常遇到超时的情况:

当我们点击Test,开始测试Driver Assessment test的时候,发现报错没有磁带在driver中:
而在这之前,我们已经手工的load了一卷磁带到Driver中:
DT_slot_1 FULL QWB425
DT_slot_2 EMPTY
ST_slot_1 FULL QWB417
ST_slot_2 FULL QWB418
ST_slot_3 FULL QWB419
ST_slot_4 FULL QWB420
ST_slot_5 FULL QWB421
ST_slot_6 FULL QWB422
ST_slot_7 FULL QWB423
ST_slot_8 FULL QWB424
ST_slot_9 EMPTY
ST_slot_10 FULL QWB434
ST_slot_11 FULL QWB435
ST_slot_12 FULL QWB497
ST_slot_13 FULL QWB496
ST_slot_14 FULL QWB499
ST_slot_15 FULL QWB506
ST_slot_16 FULL QWB498
ST_slot_17 FULL QWB508
ST_slot_18 FULL QWB500
ST_slot_19 FULL QWB510
ST_slot_20 FULL QWB511
ST_slot_21 EMPTY
ST_slot_22 FULL QWB502
ST_slot_23 FULL QWB501
ST_slot_24 FULL QWB509
ST_slot_25 EMPTY
ST_slot_26 EMPTY
ST_slot_27 FULL QWB507
ST_slot_28 EMPTY
ST_slot_29 FULL QWB433
ah-db01#[/sbin/init.d]
既然已经load进了带子,但是LTT做测试的时候还是认为没有带子,无法读写测试。那就应该可以确定是driver的问题了。
把该情况和设备厂家说明后,要求厂家换driver。
scsidev@14.0.1:HP Ultrium 2-SCSI F59W|Tape, /dev/rmt/c14t0d1BESTnb
S/N: HUL5A04564
ATNN:HP Ultrium 2-SCSI HUL5A04564
WWNN:50060B00002BBEFE
scsidev@14.0.2:HP Ultrium 2-SCSI F59W|Tape, /dev/rmt/c14t0d2BESTnb
S/N: HUL5A07372
ATNN:HP Ultrium 2-SCSI HUL5A07372
WWNN:50060B00002BC9F6
换后:
scsidev@14.0.1:HP Ultrium 2-SCSI F59W|Tape, /dev/rmt/c14t0d1BESTnb
S/N: HUL5A04564
ATNN:HP Ultrium 2-SCSI HUL5A04564
WWNN:50060B00002BBEFE
scsidev@14.0.2:HP Ultrium 2-SCSI F6AW|Tape, /dev/rmt/c14t0d2BESTnb
S/N: HUL8A06538
ATNN:HP Ultrium 2-SCSI HUL8A06538
WWNN:50060B000028C845
更换后,在备份主机上更新新的driver的驱动,使得备份主机能识别新的driver。
我们注意新的driver的SN是HUL8A06538。在LTT界面,选择这个driver,开始准备测试:
在这里,不得不提一下,更换driver后,读取这个driver的信息很快,在identity这个driver信息的时候,不到2分钟就出来了。
我们手工load上一个带子做读写测试:
DT_slot_1 FULL QWB425
DT_slot_2 EMPTY
ST_slot_1 FULL QWB417
ST_slot_2 FULL QWB418
ST_slot_3 FULL QWB419
ST_slot_4 FULL QWB420
ST_slot_5 EMPTY
ST_slot_6 FULL QWB422
ST_slot_7 FULL QWB423
ST_slot_8 FULL QWB424
ST_slot_9 FULL QWB421
ST_slot_10 FULL QWB434
ST_slot_11 FULL QWB435
ST_slot_12 FULL QWB497
ST_slot_13 FULL QWB496
ST_slot_14 FULL QWB499
ST_slot_15 FULL QWB506
ST_slot_16 FULL QWB498
ST_slot_17 FULL QWB508
ST_slot_18 FULL QWB500
ST_slot_19 FULL QWB510
ST_slot_20 FULL QWB511
ST_slot_21 EMPTY
ST_slot_22 FULL QWB502
ST_slot_23 FULL QWB501
ST_slot_24 FULL QWB509
ST_slot_25 EMPTY
ST_slot_26 EMPTY
ST_slot_27 FULL QWB507
ST_slot_28 EMPTY
ST_slot_29 FULL QWB433
我们开始做测试,这次测试很顺利:
测试另一个driver,也同样没有问题:
于是,就基本判断目前硬件没问题。开始配置legato。
但是legato备份的时候还是报错了:
03/01/10 20:20:37 nsrmmd #3: Diagnostic: Tape device \\.\Tape0 is empty
03/01/10 20:20:48 nsrmmd #3: Diagnostic: Tape device \\.\Tape0 is empty
03/01/10 20:20:48 nsrd: media warning: \\.\Tape0 reading: read open error: drive status is There is not a tape in the drive
03/01/10 20:20:50 nsrd: nsrjb notice: nsrjb -j msl6000 -Y -O31 -L -g -bmiscdb -f \\.\Tape0 -S 1-1
03/01/10 20:20:50 nsrd: \\.\Tape0 1:Verify label operation in progress
03/01/10 20:21:00 nsrmmd #3: Diagnostic: Tape device \\.\Tape0 is empty
03/01/10 20:21:10 nsrmmd #3: Diagnostic: Tape device \\.\Tape0 is empty
03/01/10 20:21:11 nsrd: media warning: \\.\Tape0 reading: read open error: drive status is There is not a tape in the drive
03/01/10 20:21:11 nsrd: \\.\Tape0 1:Label without mount operation in progress
03/01/10 20:21:21 nsrmmd #3: Diagnostic: Tape device \\.\Tape0 is empty
03/01/10 20:21:23 nsrd: \\.\Tape0 1:Eject operation in progress
03/01/10 20:21:33 nsrmmd #3: Diagnostic: Tape device \\.\Tape0 is empty
03/01/10 20:21:44 nsrmmd #3: Diagnostic: Tape device \\.\Tape0 is empty
之前查到drive status is There is not a tape in the drive是光纤的连接的问题,但是光纤连接都没问题,LTT测试也通过了,难道是里面的driver连接接反了?
尝试再次重新配置jbconfig,在配置时,先配//./Tape1,再配//./Tape0。当然,这边Tape0和Tape1对应的driver的SN还是要对应备份client 端的SN的。只是在配置的时候,先写了//./Tape1。
配置完成后测试备份,真的证实了我的猜想,里面的driver接反了。当反配jbconfig的时候,备份成功了:
至此,又一个棘手的legato备份问题解决!
在处理legato问题的时候,如果无法确定是否硬件问题,那么相信LTT吧!
现在个人要注册并且使用一个cn域名,手续需要:
1. 购买域名,付费
2. 付费成功之后提供审核资料(包括一些打印件和身份证的扫描件)
3. 审核通过之后去工信部备案网站中自行备案
4. 备案成功之后域名开通
为此条款我特地致电了国内某域名注册商的客服。
Q:费用计费是从什么时候开始的?
A:从成功付费以后。
Q:那如果工信部备案拖了我几个月都备案不成功,这段时间如何补偿?
A:没有补偿。
Q:如果备案不成功怎么办?
A:那你就重复提交备案申请,总会成功的。
Q:如果我厌倦了备案的繁琐,决定放弃这个域名,既然你们自从我注册了这个域名之后就没有提供任何服务,可以退款吗?
A:抱歉,一旦付费成功了,就无法退款。
cao你大爷,贵国真是威武。老子惹不起总躲得起,本来一直说cn域名还代表咱是中国人,用着挺爱国的,但是从今以后决定不再注册任何cn域名。
做出这个决定,就好比方鸿渐老爹抱怨的那样“他爱国而国不爱他,大有青年守节的孀妇不见宠于翁姑的怨抑”,又跟五折叔说的那样怎么老是有种挥之不去的忧郁感呢?日你个麻哟。
最后看一眼工信部备案管理网站糟糕至极的用户体验。
1. “建议使用:1024 * 768 分辨率”,这种土掉渣的提示应该在进入21世纪以后就很少看到了吧。
2. “刷新验证码”这个链接是假的,毫无用处。不偷工减料会死啊。
3. 每个新网站必须要重新注册新用户才可以备案,即使登陆备案网站是通过用户名而不是网站名。也就是一个名下有10个网站的主办者需要注册10次才可以,这是什么脑子思考出来的模式?
4. 作为一个互联网域名备案的网上办公系统,毫无专业性。为什么“典型问题指南”是用弹出窗口这样被用户诟病了多年的方式来表达?为什么在用户登陆之后页面左侧的树状结构在Firefox和Chrome浏览器里面一团糟完全没法正常使用?
不知道这个网站用了多少钱造出来的,我只想说在如今这个年代大概再差劲的架站初学者应该也会比这个做的好看吧。
2010-03-01 Mon
我在"如何在oracle里使用java存储过程连接db2"这篇文章里已经提到过如何在oracle里用java存储过程连db2 v9 for z/OS,并且我在里面举了用java存储过程在db2 v9 for z/OS上执行一条sql的例子,这篇文章其实就是上述文章的延续,在这篇文章里,我们完整的做了一个调用db2 v9 for z/OS上存储过程的例子。
我们的目的是要调用存储过程XBAIPA.CAAUD,这个存储过程有一个输入参数和一个输出参数,其中输入参数是一个字符串,输出参数也是一个字符串。
注意这里安装完transparent gateway后虽然能连上db2 v9 for z/OS,但是不能执行其中的存储过程,如下所示:
SQL> select deptname from DSN8910.DEPT@PLHI3 where deptno='A00';
DEPTNAME
------------------------------------------------------------------------
SPIFFY COMPUTER SERVICE DIV.
SQL> var temp varchar2(32767);
SQL> set serveroutput on size 1000000;
SQL> begin
2 XBAIPA.CAAUD@PLHI3('A 9999992581970687034 NBEUR 1232542102008120220091222 LEENEN/WERNER MR 5BJ9B9/1A NON-RER REF FEE MAY APPLY BR0.114200 0000000019000000000001900000000000190000000000293000000000000Y 0 0N00000000000H',:temp);
3 end;
4 /
begin
XBAIPA.CAAUD@PLHI3('A 9999992581970687034 NBEUR 1232542102008120220091222 LEENEN/WERNER MR 5BJ9B9/1A NON-RER REF FEE MAY APPLY BR0.114200 0000000019000000000001900000000000190000000000293000000000000Y 0 0N00000000000H',:temp);
end;
ORA-06550: line 2, column 1:
PLS-00201: identifier 'XBAIPA.CAAUD@PLHI3' must be declared
ORA-06550: line 2, column 1:
PL/SQL: Statement ignored
temp
---------
为什么不能执行上述存储过程的原因我已经在上述文章里说过了。
现在我们来看怎样才能成功调用上述存储过程:
在把JDBC for db2的驱动加载到oracle里后首先创建所需的java存储过程:
SQL> create or replace and compile java source named call_db2 as
2 import java.sql.*;
3 import oracle.jdbc.*;
4 import java.io.*;
5 import java.lang.*;
6
7 public class call_db2
8 {
9 public static String call_db2_procedure_type_1(String ProcedureName, String InputString)
10 {
11 Connection conn = null;
12 CallableStatement proc = null;
13 String callname = null;
14 String OutputString = null;
15
16 try
17 {
18 DriverManager.registerDriver(new com.ibm.db2.jcc.DB2Driver());
19 conn = DriverManager.getConnection("jdbc:db2://10.1.21.215:446/LOCDSN3", "xbalhu", "abcd");
20
21 //执行一个db2存储过程----------begin------------------------------
22 callname = "{CALL " + ProcedureName + "(?,?)}";
23 proc = conn.prepareCall(callname);
24 proc.setString(1, InputString);
25 proc.registerOutParameter(2, Types.VARCHAR);
26 proc.execute();
27 OutputString = proc.getString(2).substring(1,2000);
28 //执行一个db2存储过程----------End--------------------------------
29 }
30 catch(Exception e)
31 {
32 e.printStackTrace();
33 OutputString = "Error Occur: " + e;
34 }
35 finally
36 {
37 try
38 {
39 if(proc != null)
40 {
41 proc.close();
42 }
43
44 if(conn != null)
45 {
46 conn.close();
47 }
48 }
49 catch(Exception ex)
50 {
51 }
52 }
53
54 return OutputString;
55 }
56 }
57 /
Java created
接着创建wrapper function:
SQL> CREATE OR REPLACE Function F_SYS_CALL_DB2_PROC(ProcedureName varchar2, InputString varchar2)
2 return varchar2
3 as language java
4 name 'call_db2.call_db2_procedure_type_1(java.lang.String, java.lang.String) return java.lang.String';
5 /
Function created
好了,现在我们可以来测一下最后的效果了:
SQL> var temp varchar2(32767);
SQL> set serveroutput on size 1000000;
SQL> begin
2 :temp := f_sys_call_db2_proc('XBAIPA.CAAUD','A 9999992581970687034 NBEUR 1232542102008120220091222 LEENEN/WERNER MR 5BJ9B9/1A NON-RER REF FEE MAY APPLY BR0.114200 0000000019000000000001900000000000190000000000293000000000000Y 0 0N00000000000H');
3 end;
4 /
PL/SQL procedure successfully completed
temp
---------
0000000000000+0000000000000+0000000000000+0000000000000 Y
从结果里可以看到,我们已经在oracle里成功调用了db2 v9 for z/OS中的存储过程。
上述蓝色字体标注的部分格式不能错,否则oracle可能会报错:
com.ibm.db2.jcc.c.SqlException: [ibm][db2][jcc][10243][10940] 对 DB2 z/OS 版的存储过程调用不支持字符串文字
呵呵,很搞的错误提示。
本文翻译自Jonathan Lewis早年写在dbazine上的文章unbalanced indexes? 本文的word版本可以到此处下载
原文参见: 不平衡的索引?
不平衡的索引?
by Jonathan Lewis
网络上有多篇介绍Oracle索引实现机制的文章,都提及需要经常重建索引.在这些文章中的某处,总是会出现这样一段简短的描述,索引会如何变的不平衡,以及可能导致的后果.很不幸,它们好像忽视了这样一个事实,Oracle使用的B-tree机制是一种”平衡B-tree”索引,也就是说,索引无法变得不平衡.
“平衡”到底意味着什么?
既然Oracle的索引使用的是平衡B-tree,为什么还有如此多的人相信他们的索引会变得不平衡呢?
另外,平衡B-tree到底又是什么呢?
第二个问题的答案可能能够帮助我们得到第一个问题的答案.
从技术角度讲,平衡B-tree的显要特性是,在任意时间点,任何叶子节点(leaf block)到根节点(root block)的距离都相等,平衡是指从顶部到底部的平衡.
就Oracle来说,执行一个treedump命令就可以很容易发现这一点,如图-1所示:
select object_id from user_objects where object_type = 'INDEX' and object_name = 'T1_IDX1' -- and subobject_name = . . . ; alter session set events ' 'immediate trace name treedump level N';
图-1: 一次索引树转储涉及到的步骤
首先,需要找到你想要转储(dump)索引或者索引分区(index partition)的object_id;接着,将object_id作为level的参数来调用treedump事件. 如果检查这个索引树(tree dump)转储生成的跟踪文件,你将发现类似于图-2中所示的结果.
branch: 0x14001aa 20971946 (.. level 2)
branch: 0x14003ef 20972527 (.. level 1)
leaf: 0x14001ab 20971947 (..)
leaf: 0x14001ac 20971948 (..)
图-2: 从索引树转储结果中提取出的一段内容
这个跟踪文件以递归降序的方式展示索引的分支块(branch block,根块只是分支块的一个特例)与叶子块.注意,转储内容的第一个块(根块)记录了一个高度(level),并且它下面的每一个分支块也都记录了一个高度,但是叶子块没有记录高度.
根块的高度就是索引的blevel(执行analyze index命令之后会记录在视图dba_indexes中).索引的高度(height,执行命令validate index后会记录在视图index_stats中)就是blevel + 1.
每一个叶子块到根块的距离就正好有这么多步.索引总是平衡的.
那么为什么有那么多人相信Oracle会允许索引变得不平衡呢?
我应负的责任
此时,我必须承认我有罪,仅仅在一年前(2002年5月),我也重复了一个关于块分裂(index block split)的众所周知但是却完全错误的描述.虽然我知悉(在我的书(2000年12月,Practical Oracle 8i)中对此做了说明) treedump的细节,但我还是这样做了.
我猜想,这种错误的观念最初产生于Oracle5(很多年以前)手册的说明,其大意是,因为”没有一个叶子块到根块的距离比任何其他叶子块到根块的距离远.”, 所以Oracle索引是平衡的.将这个表述与一个过于简化的块分裂的图结合到一起,瞧,一个几乎牢不可破的神话就诞生了.
图-3和图-4描绘了一个非常常见,但是完全错误的关于叶子块如何分裂的概念.

图-3: 叶子块将要分裂前的索引结构

图-4 这不是叶子块分裂发生的方式
有这样一个流传广泛的说法,叶子块分裂到两个全新的块,这两个块分享它的所有数据;接着, Oracle在原来的叶子块的位置插入一个新的分支块来持有指向这两个块的指针.因此,在这样一个错误的视角下,这个索引的右边就会比左边更深.(经常会有人说,创建在基于序列的字段上的索引会带来最大的问题,因为,从这个理论来推导,最右边的叶子块到根块的距离会越来越远,没分裂一次,就会降低一层.)
事实上,这个工作Oracle做得更加精致前瞻并有效得多. 图-5所示是一个复杂的叶子块分裂的结果.

图-5: 一次递归分裂后的索引结构图
由于这个叶子块分裂成了两个块,Oracle会尝试往当前指向这个叶子块的分支块中插入一个额外的指针.
但是,如果这个分支块也满了,Oracle会继续将这个分支块也分裂成两个块,并且在两个分支块之间分配现存块里的指向叶子块的指针,并且(递归地) 在这个分支块的上一级的分支块中插入一个指向这个新的分支块的新的分支指针.
如果在这个过程中,Oracle抵达了根块,然而这个根块也满了,那么根块也必须分裂.在这种情况下,Oracle将创建一个新的根块来持有这两个分支指针.(事实上,Oracle处理根块分裂的方式与处理普通的分支块的分裂有一点细微的差异,以确保无论根块上发生了多少次的分裂,总是可以在物理段的同一个位置找到根块.)
注意,这个递归的分裂操作这样沿着索引树不断攀升意味着,无论何时,索引总能保持平衡.
为什么这个神话如此牢固?
为什么这个关于不平衡的索引的神话能够长盛不衰,是否存在一些原因呢?我这答案是确实存在一些原因.
要切记,当我们讨论B-tree的时候,单词”balanced”的定义有非常严格的含义.然而,这个单词还有一种完全不同的解释.
例如,你将如何描述图-6中的这个索引,其中根块指向六个叶子块,但是其中一个叶子块是空的,有三个块几乎是空的,还有两个块塞的很满.(注意,从根块到叶子块的这些额外的说明是为了强调索引填充分布的多么不均匀;实际上,根块到每个叶子块都只有一个指针.)

图-6 “不平衡”的一种非技术理解
看到这种图案的索引,一个”人”的真实反应都会人为它”不平衡”.很明显,索引的右手边要比左手边”重”.很不幸,当技术表达意味着完全不同的东西的时候,这种非正式的人为表达应该更加恰当.
或许正是这种技术表达与非正式的人为表达之间的冲突导致了这种混淆.
在这种非正式的意义上,在基于序列值的字段上索引很容易就会变得”不平衡”,特别是它们被用来表征/处理先进先出(FIFO)队列机制的时候.然而,即使它们(在非正式语境中)是不平衡的,它们(在技术上)仍然是平衡的B-tree.
(推动使用类似于”扭曲”或者”分布不均匀”作为术语来描述这种类型的索引,或许会是个好主意.)
有时,仅仅几篇草率地使用术语的文章或报告就可能构建一个神话,在这个例子中,就是一个导致众多DBA浪费无数小时的时间去做不必要的索引重建的神话.
记住,你下一次认为Oracle表现愚蠢或者低效的时候,很可能问题是出在一个古老的误解上面,而不是Oracle软件本身的问题.
告警提醒
如果你还想进一步地研究,treedump选项还有一系列的问题需要注意.对于大部分的Oracle版本,它看似对索引段中的每个块都生成一行输出,这样可能会非常昂贵并且速度缓慢,因为它需要按顺序访问索引中的每一个数据块.然而,在Oracle 9.0中,跟踪文件看似会对每一个块做一个整块转储,这样会使得转储文件非常巨大,转储速度也会非常缓慢.
第二个问题是所有版本都一致的.如果这个索引是在定义主键约束或者唯一键约束时生成的,Oracle就会设置ind$表的flags字段的第13位,而这将导致treedump程序崩溃并报出错误”invalid value.”分区索引的分区段不会产生这个问题,但是对于所有其他类型的主键索引与唯一索引(包含非分区索引组织表,IOT),这都很恼人.先创建索引,再基于这个索引创建约束通常是个好主意, 这样处理可以避免除索引组织表外的其他所有条件下的问题. 在紧急情况下,你可以修改ind$表来清除这一位,但是很明显,需要先取得Oracle支持的认可.
结论
当谈到平衡B-tree索引的时候,术语”平衡”指的是从顶部到底部,而不是从左到右.
Oracle确实实现了一个版本的”平衡B-tree索引”,因此在任何时候,索引中的所有叶子块到根块的距离都是完全相同的,如果最近对这个索引作过分析的话,可以从视图user_indexes的字段blevel找到它,如果刚刚对这个索引执行过validate index的话,可以从视图index_stats的height字段(等价于blevel+1)得到.
当听到你应该经常重建索引,因为”这些索引已经变得不平衡”时,要抵制这种理由.因为它不是一个靠得住的理由.
本文翻译自Jonathan Lewis发表在DBAZine上的文章:Why Isn’t Oracle Using My Index?!,可以从此处下载本文的Word版本.
原文参见: 为什么Oracle不使用我的索引?!
为什么Oracle不使用我的索引?!
by Jonathan Lewis
标题的这个问题可能是在Metalink论坛与Usenet新闻组出现的最频繁的问题了.这篇文章使用一个测试用例(可以在你自己的系统来重现的)来演示基于成本的优化器的基本工作原理.在看完这篇文章之后,当再次遇到这个令人讨厌的问题时,你应该就可以自信的解答了.
由于在安装Oracle的时候存在大量的选项,因此当某人执行一条你口授的脚本时,通常很难精确的预测即将出现什么结果. 当时我想要尝试一下,希望你的数据库选择了一个相对普通的安装选项,并且最常用的关键的参数是取得默认值. 这个例子是在Oracle 8.1.7下创建并测试的,参数db_block_size被设置成最常用的值(8k),参数db_file_multiblock_read_count也设置了一个很常用的值(8).在Oracle 9.2下跑图-1中的这个脚本(创建了一组表,在表上添加索引并分些表与索引),结果可能出现部分差异.
create table t1 as
select trunc((rownum-1)/15) n1, trunc((rownum-1)/15) n2, rpad('x', 215) v1
from all_objects
where rownum <= 3000;
create table t2 as
select
mod(rownum,200) n1,
mod(rownum,200) n2,
rpad('x',215) v1
from all_objects
where rownum <= 3000;
create index t1_i1 on t1(N1);
create index t2_i1 on t2(n1);
analyze table t1 compute
statistics;
analyze table t2 compute statistics;
图 1: 测试的数据集
在你准备好数据之后,你可能认为这两组数据是一样的,尤其是,在两个数据集中字段N1有的值范围相同(从0-199),并且每个值都出现了15次.你可能会这样检查数据:
select n1, count(*) from t1 group by n1;
查询表T2也会证实你的上述观点.
如果你接着执行下面的查询语句:
select * from t1 where n1 = 45; select * from t2 where n1 = 45;
你将发现每个查询语句都返回了15条记录.然而如果你执行
set autotrace traceonly explain
语句,你将发现这两个查询语句拥有两种不同的执行路径.针对表T1的查询使用了索引,而针对表T2的查询则做了一个全表扫描.
因此,在拥有完全相同的数据的情况下,同一个查询语句戏剧性地出现了两个不同的执行路径.
索引到底怎么了?
注意: 如果你曾经听到如下的关于使用索引的”魔法”准则,例如,”在数据少于23%/10%/2%(随机取一个数字)的时候,Oracle将使用索引,”那么,此时你将怀疑他们的准确性.例如,在这个例子中,Oracle对于一个在3000记录中取15条的查询使用了全表扫描,仅仅0.5%的数据.
要调查诸如此例的问题,只有一个手段(我经常首先尝试使用的):添加一些索引以使得Oracle选择我们认为它应该选择的执行路径,并检查这能否给我们部分提示.
在这个例子中,添加一个简单的提示:
/*+ index(t2, t2_i1) */
就足够让Oracle从选择全表扫描切换到选择使用索引访问.图-2展示了这三种路径的成本(简化为C=nnn).
select * from t1 where n1 = 45;
EXECUTION PLAN
--------------
TABLE ACCESS BY INDEX ROWID OF T1 (C=2)
INDEX(RANGE SCAN) OF T1_I1 (C=1)
select * from t2 where n1 = 45;
EXECUTION PLAN
--------------
TABLE ACCESS FULL OF T2 (C=15)
select /*+ index(t2 t2_i1) */
*
from t1
where n1 = 45;
EXECUTION PLAN
--------------
TABLE ACCESS BY INDEX ROWID OF T2 (C=16)
INDEX(RANGE SCAN) OF T2_I1 (C=1)
图 2: 不同的查询以及它们的成本
因此,为什么在T2相关的查询中Oracle没有选择索引作为默认的执行路径?很简单,正如执行计划所展示,选择执行全表扫描的成本要低于使用索引的成本.
为什么使用全表扫描成本更低?
当然,这仅仅是在重复问题.为什么全表扫描的成本会低于使用索引的成本呢?
通过深入调查这个问题,你将揭开了基于成本的优化器的关键机制(也是致命的错误假设).
让我们通过运行下面这个查询来开始我们的考查:
select
table_name,
blevel,
avg_data_blocks_per_key,
avg_leaf_blocks_per_key,
clustering_factor
from user_indexes;
下表是对应的输出结果:
| T1 | T2 | |
|---|---|---|
| Blevel | 1 | 1 |
| Data block / key | 1 | 1 |
| Leaf block / key | 1 | 15 |
| Clustering factor | 96 | 3000 |
请特别关注”data block per key”的值. 如果你执行一个完全基于这个索引的键值的等值校验的查询语句,这个值就是Oracle认为必须访问的不同数据块的数量.
因此,我们的查询语句的成本是从哪儿来得呢?就Oracle而言,如果输入的键值为45,当从表T1获取数据时,我们就可以访问一个索引叶子块以及一个表块(两个块),因此成本为2.
如果对表T2执行同样的查询,我们就必须访问一个索引叶子块以及15个表块(总共16个块),因此成本为16.
很明显,根据这种观点,表T1的索引比表T2的索引更加理想.不过,这就带来了两个未解决的问题:
全表扫描的成本来自何处,为什么两张表之间的avg_data_blocks_per_key的数值差别如此大?
第二个问题的答案很简单.回头再看看表T1的定义,它使用trunc()函数来生成N1的值,使用”rownum -1″除以15并截成整数.
Trunc(675/15) = 45
Trunc(676/15) = 45
…
Trunc(689/15) = 45
所有值为45的记录实际上都是一条接着一条连续(可能所有的都能够保存到一个数据块中)的出现的.
表T2使用mod()函数来生成N1的值,使用对rownum取200的模的方式.
mod(45,200) = 45
mod(245,200) = 45
…
mod(2845,200) = 45
值为45的记录要隔200才会在表中出现一次(可能导致每一个相关数据块中都不会超过1条记录).
通过对表的分析,Oracle可以得到我们表中的数据分布的完美的描述.从而优化器才确切的明白,对于我们的查询,Oracle将需要访问多少个数据块,在这个简单的例子中,这个查询的成本就是需要访问的数据块的数量.
但是为什么是全表扫描呢?
我们看到,对于同样的执行路径,对表T2进行索引访问的成本要远远高于对表T1的索引访问成本,但是为什么会选择使用全表扫描呢?
这个问题将让我们发现Oracle做的两个过于简单甚至不恰当的假设.
第一个假设是,每个块访问都视为一次物理磁盘读,第二个假设是,多块读的速度与单块读一样.
因此,这些假设将对我们的这个实验产生什么影响?
如果使用下面的查询语句查询user_tables表:
select
table_name,
blocks
from user_tables;
你将发现这两张表每个都是占用96个数据块.
在文章开头,我说过这个测试用例运行在一个db_file_multiblock_read_count的值为8的版本为8的Oracle系统系统上.
粗略地讲,Oracle认为它可以通过12(96/8)次磁盘读请求来读出所有的96个数据块.
由于通过索引访问表需要16个块(等于物理读)请求, 从Oracle的可悲的受骗的视角看的话,选择全表扫描显得更清晰也更快捷.
瞧!如果你要访问的数据适当地散布在表上,即使只有很小比例的数据也会选择使用全表扫描,在数据块非常多(也就是表很大)而返回的记录数很少的时候,这个问题还会被放大.
校正
实际上,可能你已经发现,我计算出来的扫描读次数为12,而执行计划中报告的成本是15.一种轻微的简化版本认为表扫描(或者索引快速全扫描)的成本为
‘number of blocks’ /
db_file_multiblock_read_count.
Oracle使用一种”调整后”的多块读的值来做这种计算(然而,在扫描开始之后,它仍然尽力使用这个真实的请求值来扫描).
为了方面查询,下表对比了几个真实值与调整后的值:
| Actual | Adjusted |
|---|---|
| 4 | 3.175 |
| 8 | 6.589 |
| 16 | 10.398 |
| 32 | 16.409 |
| 64 | 25.895 |
| 128 | 40.865 |
你还将发现,当你为这个参数提供一个不切实际的很大的值后,Oracle可以为你提供保护来避免发生错误.
顺便提一下,Oracle 9中有一点小小的改变,表扫描的成本还会做进一步的调整(对相除之后的结果加1),这意味着Oracle 9中的表扫描的成本会比Oracle 8中大一点点,从而索引会变得更可能被使用一点点.
修正
我们已经看到,优化器有两个内置的假设,而这两个假设又不是很合理.
- 一次单块读的成本与一次多块读的成本一样-(实际上不大可能,特别是运行在没有顺序的文件系统上的时候)
- 一次块访问就是一次物理磁盘读-(那么Buffer Cache是干什么吃的?)
从Oracle 8.1刚发布开始,就有多个参数可供我们以一种相当切合实际的方式来修正这些假设.
Tim Gorman的文章为这些参数提供了一个切实的描述,下面是简单的描述:
- Optimizer_index_cost_adj的值范围为1到10000,默认为100.实际上,这个参数描述的是,相对于一次多块读来讲,一次单块读有多么便宜.如果它的值为30,也就是高速Oracle一次单块读的成本是一次多块读的成本的30%. 从而Oracle就会因此这个参数的值很小而更多的倾向于选择使用索引访问.
- Optimizer_index_caching的值访问为0到100,默认为0.这个参数告诉Oracle,假定索引块将在Buffer Cache中存在百分比.在这个例子中,将这个值设置为接近100的值将助长使用索引而不是表扫描.
关于这些参数的真正美好的事情是,可以将他们设置成”符合实际”的值.
将optimizer_index_caching设置成”buffer cache hit ratio”范围内的一个值(你需要自己决定具体是按照default pool,keep pool还是这两个的某种组合来得到这个数值).
Optimizer_index_cost_adj的值的设置要更加复杂一点.检查v$system_event视图中等待事件”db file scattered read”(多块读取)与”db file sequential read”(单块读取)的有代表性的等待时间.用后者(单块读的等待时间)除以前者(多块读的等待时间)并乘以100.
改进
不要忘了,这两个参数可能需要一天(周)的不同时段进行调整以反映终端用户的工作负载.仅仅取得一组数字,就一直使用下去,是不可行的.
很高兴,在Oracle 9中,情况得到了改善.你可以收集系统统计信息,通常就包含以下四个统计数据:
- 单块读的平均读取时间
- 多块读的平均读取时间
- 实际发生的多块读的平均读取块数
- CPU的理论可用速度
要详细介绍这个特性足够配得上一整篇文章,但是这里我特别强调一点,前三个统计值使得Oracle可以明白对多块读的真实成本(相对单块读来讲).实际上,CPU速度使得Oracle可以得出不适宜的访问机制的CPU成本,比如,读取一个数据块中的每条记录以找出特定的数据值,以及与此相似的行为.
当你将系统升级到Oracle 9时,你首先需要检查的事情就是是否正确使用系统统计信息.单单这个特性就可能大大降低你尝试”优化”的糟糕的SQL的时间.
顺便提一下,尽管系统统计信息带来了惊人的效果,这两个优化器调整参数仍然有效,虽然使用它们的确切地公式在Oracle 8与Oracle 9之间发生了变化.
主题的变种
当然,我选择了一个非常特殊的例子,一个单列非唯一索引上的等值查询,并且表中没有空值,这种情况非常容易处理.(我甚至都没有提及索引的blevel与clustering_factor.)Oracle还有多个不同的方法来处理更加一般的例子.
考虑如下这些我为了方便而忽视的情况:
- 多列索引
- 使用多列索引中的部分列
- 范围扫描
- 唯一索引
- 由非唯一索引代表的唯一约束
- 索引跳跃扫描
- 只查询索引的语句
- 位图索引
- 空值的影响
这个列表还可以不停地列下去.并没有一个简单的公式来告诉你Oracle是如何计算它的成本,只存在一个通用准则,通过它你可以了解这个方法的梗概,以及一组可以应用到不同情形下的不同计算公式.
不管怎样,本文的目的是让你知道有这个通用准则,以及优化器策略中内嵌的两个基本假设.我希望,这篇文章可以帮助你更加深入的理解那些优化器做出来的众所周知的怪事.
进一步阅读
- Tim Gorman: www.evdbt.com. “The Search for Intelligent Life in the Cost Based Optimiser.”
- Wolfgang Breitling: www.centrexcc.com. “Looking under the hood of the CBO.”
本文翻译自Jonathan Lewis早年写在dbazine上的文章unbalanced indexes? 本文的word版本可以到此处下载
不平衡的索引?
by Jonathan Lewis
网络上有多篇介绍Oracle索引实现机制的文章,都提及需要经常重建索引.在这些文章中的某处,总是会出现这样一段简短的描述,索引会如何变的不平衡,以及可能导致的后果.很不幸,它们好像忽视了这样一个事实,Oracle使用的B-tree机制是一种”平衡B-tree”索引,也就是说,索引无法变得不平衡.
“平衡”到底意味着什么?
既然Oracle的索引使用的是平衡B-tree,为什么还有如此多的人相信他们的索引会变得不平衡呢?
另外,平衡B-tree到底又是什么呢?
第二个问题的答案可能能够帮助我们得到第一个问题的答案.
从技术角度讲,平衡B-tree的显要特性是,在任意时间点,任何叶子节点(leaf block)到根节点(root block)的距离都相等,平衡是指从顶部到底部的平衡.
就Oracle来说,执行一个treedump命令就可以很容易发现这一点,如图-1所示:
select object_id from user_objects where object_type = 'INDEX' and object_name = 'T1_IDX1' -- and subobject_name = . . . ; alter session set events ' 'immediate trace name treedump level N';
图-1: 一次索引树转储涉及到的步骤
首先,需要找到你想要转储(dump)索引或者索引分区(index partition)的object_id;接着,将object_id作为level的参数来调用treedump事件. 如果检查这个索引树(tree dump)转储生成的跟踪文件,你将发现类似于图-2中所示的结果.
branch: 0x14001aa 20971946 (.. level 2)
branch: 0x14003ef 20972527 (.. level 1)
leaf: 0x14001ab 20971947 (..)
leaf: 0x14001ac 20971948 (..)
图-2: 从索引树转储结果中提取出的一段内容
这个跟踪文件以递归降序的方式展示索引的分支块(branch block,根块只是分支块的一个特例)与叶子块.注意,转储内容的第一个块(根块)记录了一个高度(level),并且它下面的每一个分支块也都记录了一个高度,但是叶子块没有记录高度.
根块的高度就是索引的blevel(执行analyze index命令之后会记录在视图dba_indexes中).索引的高度(height,执行命令validate index后会记录在视图index_stats中)就是blevel + 1.
每一个叶子块到根块的距离就正好有这么多步.索引总是平衡的.
那么为什么有那么多人相信Oracle会允许索引变得不平衡呢?
我应负的责任
此时,我必须承认我有罪,仅仅在一年前(2002年5月),我也重复了一个关于块分裂(index block split)的众所周知但是却完全错误的描述.虽然我知悉(在我的书(2000年12月,Practical Oracle 8i)中对此做了说明) treedump的细节,但我还是这样做了.
我猜想,这种错误的观念最初产生于Oracle5(很多年以前)手册的说明,其大意是,因为”没有一个叶子块到根块的距离比任何其他叶子块到根块的距离远.”, 所以Oracle索引是平衡的.将这个表述与一个过于简化的块分裂的图结合到一起,瞧,一个几乎牢不可破的神话就诞生了.
图-3和图-4描绘了一个非常常见,但是完全错误的关于叶子块如何分裂的概念.

图-3: 叶子块将要分裂前的索引结构

图-4 这不是叶子块分裂发生的方式
有这样一个流传广泛的说法,叶子块分裂到两个全新的块,这两个块分享它的所有数据;接着, Oracle在原来的叶子块的位置插入一个新的分支块来持有指向这两个块的指针.因此,在这样一个错误的视角下,这个索引的右边就会比左边更深.(经常会有人说,创建在基于序列的字段上的索引会带来最大的问题,因为,从这个理论来推导,最右边的叶子块到根块的距离会越来越远,没分裂一次,就会降低一层.)
事实上,这个工作Oracle做得更加精致前瞻并有效得多. 图-5所示是一个复杂的叶子块分裂的结果.

图-5: 一次递归分裂后的索引结构图
由于这个叶子块分裂成了两个块,Oracle会尝试往当前指向这个叶子块的分支块中插入一个额外的指针.
但是,如果这个分支块也满了,Oracle会继续将这个分支块也分裂成两个块,并且在两个分支块之间分配现存块里的指向叶子块的指针,并且(递归地) 在这个分支块的上一级的分支块中插入一个指向这个新的分支块的新的分支指针.
如果在这个过程中,Oracle抵达了根块,然而这个根块也满了,那么根块也必须分裂.在这种情况下,Oracle将创建一个新的根块来持有这两个分支指针.(事实上,Oracle处理根块分裂的方式与处理普通的分支块的分裂有一点细微的差异,以确保无论根块上发生了多少次的分裂,总是可以在物理段的同一个位置找到根块.)
注意,这个递归的分裂操作这样沿着索引树不断攀升意味着,无论何时,索引总能保持平衡.
为什么这个神话如此牢固?
为什么这个关于不平衡的索引的神话能够长盛不衰,是否存在一些原因呢?我这答案是确实存在一些原因.
要切记,当我们讨论B-tree的时候,单词”balanced”的定义有非常严格的含义.然而,这个单词还有一种完全不同的解释.
例如,你将如何描述图-6中的这个索引,其中根块指向六个叶子块,但是其中一个叶子块是空的,有三个块几乎是空的,还有两个块塞的很满.(注意,从根块到叶子块的这些额外的说明是为了强调索引填充分布的多么不均匀;实际上,根块到每个叶子块都只有一个指针.)

图-6 “不平衡”的一种非技术理解
看到这种图案的索引,一个”人”的真实反应都会人为它”不平衡”.很明显,索引的右手边要比左手边”重”.很不幸,当技术表达意味着完全不同的东西的时候,这种非正式的人为表达应该更加恰当.
或许正是这种技术表达与非正式的人为表达之间的冲突导致了这种混淆.
在这种非正式的意义上,在基于序列值的字段上索引很容易就会变得”不平衡”,特别是它们被用来表征/处理先进先出(FIFO)队列机制的时候.然而,即使它们(在非正式语境中)是不平衡的,它们(在技术上)仍然是平衡的B-tree.
(推动使用类似于”扭曲”或者”分布不均匀”作为术语来描述这种类型的索引,或许会是个好主意.)
有时,仅仅几篇草率地使用术语的文章或报告就可能构建一个神话,在这个例子中,就是一个导致众多DBA浪费无数小时的时间去做不必要的索引重建的神话.
记住,你下一次认为Oracle表现愚蠢或者低效的时候,很可能问题是出在一个古老的误解上面,而不是Oracle软件本身的问题.
告警提醒
如果你还想进一步地研究,treedump选项还有一系列的问题需要注意.对于大部分的Oracle版本,它看似对索引段中的每个块都生成一行输出,这样可能会非常昂贵并且速度缓慢,因为它需要按顺序访问索引中的每一个数据块.然而,在Oracle 9.0中,跟踪文件看似会对每一个块做一个整块转储,这样会使得转储文件非常巨大,转储速度也会非常缓慢.
第二个问题是所有版本都一致的.如果这个索引是在定义主键约束或者唯一键约束时生成的,Oracle就会设置ind$表的flags字段的第13位,而这将导致treedump程序崩溃并报出错误”invalid value.”分区索引的分区段不会产生这个问题,但是对于所有其他类型的主键索引与唯一索引(包含非分区索引组织表,IOT),这都很恼人.先创建索引,再基于这个索引创建约束通常是个好主意, 这样处理可以避免除索引组织表外的其他所有条件下的问题. 在紧急情况下,你可以修改ind$表来清除这一位,但是很明显,需要先取得Oracle支持的认可.
结论
当谈到平衡B-tree索引的时候,术语”平衡”指的是从顶部到底部,而不是从左到右.
Oracle确实实现了一个版本的”平衡B-tree索引”,因此在任何时候,索引中的所有叶子块到根块的距离都是完全相同的,如果最近对这个索引作过分析的话,可以从视图user_indexes的字段blevel找到它,如果刚刚对这个索引执行过validate index的话,可以从视图index_stats的height字段(等价于blevel+1)得到.
当听到你应该经常重建索引,因为”这些索引已经变得不平衡”时,要抵制这种理由.因为它不是一个靠得住的理由.
No related posts.
ORA-00283: recovery session canceled due to errors
RMAN-11003: failure during parse/execution of SQL statement:
alter database recover logfile '/arch/prod1_2711_681480148.arc'
ORA-00283: recovery session canceled due to errors
ORA-12801: error signaled in parallel query server P011, instance hpdb1:PROD1 (1)
ORA-00600: internal error code, arguments: [3020], [37], [94633], [2], [3659], [604], [16], []
ORA-10567: Redo is inconsistent with data block (file# 37, block# 94633)
ORA-10564: tablespace APPS_UNDOTS2
ORA-01110: data file 37
出现这个错误后,恢复中断,无法继续,3020错误在Metalink上的解释,主要原因是:
This is called a 'STUCK RECOVERY'.也就是说,在恢复时发现Redo里面记录的信息和被恢复的数据块信息不一致,导致恢复无法继续。比如Update Some record from 3 to 2,结果发现该记录根本不是3,恢复无法继续。
There is an inconsistency between the information stored in the redo
and the information stored in a database block being recovered.
这个错误可能是由于写Redo的某个操作丢失,这可能是由于异常宕机或存储故障导致的。
This error can be reported if any of these updates are lost for some reason.
出现这个错误,如果没有备份,数据也不是特别重要,则可以通过一些隐含参数或强制手段来打开数据库,不过不可避免的会出现数据损失,Olive做过一次这样的尝试 。
这次处理这个案例,最后选择了不完全恢复,补录数据,有时候放弃也是一种恢复!
-The End-
相关文章|Related Articles
- kcbgtcr 错误小记
- ORA-600 kcbzpbuf_1 坏块的恢复案例一则
- ORA-600 17285 错误 与 PL/SQL Developer
- Oracle HowTo: How to deal with Ora-600 4193 error
- Oracle Diag:如何处理ORA-600 2662错误
评论数量(0)|Add Comments
本文网址:http://www.eygle.com/archives/2010/03/ora_00600_3020.html
- Plays well with othersA few years ago MySQL+memcached and PostgreSQL+memcached were the only choices for high-scale applications. That has changed with the arrival of NoSQL. Change is good. Open-source monopolies are not much better than closed-source ones from the pers..
- 一位大陆学者到台湾的所见所闻:你所不知道关于台湾的N个细节Shared by orczhou 你是台湾人?你想统一吗? 感谢喷饭 那谁 的分享: 台湾不“禁摩”的原因:要优先考虑“弱势群体”的利益 到台湾的第一个早晨,是被摩托车的噪音叫醒的。拉开窗帘,不远处是一个十字路口,数十上百辆摩托黑压压地停在人行道后面,骑士们都戴着安..





















