DBA日记 第一部(30) (补) ORA-4030和内存泄露
这几天在整理DBA日记所以很久没有更新了。这是补充6月1日的日记,并且在日记里增加了每日一技,会针对当天遇到的问题,介绍一些技术和工作技巧。以前各个章节的每日一技就不补充了,等以后一起发布吧。
6月1日 ORA-4030和内存泄露
一大早过来就看了看昨天晚上录制的数据,快进了半天也没看到什么特殊的东西,干脆不看了,打电话问了几个昨天晚上做账务处理的人,大家都说比较正常,除了速度比上个月更慢了一些以外,没有性能下降特别多的模块。账务处理的速度每个月都是线性下降的,所以大家都觉得很正常,并没有什么特别的地方。既然大家都没觉得什么,昨天晚上录制的东西也就懒得去看了。不过看录像的时候突然发现这台安装OMS服务器的微机速度比我那台借来的老掉牙的笔记本快多了,干脆用这台电脑工作吧,用那台电脑起码降低1/3的工作效率。
由于优化的方案基本上都确定了,剩下的事情老于他们在做细化。SQL优化的工作有老熊帮忙,我也轻松了许多。前面几批提交的3、40个SQL的优化方案也分析的差不多了,大部分都已经由张工转发给了开发商。由于昨天电脑故障,今天我主要的工作还是在现有的电脑上安装相关的工具,拷贝相关的文件。
这几天系统虽然负载很重,不过这种情况已经持续了快一年了,所有的人也都没有感觉什么不适应的地方。中午快吃午饭的时候,张工突然打电话过来,说他们那边有一个数据库出现了ORA-4030错误。由于那套系统并不在我们合同范围之内,因此张工很委婉的问我有没有时间,帮她们看看。使用张工给我的账号密码登录到了系统里。发现报错的信息是:
ORA-04030: out of process memory when trying to allocate 2097192 bytes (joxcx callheap,ioc_allocate ufree)
Current SQL statement for this session:
call CRM_OPER.oper(:1,:2)
----- PL/SQL Call Stack -----
object line object
handle number name
c000000100da8108 0 package SYS.XMLNODECOVER
c000000100dada80 381 package body SYS.XMLDOM
c000000103a1d178 77 package body CRM.CRM_OPER
看到这个错误信息,首先我查看了一下ulimit,发现ulimit设置很正常,没有可能导致故障的设置。检查物理内存的使用情况,发现物理内存还有一些空闲,虽然不是很多,不过也就300多兆。SWAP区的使用率相当高,高达98%。从这一点上可以看出,不久前系统曾经出现过十分严重的换页现象。从CALL STACK中我们可以看出,这是CRM.CRM_OPER在调用XMLDOM包的时候报错。DOM操作是十分消耗内存的,这回报错的是一次申请2M的内存空间。看到DOM操作我的第一个反应就是是不是DOM对象使用后没有释放。于是马上找到CRM_OPER的代码进行分析,有一段代码引起了我的注意:
parser := xmlparser.newParser;
xmlparser.parseBuffer(parser,operInfo);
doc := xmlparser.getDocument(parser);
xmlparser.freeParser(parser);
虽然xmlparser被释放了,而Documentation对象DOC并没有释放。Doc是一个dom对象,如果不释放,DOM对象所占的空间将会随着调用的增加而叠加,最终导致物理内存被耗尽。为了证实这个猜测,首先编写一个测试程序:
create or replace procedure oper is
parser xmlparser.Parser;
doc sys.xmldom.DOMDocument;
operInfo varchar2(2000);
i integer;
begin
operInfo:='<?xml version="1.0" standalone="yes" ?>';
operInfo:=operInfo||'<QUERY_LIST>';
operInfo:=operInfo||'<LIB NAME="areasQueries" VER="2.2.0.7.0" REP_VER="0.0" MIN_INST_VER="2.1.0.4.1" INV_LOC="Queries21/areasQueries/2.2.0.7.0/areasQueries.jar"/>';
operInfo:=operInfo||'</QUERY_LIST>';
i:=0;
parser := xmlparser.newParser;
xmlparser.parseBuffer(parser,operInfo);
doc := xmlparser.getDocument(parser);
xmlparser.freeParser(parser);
-- xmldom.freeDocument(doc);
i:=i+1;
end;
/
分别进行2次测试,第一次不执行xmldom.freDocument(doc),第二次执行该语句。通过下面的方法调用:
declare
i integer;
begin
i:=0;
loop
oper;
i:=i+1;
exit when i>100;
end loop;
end;
/
每调用一次,通过下列语句检查PGA的情况:
select value, n.name|| '('||s.statistic#||')'
from v$sesstat s , v$statname n
where s.statistic# = n.statistic#
and n.name like '%ga memory%'
and sid= <sid of problem session>;
首先进行一次调用freeDocument的测试,查看UGA和PGA的使用情况。在调用前,结果是:
-------------------------------------
142476 session uga memory(15)
207940 session uga memory max(16)
710024 session pga memory(20)
1037704 session pga memory max(21)
第一次执行后的情况:
-------------------------------------
207940 session uga memory(15)
273404 session uga memory max(16)
8165056 session pga memory(20)
8165056 session pga memory max(21)
第二次执行后的情况:
-------------------------------------
207940 session uga memory(15)
273404 session uga memory max(16)
7882672 session pga memory(20)
10734088 session pga memory max(21)
可以看出随着调用次数的增长,PGA和UGA并没有明显的增长。下面修改一下测试程序,将freeDocument的部分去掉。没执行的时候PGA情况:
-------------------------------------
77012 session uga memory(15)
142476 session uga memory max(16)
776488 session pga memory(20)
842024 session pga memory max(21)
执行第一次后的情况:
-------------------------------------
142476 session uga memory(15)
207940 session uga memory max(16)
5188024 session pga memory(20)
5253560 session pga memory max(21)
执行第二次后的情况:
-------------------------------------
142476 session uga memory(15)
207940 session uga memory max(16)
5126608 session pga memory(20)
5253560 session pga memory max(21)
通过WINDOWS任务管理器观察ORACLE进程的物理内存情况可以得出类似的结果。就是如果释放DOM对象,PGA内存不会持续增长,如果不释放DOM对象,PGA内存会越占越多。通过WINDOWS任务管理器可以看出,执行200次存储过程,ORACLE进程的内存使用增加了200M。从上述测试中可以得出结论,由于没有释放DOCUMENT对象,导致了内存泄露。我把这个结果告诉了张工,他和开发人员确认了一下,确认这个模块是昨天下午才上线的一个应用调用的,程序员也确认不释放DOCUMENT对象是错误的。
处理完这个小故障,已经是中午的12点半了。办公室里除了老于其他人都去吃饭了。我急忙锁了屏幕,和老于下楼去吃饭。中午吃饭的时候,老于一直比较沉默,我问他是不是有什么心事。他说有点想家,老于家就是锦州的,原计划这个周末回家休息一下,由于6号要做实施,这个计划只能泡汤了。做DBA的,很多象老于那样,一年到头没有多长时间能够和家里人团聚。
0.1.1. 每日一技 如何分析ORA-4030
ORA-4030一般来说是进程从操作系统申请内存的时候,操作系统无法分配内存引起的。一般来说ORA-4030可能是几方面原因引起:操作系统无法从物理内存和SWAP区分配内存给进程,或者进程受到了操作系统的某个限制条件的约束无法分配更多内存。还有可能就是碰到了某个ORACLE的BUG。
碰到出现ORA-4030,首先我们需要检查的是操作系统的物理内存和SWAP区是否满了。如果物理内存所剩无几,并且SWAP区接近或者达到100%,那么就是真正的内存不足了。一般情况下这种现象出现的较少,大多数ORA-4030是由于进程或者操作系统参数限制引起。
如果我们发现物理内存还有很多剩余,那么下一步需要检查的是oracle账户的ulimit参数。比如:
SUN OS:
/tmp/oralog>>> ulimit -a
time(seconds) unlimited
file(blocks) unlimited
data(kbytes) unlimited
stack(kbytes) 8192
coredump(blocks) unlimited
nofiles(descriptors) 256
vmemory(kbytes) unlimited
HP-UX:
$[/oracle]ulimit -a
time(seconds) unlimited
file(blocks) unlimited
data(kbytes) 1048576
stack(kbytes) 131072
memory(kbytes) unlimited
coredump(blocks) 4194303
nofiles(descriptors) 2048
AIX:
[/home/oracle9i]#ulimit -a
time(seconds) unlimited
file(blocks) unlimited
data(kbytes) unlimited
stack(kbytes) 65536
memory(kbytes) unlimited
coredump(blocks) 2097151
nofiles(descriptors) unlimited
其中的DATA,STACK,MEMORY等参数过小都可能引起ORA-4030。一般来说这些参数建议设置为-1(unlimited)。如果ulimit参数没有问题,那么也可能是其他操作系统内核参数引起。我们可以使用下面一个程序去测试一下,一个进程能够分配到的物理内存的大小:
/* mem.c */
#include <stdio.h>
#include <errno.h>
main()
{
long int i;
i = 1;
for(;;)
{
if (!malloc(1048576))
{
printf("malloc failed with error: %u at iteration %u\n", errno,i);
exit(-1);
Permalink
No Comments
DBA日记 第一部 (28) 6月18日 准备收工
早上8点多和小齐会合后一起来到浑南的省公司。老方本来也要来,被吉林的事情绊住了。昨天晚上我和老于都没睡好,老于的眼睛红红的,我也一直打着哈欠。看样子小齐也没睡好,脸色有点白。我开玩笑的说女孩子别有太多心思,老得快。可能大家心里都有些忐忑,这个玩笑也没有达到应有的效果。我打了个电话给小孙,问他昨天模块上线的情况以及现在系统的情况。小孙告诉我,昨天晚上他们原计划上线的14个模块,最终上线了6个,其他模块领导临时决定暂时不上了。因为新版本升级后,这几个模块要大改,目前上线意义不大。小孙不会监控系统,不过从应用那边看,几个服务器的性能都不错,和昨天的感受差不多。我让小孙和下面的营业厅联系联系,看看今天的系统情况,有事立即通知我。到了会议室,张工正在安排投影,我看他的笔记本通过无线连载DCN网上,就通过张工的笔记本连到服务器上,查看了3台服务器的状态,都比昨天的指标略好一些,看来昨天上线的6个模块表现还是不错。大家看到这个情况,心里踏实多了。
孙主任临时有点事,晚了10多分钟才到了会场。之前和张工他们聊了聊目前系统的情况,他们对优化的效果都感到比较满意。张工问我系统性能提升的比例大概有多少,是不是能够超过30%的预期。我说现在还没做评估,还不好说,不过以我的经验,超过1倍应该没问题,远远高于30%的预期。孙主任一到现场首先向我们表示祝贺,他来之前也让人和几个营业厅确认过了,今天系统状态十分好,好几个常用模块都比以前快很多。
今天的会议比较正式,首先老于向甲方汇报了到目前为止所做的优化,以及达到的效果。然后开发商也汇报了应用修改的情况,按照开发商的统计,他们对我们提出的应用修改,已经100%完成修改,超过90%的模块都已经上线,剩下没上线的是从业务角度考虑,准备在下一个小版本升级的时候一起做。
由于优化目的基本达到,因此这次小结会开得比较轻松,集团公司的领导也通过电话会议参加了讨论。会上大家一致同意本次优化到此为止,不再进行下一次微调。随后就是后续的一些安排。我明天就可以回家了,老于还要再观察几天,下周也可以撤离现场。在7月1号,大家回到沈阳,进行账期数据的收集,以便于完成最终的性能评估报告。7月7日-10日进行验收。随后安排一次北方公司的性能优化研讨会,在该研讨会上,以沈阳的案例,介绍系统性能优化的方法与技术,对北方公司的DBA进行一次全面的培训。在这段时间里,我们需要初步完成系统分析报告、性能评估报告、优化方案等正式文档。
会议结束后,我和老于先下楼,老于的烟瘾又犯了,出了门马上把烟点上。小齐还在和孙主任确认一些事情,我们在楼下等他。我也向老于要了一支烟点上,绷得很紧的神经终于松弛了下来。就这样结束了,心里放下了一块石头,反而觉得空落落的。
中午和小齐一起在北站旁边的新洪记吃了顿饭。心情高兴,多喝了几杯,下午就直接和老于一起回到酒店。想着下午到中街去买点沈阳土特产。老于建议晚上去刘老根大舞台看场二人转,就住在大舞台边上,一直也没心思去看,老于这个建议马上得到了我的响应。打了个电话给酒店前台,问问能不能帮助订票。忙了半天,买了两张200块的票,原价180的,黄牛还不算黑,不过是二楼的,离舞台比较远。
下午接到了万隆的李科的电话,问我有没有时间,帮他们的系统做一个调优,经费已经申请下来了,总共十五万,他们出一半,集成商出一半,合同可以随后走流程,只要我们尽快进场做就可以了。万隆的系统问题很大,集成商在做软件开发的时候底层设计存在问题,导致每年7、8、9三个月业务高峰期的时候年年会出问题。我一年前和李科讨论过,希望大家一起坐下来,把底层的应用架构和数据字典调整好,这样就可以一劳永逸的解决问题。当时我提出的价格就是十五万,不过当时他们觉得价格太贵,没地方出这笔经费,这件事就作罢了。没想到李科还记着这个事情,而且运作出了这个项目。经过一年的运行,我估计万隆的系统比一年前更加恶化了,这个优化项目活不好干,可能成为一个吃力不讨好的项目。而且沈阳的项目刚刚结束,我也想好好休息一下,不想连续去碰硬骨头,所以这个项目我的初步想法就是推掉。不过李科一副死缠烂打的架势,搞得我也不好彻底推掉,只是说先给我开个VPN,我先安排人上去看看,了解一下我们能不能搞定再做决定。
放下电话后,和南京的阿罗联系了一下,让他有空VPN上去看看系统的情况。我再三嘱咐阿罗,这个系统问题很大,我们还没决定是不是要接这个项目,因此登上去后,只能看,不能动任何的东西。并且这个系统十分关键,千万不能出问题,VPN账号不要透露给公司的其他人,只有他一个人知道就行了。
嘱咐完阿罗,老于的电话就进来了,两个人一起喝了点小酒就去刘老根大舞台看二人转去了。小时候也经常听二人转,不过今天看赵本山的弟子演出的二人转,还是感到十分过瘾。演出刚开始的时候报幕员说的赵本山今天也在沈阳,如果能安排的开,会亲自表演一个节目。虽然最后由于时间错不开,赵本山只是出面打了个招呼就走了,不过看到这么一场演出,感觉200块钱花的还是很值的。
美食杂谈之扬州炒饭
据说扬州市政府要规范扬州炒饭,并且注册知识产权,不禁想起了近20年前的一件事。那时候还在南京读大学,大概是90年吧。一次和一个广东的同学一起烟花三月下扬州,到扬州游玩。中午的时候,广州的同学一定要拉我去吃扬州炒饭,据说他老豆对扬州炒饭情有独钟,偶尔会带上他到街坊的茶餐厅点上一份扬州炒饭解馋。既然到了扬州炒饭的老家,当然要尝尝最正宗的扬州炒饭了。不过我们在大街上问了好几家小餐馆,都没有卖这道菜的。后来以为可能扬州炒饭在扬州可能属于高档酒店的美食,也就没有过多的追究了。
毕业后到了深圳,发现大街小巷几乎每个餐馆都会提供这道扬州炒饭。价格便宜,2、3块钱一份,而且量又足。在广东,扬州炒饭是工薪阶层常吃的快餐之一,基本可以和桂林米粉有一拼。有一次和一个老广东一起工作,我就又想起了在扬州没有遇到卖扬州炒饭的地方的事情,问他是否知道扬州炒饭的来源。那老兄是家住西关的老广,偏爱美食,对各种美食掌故也是了如指掌。
据他所说,扬州炒饭实际上起源于香港,大约是清末民初的时候,香港有家扬州菜馆,推出了一道通过扬州名菜三鲜锅巴改良来的锅巴菜,起名叫扬州锅巴。一经推出就风靡香港。后来大三元的一个厨师就用扬州锅巴的材料(青豆、胡萝卜、火腿)加上鸡蛋,炒制炒饭,命名为扬州炒饭,其愿意是想借扬州锅巴来宣传自制的炒饭。后来扬州炒饭就名扬省港,甚至现在连扬州都为扬州炒饭编了一个和隋炀帝下扬州的故事。
其实淮扬菜偏咸偏甜,根本做不出扬州炒饭这样的菜式,整个江浙菜系里面也根本找不到炒饭这种传统小吃。炒饭本事一种家里冷饭利用的家常做法。很多家庭都经常将冷饭热一下再吃。讲究一点的人家就放点油盐炒一下,再讲究一点的就打上一个鸡蛋。而扬州炒饭说白了就是一种豪华版本的家常炒饭,里面加上火腿、青豆、胡萝卜等,其主要用途除了增加口感外,在感官上也可以刺激食欲。
在深圳过了差不多10年的单身生活,炒饭当然也是吃了不少,街头小餐馆或者茶餐厅的扬州炒饭往往过于油腻,而且随着地沟油的出现,对这种东西也不太敢于光顾了。不过偶尔嘴馋的时候,还是会自己下厨房炒制一下。久而久之,总结出了一套炒饭的秘诀。
炒制扬州炒饭的用料可以随意,根据喜好就行了。传统的扬州炒饭必须有青豆,或萝卜和火腿丁。如果没有火腿肉,也可以用超市里那种方腿、火腿肠替代。不过如果是真的火腿,最好泡过,蒸制过,生火腿不宜炒熟,并且会带有一点腥味。也可以准备一点鲜虾仁之类的东西,不过扬州炒饭的辅料不要用口味特别重或者味道特别霸道的,选择平和一点的辅料。另外一样辅料就是葱,蒜不是必须的,不过准备少许爆香还是不错的。
扬州炒饭的主料当然是米饭,米饭最好选用硬一点的,看到网上建议使用隔夜的米饭。其实也不一定非要隔夜,把米饭放到冰箱里冰一会也能起到脱水的作用。不过从根本上来说,煮饭的时候稍微偏硬一点是关键。
炒饭的技巧也十分重要,首先热油放蒜末爆香,低油要足,然后爆炒葱及辅料。等锅里的油温再次升起来后,再放入蛋液将鸡蛋和辅料一起炒熟,盛好待用。
然后就是炒制米饭。现在人喜欢少油,因此炒米饭的时候尽量少放油,甚至可以用刚才炒辅料的剩油来炒制米饭。将锅烧热,然后再放入米饭,米饭下锅前最好用筷子拨松。如果没有放油或者油很少,米饭下锅后开小火,用锅铲将米饭拨开,瘫在锅底,慢慢加热,除去水分。
这个时候如果家里有一些浓汤,比如炖肉剩下的汤,可以放入米饭中,以增加米饭的香味。不过加入汤的时候不能一次性加入,而要一点一点的加入。加一点就翻炒一下搅拌均匀,并且除去多余的水分。米饭炒好后就可以加入辅料以及盐和鸡精,一起翻炒几下,搅拌均匀就可以出锅了。
对于米饭的处理,还有一种比较讲究的做法是米饭下锅前先将部分蛋液倒入米饭中搅拌均匀,然后再去炒制,炒出来的米饭是金黄的,卖相十分好。不过蛋液不宜太多,否则必须用较多的油,而且火候不宜把握。
扬州炒饭是单身青年的方便食品,大家有兴趣也可以试试。多做几次,就能推陈出新,发扬广大了。真的十分感谢发明扬州炒饭的那个香港厨师。
一个奇怪的ROW CACHE OBJECTS等待
有个客户的系统中某个模块突然变得十分慢,以前每小时处理1万必业务,今天每小时只能处理1000笔业务。大量的业务堆积,使客户感到十分头痛。从V$SESSION_WAIT看,存在大量的LATCH FREE等待,从STATSPACK报告上看:
Load Profile
~~~~~~~~~~~~ Per Second Per Transaction
--------------- ---------------
Redo size: 606,513.75 10,096.93
Logical reads: 263,689.83 4,389.77
Block changes: 3,438.74 57.25
Physical reads: 817.62 13.61
Physical writes: 319.30 5.32
User calls: 9,289.06 154.64
Parses: 2,764.50 46.02
Hard parses: 334.28 5.56
Sorts: 1,460.77 24.32
Logons: 3.53 0.06
Executes: 2,808.80 46.76
Transactions: 60.07
Instance Efficiency Percentages (Target 100%)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Buffer Nowait %: 97.29 Redo NoWait %: 100.00
Buffer Hit %: 99.75 In-memory Sort %: 100.00
Library Hit %: 93.44 Soft Parse %: 87.91
Execute to Parse %: 1.58 Latch Hit %: 88.50
Parse CPU to Parse Elapsd %: 74.96 % Non-Parse CPU: 88.71
Top 5 Timed Events
~~~~~~~~~~~~~~~~~~ % Total
Event Waits Time (s) Ela Time
-------------------------------------------- ------------ ----------- --------
latch free 44,261,551 122,352 46.29
CPU time 44,436 16.81
buffer busy global CR 24,549,325 29,212 11.05
db file sequential read 2,298,542 23,234 8.79
wait list latch free 810,305 17,562 6.64
-------------------------------------------------------------
LATCH FREE等待占了46.29%。经过检查,发现是ROW CACHE OBJECTS等待十分严重。初步怀疑在某张表上,客户在前一天晚上对这张表做了一些修改。询问应用开发部门,他们都不承认做了操作。从数据库上看,并没有多大的问题。通过HANGANALYZE看:
存在大量的HANG住现象:
Found 26 objects waiting for <cnode/sid/sess_srno/proc_ptr/ospid/wait_event>
<1/270/2196/0x47a8100/1259/No Wait>
Found 10 objects waiting for <cnode/sid/sess_srno/proc_ptr/ospid/wait_event>
<1/1238/35370/0x4784820/966/latch free>
Found 14 objects waiting for <cnode/sid/sess_srno/proc_ptr/ospid/wait_event>
<1/373/3688/0x47b9ae0/2253/No Wait>
Found 11 objects waiting for <cnode/sid/sess_srno/proc_ptr/ospid/wait_event>
<1/855/23311/0x47a76c0/1253/latch free>
Cycle 1 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/754/1937/0x47add40/1310/latch free>
-- <1/905/1505/0x47ac3a0/1302/latch free>
-- <1/71/1827/0x479e220/1161/latch free>
Cycle 2 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/1238/35370/0x4784820/966/latch free>
-- <1/125/2442/0x47b8660/1720/latch free>
-- <1/905/1505/0x47ac3a0/1302/latch free>
-- <1/71/1827/0x479e220/1161/latch free>
-- <1/508/4711/0x47ae780/1329/latch free>
-- <1/855/23311/0x47a76c0/1253/latch free>
-- <1/531/2223/0x47ab440/1286/latch free>
Cycle 3 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/508/4711/0x47ae780/1329/latch free>
-- <1/855/23311/0x47a76c0/1253/latch free>
Open chains found:
Chain 1 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/238/45371/0x47b90a0/2307/global cache cr request>
-- <1/508/4711/0x47ae780/1329/latch free>
-- <1/855/23311/0x47a76c0/1253/latch free>
-- <1/531/2223/0x47ab440/1286/latch free>
-- <1/1239/12911/0x47a71a0/1249/latch free>
-- <1/562/765/0x47ae260/1335/latch free>
-- <1/33/24430/0x47ac8c0/1298/latch free>
Chain 2 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/270/2196/0x47a8100/1259/No Wait>
-- <1/562/765/0x47ae260/1335/latch free>
-- <1/33/24430/0x47ac8c0/1298/latch free>
Chain 3 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/373/3688/0x47b9ae0/2253/No Wait>
-- <1/1239/12911/0x47a71a0/1249/latch free>
-- <1/562/765/0x47ae260/1335/latch free>
-- <1/33/24430/0x47ac8c0/1298/latch free>
Chain 4 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/927/2464/0x47b67a0/2112/No Wait>
-- <1/744/287/0x46f12a0/2057/latch free>
-- <1/460/1881/0x47afc00/1344/latch free>
-- <1/71/1827/0x479e220/1161/latch free>
-- <1/508/4711/0x47ae780/1329/latch free>
-- <1/855/23311/0x47a76c0/1253/latch free>
-- <1/531/2223/0x47ab440/1286/latch free>
-- <1/1239/12911/0x47a71a0/1249/latch free>
-- <1/562/765/0x47ae260/1335/latch free>
-- <1/33/24430/0x47ac8c0/1298/latch free>
Other chains found:
Chain 5 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/2/7/0x468a060/7842/No Wait>
Chain 6 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/40/55347/0x46958e0/2392/latch free>
Chain 7 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/113/8784/0x47a9aa0/1276/enqueue>
Chain 8 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/134/24816/0x47b7c20/1711/latch free>
-- <1/614/18700/0x47ba000/2353/latch free>
Chain 9 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/135/577/0x47a9060/1280/latch free>
-- <1/1191/36393/0x4762e00/706/latch free>
Chain 10 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
经过多次HANGANALYZE看到,目前的状态主要是比较慢,并不是真正的HANG住。过一段时间做的HANGANALYZE,BLOCKER和BLOCKED是不停变化的。
由于在另外一个地方做另外一个项目的支持,所以我也没有太多的时间协助客户做详细的分析。也就没有仔细阅读STATSPACK报告。不过以我的经验,这种情况往往和应用系统的某些变化有关。询问了开发部门,他们都说没有修改过数据字典,也没有异常的操作。这种回答也给了我很大的误导,当时把重点放到了ROW CACHE OBJECTS的分析上,重点放在了共享池方面。最后证明,这是极其错误的。
基于上述分析,首先决定针对共享池进行操作。刷新共享池,系统没有任何改善。无奈之下,客户只好重启服务器,服务器重启后,状态依然。看样子肯定是应用出了问题。回过头再分析STATSPACK报告,刚才一直萦绕在心头的一个问题终于又引起了我的注意:
Instance Efficiency Percentages (Target 100%)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Buffer Nowait %: 97.29 Redo NoWait %: 100.00
Buffer Hit %: 99.75 In-memory Sort %: 100.00
Library Hit %: 93.44 Soft Parse %: 87.91
Execute to Parse %: 1.58 Latch Hit %: 88.50
Parse CPU to Parse Elapsd %: 74.96 % Non-Parse CPU: 88.71
BUFFER BUSY WAIT等待十分严重。并且buffer busy global CR等待也十分严重。客户的系统虽然是RAC,但是两个节点之间共享的数据十分少,而且共享数据基本上遵循在某个节点上写操作的,在另外一个节点上尽可能不做写操作。这种情况下,buffer busy global CR不可能存在这么大的问题。一份HANGANALYZE的信息引起了我的注意:
Chain 1 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/523/25/0x772efc0/10816/buffer busy global CR>
-- <1/601/97/0x7747f80/11045/latch free>
-- <1/832/136/0x7788080/12069/latch free>
-- <1/820/374/0x778b8e0/12055/latch free>
-- <1/837/177/0x778ec20/12144/latch free>
-- <1/705/38/0x7768f60/11419/latch free>
-- <1/611/21/0x774ada0/11075/latch free>
-- <1/760/86/0x777b8a0/11724/latch free>
-- <1/600/7/0x7747540/11041/latch free>
-- <1/520/59/0x772db40/10818/latch free>
Chain 3 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/769/286/0x7782e80/11835/buffer busy global CR>
-- <1/738/33/0x7773880/11611/latch free>
-- <1/524/5/0x772eaa0/10812/latch free>
-- <1/845/46/0x7790ae0/12204/latch free>
-- <1/820/374/0x778b8e0/12055/latch free>
-- <1/837/177/0x778ec20/12144/latch free>
-- <1/705/38/0x7768f60/11419/latch free>
-- <1/611/21/0x774ada0/11075/latch free>
-- <1/760/86/0x777b8a0/11724/latch free>
-- <1/600/7/0x7747540/11041/latch free>
-- <1/520/59/0x772db40/10818/latch free>
Chain 7 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/825/255/0x778d280/12061/buffer busy global CR>
-- <1/777/9/0x777a940/11716/latch free>
-- <1/520/59/0x772db40/10818/latch free>
Chain 8 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/831/119/0x778cd60/12122/buffer busy global CR>
-- <1/845/46/0x7790ae0/12204/latch free>
-- <1/820/374/0x778b8e0/12055/latch free>
-- <1/837/177/0x778ec20/12144/latch free>
-- <1/705/38/0x7768f60/11419/latch free>
-- <1/611/21/0x774ada0/11075/latch free>
-- <1/760/86/0x777b8a0/11724/latch free>
-- <1/600/7/0x7747540/11041/latch free>
-- <1/520/59/0x772db40/10818/latch free>
Chain 10 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/842/108/0x77900a0/12176/buffer busy global CR>
-- <1/520/59/0x772db40/10818/latch free>
Chain 11 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/846/15/0x7791520/12190/global cache cr request>
-- <1/600/7/0x7747540/11041/latch free>
-- <1/520/59/0x772db40/10818/latch free>
Chain 12 : <cnode/sid/sess_srno/proc_ptr/ospid/wait_event> :
<1/867/46/0x7794860/12346/buffer busy global CR>
-- <1/823/175/0x77861c0/12028/latch free>
-- <1/741/3/0x77742c0/11601/latch free>
-- <1/783/32/0x7781f20/11807/latch free>
-- <1/520/59/0x772db40/10818/latch free>
通过检查v$segment_statistics和V$CR_BLOCK_TRANSFER,发现有一张表的CR BLOCK TRANSFER是最活跃的,而这张表就是这个业务出问题的那张表。我再次咨询了开发部门,提出了我的疑问,并把我找到的证据发给了他们。两个小时后,系统突然恢复正常。
由于关键业务系统白天营业时间停机,主管领导一定要搞清楚具体原因。在强大的政治攻势下,开发部门终于承认,早上在另外一个节点上对这张表的200万条记录进行UPDATE。UPDATE操作特别慢,几个小时后,他们杀掉了UPDATE的进程。
ORA-00600 [kkxprpic8]
数据库出现:
Fri Nov 28 09:27:00 2008
Errors in file /home/oracle9i/admin/ora9i/udump/ora9i2_ora_6615.trc:
ORA-00600: internal error code, arguments: [kkxprpic8], [], [], [], [], [], [], []
这个ORA-600错误一般出现在9.2.0.8环境,查看日志信息:
ksedmp: internal or fatal error
ORA-00600: internal error code, arguments: [kkxprpic8], [], [], [], [], [], [], []
Current SQL statement for this session:
INSERT INTO TB_RM_MIN_NBR (MIN_ID, MIN, MIN_GRP, INPUT_STAFF, INPUT_DATE, USE_STATE, USE_STAFF, USE_SITE, SERV_ID) SELECT SQ_RM_MIN_
NBR_ID.NEXTVAL, IB_MIN, PG_CDMA_RM_NEW.TRAN_MIN_TO_MINGRP(IB_MIN_GRP), 'C_GJ', C_OPER_DATE, IB_MIN_STATE, NULL, 0, IB_SERV_ID FROM M
ID_CARD_PHONE_MIN_INFO M WHERE M.C_OPER_DATE = (SELECT MAX(N.C_OPER_DATE) FROM MID_CARD_PHONE_MIN_INFO N WHERE M.IB_MIN = N.IB_MIN G
ROUP BY IB_MIN HAVING COUNT(*) >= 1)
----- PL/SQL Call Stack -----
object line object
handle number name
c00000102dd6d620 1687 package body ZQIB.PG_CDMA_RM_NEW
c00000102dd6d620 1518 package body ZQIB.PG_CDMA_RM_NEW
c00000102dd6d620 28 package body ZQIB.PG_CDMA_RM_NEW
c00000104f5a74f8 1 anonymous block
在存储过程ZQIB.PG_CDMA_RM_NEW的时候报错。通过日志查看这个存储过程的信息:
LIBRARY OBJECT LOCK: lock=c00000102c122418 handle=c00000102dd6d620 mode=N
call pin=c00000102c1241c8 session pin=0000000000000000
htl=c00000102c122488[c00000102c1222f0,c000001051799268] htb=c000001051799268
user=c000000fe86436f0 session=c000000fe86436f0 count=1 flags=PNC/[04] savepoint=25053
LIBRARY OBJECT HANDLE: handle=c00000102dd6d620
name=ZQIB.PG_CDMA_RM_NEW
hash=ccb300c5 timestamp=11-28-2008 09:16:45
namespace=BODY/TYBD flags=KGHP/TIM/SML/[02000000]
kkkk-dddd-llll=0000-0039-00bf lock=N pin=S latch#=61
lwt=c00000102dd6d650[c00000102dd6d650,c00000102dd6d650] ltm=c00000102dd6d660[c00000102dd6d660,c00000102dd6d660]
pwt=c00000102dd6d680[c00000102dd6d680,c00000102dd6d680] ptm=c00000102dd6d710[c00000102dd6d710,c00000102dd6d710]
ref=c00000102dd6d630[c00000102dd6d630, c00000102dd6d630] lnd=c00000102dd6d728[c00000102dd6d728,c00000102dd6d728]
LOCK INSTANCE LOCK: id=LC5e044cb94e42b0e4
PIN INSTANCE LOCK: id=NC5e044cb94e42b0e4 mode=S release=F flags=[00]
INVALIDATION INSTANCE LOCK: id=IV0008de6b1c0a112e
LIBRARY OBJECT: object=c00000102dd39de8
type=PKBD flags=EXS/LOC[0005] pflags=/DBG [02]status=INVL load=0
DEPENDENCIES: count=66 size=80
READ ONLY DEPENDENCIES: count=105 size=112
ACCESSES: count=75 size=80
TRANSLATIONS: count=41 size=48
从上面可以看到status-INVL,一个正在执行的存储过程怎么可能是INVL状态呢?经确认,在存储过程执行过程中,TB_RM_MIN_NBR 上面被人做了DDL操作,从而导致存储过程失效。事后检查该存储过程,发现该存储过程的状态是VALID,重新执行该存储过程,故障消失。
以开放的心态来做服务
DBA这个圈子比较保守,一般不愿意把自己的独门绝技传人。而我们做服务一直用一种开放的心态,对客户的要求有求必应。记得有一次给客户做一个巡检,结束后我把文档拷贝在U盘上交给客户,客户犹豫了半天,问我,你的那些脚本能不能留给我。我说在U盘里已经有这些脚本了,我们做完巡检,会把巡检过程全部记录日志,并且会把使用过的脚本全部提交给客户。
和江苏电信合作3年多了,一直和他们比较融洽,主要的原因就是我们从来不保守,客户需要什么资料我们会原封不动的提供。客户咨询什么问题,我们会以很详细的报告提交。我一直要求大家写报告的时候一定要清晰明了,没必要隐瞒什么。
我经常和客户说我们的服务理念,目前客户处于A点,我们处于B点,B点高于A点,而我们做服务的一个很重要的任务是使客户的技术从A点向B点迈进,而在这个时候,我们自己在从B点向C点前进。当客户达到B点的时候我们已经达到了C点,这个时候我们就可以帮助客户从B点向C点前进,而我们也向更高的目标前进。如果是这样一种情况,我们不会害怕客户提高了我们自己就没饭吃了。对于客户而言,我们永远是有价值的,可以帮助他们象更高的目标迈进。
如果做服务的,把自己的技术保护的死死的,那早晚是会做死的。保守就很难进步,时间长了,你的价值就会越来越低。所以我觉得以开放的心态来做服务,让客户在你的帮助下提高,才是根本之道。
谈谈内存分配
这篇文章是我04年写的,现在修改一下发到博客上。
经常有人问我:"我们的系统有XX内存,怎么分配内存合适?"
我的回答是"不知道"。这是一个很无奈的答案,因为这个问题确实无解。每个系统都有不同的特性,如果使用一种通用的模式去分配内存,那么肯定是无法达到目的的。优化内存配置的时候,首先需要注意一些原则性的问题,更为准确的内存分配方法,需要根据科学的评估才能做出。以下几点是笔者在实际工作中总结的内存优化的基本原则:
第一,无论如何分配内存,绝对不能让系统存在较多的换页情况,最好的选择是让系统基本不存在换页。并且随时保留足够的空闲物理内存,以应对突发的业务高峰。宁可让你的DB CACHE命中率较低,也不要为了提高DB CACHE的命中率而过多的使用物理内存,导致物理内存换页。
第二,使用文件系统并不能给ORACLE数据库的IO性能带来好处,因此尽量使用裸设备,如果使用裸设备,SGA和PGA使用内存的总量可以高达70%,甚至更高,但是SGA、PGA、Oracle后台进程、Oracle前台进程、应用进程占用内存的总量一般不要超过系统物理内存总量的90%。上述的参考值仅仅提供参考,不能机械地说SGA和PGA不能占用超过物理内存的60%或者70%,而是要根据你的系统的实际情况进行调整。如果你的系统有很大的物理内存,那么这些指标值还可以更高,只要遵循系统不产生换页操作的原则,那么哪怕你使用了95%甚至更多的物理内存,那么你的配置也是合理的。在海量内存下,如果配置了很大的SGA,那么会消耗大量的CPU资源,因此如果数据库实际不需要使用那么多内存,配置过大的SGA会导致CPU资源的浪费。因此调整SGA的同时要考虑CPU的情况,如果CPU已经出现了瓶颈,加大SGA可能会带来更大的CPU压力。切忌在解决内存问题的同时带来新的性能故障。
第三,在内存允许的情况下,设置足够大的PGA空间,尽量避免硬盘排序。硬盘排序会造成IO压力增大和相应速度大幅度下降,因此在有条件的情况下,提高内存排序比例可以提高系统的性能。如果排序操作很大,而且物理内存也有限,那么产生部分硬盘排序也是正常的。但是如果系统中存在大量的multi-pass的硬盘排序,那么就应该加大PGA空间了。
第四,在一般情况下,共享池和各个数据块缓冲池的命中率尽量保持在95%以上(OLAP应用除外)。由于每个应用都有不同的特点,命中率指标不一定能够完全表现出数据缓冲池的实际情况,但是在大多数情况下,这个命中率具有一定的代表性。如果在使用多缓冲的情况下,总体的命中率指标超过95%不能证明数据库缓冲池没有问题。通过检查DEFAULT、KEEP、NK CACHE等的命中率情况,往往能够发现在整体命中率达标的情况下,个别缓冲区性能不佳的问题。
第五、在 Oracle 9i 之前,过大的 shared pool 会导致大量的管理开销,因此不能设置过大的 shared pool(这一点其实也不是绝对的,如果CPU足够强劲的话,一个超过4G的共享池并不一定就会带来性能问题) 。 Oracle 9i 改进了共享池的管理,并且采用了 subpool 机制,使大型共享池的性能得到了很大的改善。笔者曾经在 9i 数据库上使用过超过 5G 的共享池,没有发现由于共享池过大导致�性能问题。在一些移动公司的大型BOSS系统中,超过8GB的共享池也是十分常见的,我曾经见过一个有300G内存的系统,共享池配置了10GB。另外要注意的是,如果已经使用了很大的共享池,还是出现共享池不足的问题,那么调整应用比加大共享池更为有效,另外如果由于某种原因,共享池存在碎片问题,SUBPOOL可能成为一种负面的东西,这个时候禁止使用SUBPOOL会带来好的效果。如果存在较为严重的共享池碎片,那么PX MSG POOL可能会导致经常出现共享池无法分配的情况出现,这种情况下,将PX MSG POOL在LARGE POOL中分配,可以减轻共享池不足的现象,另外减少SESSION_CACHED_CURSORS也会起到好的效果。在一般情况下,过大的共享池是不正常的。过大的共享池也会带来加大 CPU 开销等问题,因此在适当的情况下加大共享池的大小,而不要片面调大共享池,在有些情况下,将 SQL 和 PL/SQL 对象 PIN 到共享池中可能比扩大共享池具有更好的效果。
第六、LOG BUFFER是一个环状的BUFFER,用于将SERVER进程中的REDO LOG信息写入REDO LOG BUFFER中,以便于LGWR将BUFFER的数据写入REDO LOG文件。对于log buffer的设置,过大的log buffer不能改善REDO LOG的性能。一般来说LOG BUFFER的大小在几百K到几兆之间。Oracle 9i的安装指南建议LOG BUFFER的大小是128K*CPU的数量。对于REDO LOG产生量特别大的系统,可以使用这个建议值的数倍。对于一些类似电信计费账务系统的REDO 产生量很大的系统,设置超过10M甚至30M的LOG BUFFER,可能对REDO的性能有帮助。判断LOG BUFFER是否存在性能问题,闩锁REDO SPACE ALLOCATION会存在一定的争用,另外统计值redo log space requests也会出现异常。对于LOG_BUFFER,还有一个最为常见的误区就是超过3M的LOG BUFFER是没有意义的。这个错误的论断出自于LOG BUFFER刷入LOG FILE的规则,其中一个是LOG BUFFER的数据超过1M,就会触发LGWR写,另外就是LOG BUFFER超过1/3就会触发LGWR写。这里就很容易产生一个错误的论断,就是反正超过1M的LOG BUFFER数据就会触发LGWR写,那么超过3M的LOG BUFFER就没有意义了。这个论断忽视了一个问题,就是LOG BUFFER是环状的,在LGWR想LOG FILE中写入数据的时候,LOG BUFFER的尾部还是可以写入REDO 数据的,因此大的LOG BUFFER在某些场合还是有意义的。
第七、一般来说,多数据缓冲池的使用会对系统的性能提高有益。由于缓冲池采用HASH链的方式进行管理,因此对于数据缓冲池很大的系统,管理单个大型缓冲池的开销要远大于管理多个较小缓冲池的开销。使用KEEP池、RECYCLE池以及NK缓冲池可以分散数据的分布,减少由于各种竞争带来的缓冲池的额外开销。
第八、通过工作缓冲(通过*_area_size参数设置)来减少SQL执行过程中使用临时表空间,可以提高SQL的响应速度,减少系统IO。如果是Oracle 9i以前的版本,通过设置合理的工作缓冲区参数,可以实现上述目标。在Oracle 9i以后的版本,可以通过PGA自动管理来管理这些缓冲区, PGA自动管理可以大大提高各种工作缓冲区的使用率,在最小程度占用系统物理内存的情况下,提高各类工作缓冲区的使用率。
第九、LARGE POOL是和SHARED POOL类似的缓冲池,不过只有特定的BUFFER才会在LARGE POOL里分配。第一种情况,在SHARED SERVER模式(旧版本称为MTS)下,UGA空间是从LARGE POOL中分配的;第二种情况,作为顺序文件IO的缓冲区,最典型的就是RMAN备份的时候分配LARGE POOL作为缓冲区,另外从ORACLE 8I开始,如果PARALLEL_AUTOMATIC_TUNING设置为TRUE,那么并行操作的缓冲区也从LARGE POOL里分配。如果没有使用SHARED SERVER,那么系统对LARGE POOL的使用量是很小的,保持50-80M的LARGE POOL就足够了
第十、JAVA POOL是另外一个缓冲池,主要是为ORACLE JVM提供缓冲。如果应用软件很少使用JAVA的存储过程等,那么JAVA POOL不需要设置很大。
第十一、过大的数据块缓冲会导致大量的BUFFER GET扫描,增加CPU的开销。同时维护大量的缓冲池也会带来额外的CPU开销。同样,过大的共享池会导致共享池管理开销的增大。因此片面追求提高命中率的做法是不足取的。按需分配各种缓冲区的大小,不要过度分配缓冲区是一个十分重要的原则。
第十二、9i以后支持的SGA动态调整技术可以为缓冲区动态调整提供了技术手段。DBA可以根据实际情况,随时对SGA的各种缓冲进行调整。
第十三、Oracle 10G提供了自动共享内存管理(ASMM),ASMM机制可以根据系统的状态自动调整共享内存的大小。如果系统不是很大,内存资源比较充分,而且DBA的管理水平不足的话,使用ASMM可以免除DBA这方面的维护工作,使系统保持在一个较好的运行水平上。如果系统种存在性能瓶颈,而且系统的内存资源存在竞争,那么就要慎用ASMM。
DBA的道义
最近发的BLOG主要是从粉丝网的博客上搬过来的,我会逐渐把有价值的文章搬过来。最近比较忙,很久没有写新的案例了,请大家原谅。
前一阵子给客户处理一个故障,这个故障已经重复发生了多次,几乎半个月不到就会重现。在Metalink上开了个tar,由于很多日志缺失,Oracle方面也无法进行继续的分析。
我接到资料后,第一反应是存在BUG,但是随着我分析了几十个类似的BUG后,发现虽然在表象上很类似,但是没有一个真正吻合。通过经验,我将疑点放到了OS上,并提出了优化方案。由于日志方面的缺失,很多东西只能靠猜测。做过调整后,我在报告里提出,这个问题还没有完全定位,如果调整后2个月故障未重现,说明这次调整是成功的,但也不能说是彻底解决了这个问题。因此系统监控还要继续,开的tar也要继续跟进,也许Oracle那边会提出一些好的建议。
客户的系统是一个十分重要的系统,如果出现故障将会承受十分巨大的经济损失,还会导致大客户的流失。因此客户对我的这个结论并不放心。虽然已经过去了半个多月,故障没有重现,但是客户还是不放心,因此他们又找了一家公司协助诊断这个故障,那家公司很快给出了一个故障分析报告,在报告里,用十分肯定的口气确定了这个故障和2个BUG有关。建议客户按照BUG报告上的内容进行处理。
客户告诉我,说问题的原因找到了,北京一家公司,用了不到一天就定位了这个问题。我问他最终的结论是什么,客户就说了那2个BUG,我说你把报告给我看看,肯定有问题,因为这两个BUG我都分析过,其中一个第一时间我也怀疑是问题的根源,后来随着分析的深入被第一时间排除了。另外一个BUG在我们这个平台上根本不肯能存在,因为在我们的平台上根本没有这个模块。后来我也看了这份报告的部分章节,真是一把辛酸泪,满纸荒唐言。整个报告从格式、语气上来说都十分严谨,分析也是丝丝入扣,让人不得不信服。对于缺乏足够专业知识的客户来说,这种报告的杀伤力是巨大的,一切都是用十分肯定的口气,让人觉得十分的可信。我把报告中的疑点一点一点的和客户解释后,他觉得有种上当受骗的感觉。
无疑,那份报告在商业上是成功的,如果没有我的介入,可能这份报告会带来巨大的商业价值。而我写报告的习惯是问题的分析过程十分明晰,我会把我的观点一览无余的告诉客户,包括我无法确定的事实。对于客户来说,最希望的是听到好消息,对于坏消息,他们虽然愿意知道,但是坏消息总是会让他们的心里产生一定的阴影。但是无论如何,我的原则是让客户知道他们应该知道的,我不会隐瞒任何东西,我会把我没有把握的东西第一时间让客户知道,是或者不是或者可能是,我绝对不会乱用词汇,我想这也是一个DBA应有的道德。商业利益是应该建立在一定的道义基础上的,不能为了商业利益而采用欺骗的手段,让客户蒙受更大的损失。因为在第三方服务市场,客户最大的担心就是第三方的服务水平和服务能力。欺骗可以短期内获得商业价值,但是从长期来看,这种方式会导致客户对第三方服务失去信心,从而危及整个行业。我曾经代表原厂去为客户做过一次巡检。巡检结束后,给客户提出了一份详细的报告,客户看了以后告诉我,以前他们是第三方做的服务,做巡检后也发现不了什么问题,比较而言,原厂虽然贵一点,但是更有价值,他们今后将会选择原厂服务。听到这话我感觉很不是滋味,不到位的服务不仅仅意味着丢失一个客户,还可能丢失一个正在兴起的市场。和原厂相比,第三方服务有很多先天的不足,需要用我们更加到位的服务,才能在这个市场中获得一定的份额。
那个问题虽然我已经有了9成把握,但是由于大量的日志缺失,我确实无法100%定位问题,那么如果我在报告里不把疑问列出来,客户可能很放心的放松警惕,放弃了继续的系统进行监控,那么下一次故障发生的时候,客户失去了一次定位问题的机会,遭受更大的损失。
一个ORA-4031的处理案例
客户的一个9207 RAC因为ora-4031导致了宕机。分析4031问题,如果是事后,那么TRACE文件是最好的分析工具,我们来看4031 TRACE里各种对象的情况:
===============================
Memory Utilization of Subpool 1
===============================
Allocation Name Size
_________________________ __________
"free memory " 32773512
"miscellaneous " 15862600
"partitioning i " 0
"sim trace entries " 245760
"gcs resources " 21925568
"PL/SQL DIANA " 401496
"trigger defini " 0
"KQR M PO " 49688
"krvxrr " 253056
"trigger inform " 0
"FileOpenBlock " 6028960
"transaction " 470104
"fixed allocation callback" 376
"replication session stats" 269040
"ges enqueues " 4222088
"KGK heap " 552
"trigger source " 0
"PL/SQL MPCODE " 26448
"errors " 0
"pl/sql source " 0
"sim memory hea " 515944
"ges resources " 85367744
"dictionary cache " 1071104
"PL/SQL PPCODE " 0
"Temporary Tables State Ob" 209968
"parameters " 0
"db_block_hash_buckets " 3924384
"library cache " 2541616
"db_handles " 928000
"sql area " 157400
"sessions " 597584
"KGLS heap " 80272
"gcs shadows " 2519272
"branch " 316616
"event statistics per sess" 2507024
"Checkpoint queue " 1283200
"table definiti " 0
"partitioning d " 0
===============================
Memory Utilization of Subpool 2
===============================
Allocation Name Size
_________________________ __________
"free memory " 33796496
"miscellaneous " 17424112
"KGLS heap " 134008
"transaction " 405408
"trigger defini " 0
"errors " 0
"ges enqueues " 4138672
"PL/SQL MPCODE " 0
"Checkpoint queue " 1283200
"ksm_file2sga region " 370496
"KCL name table " 1471944
"PL/SQL DIANA " 0
"gcs resources " 5824744
"KCL extra lock elements " 691200
"sim memory hea " 515944
"trigger inform " 648
"parameters " 0
"session param values " 1577760
"ges resources " 85415480
"partitioning d " 0
"gcs shadows " 2517168
"ges regular msg buffers " 893048
"dictionary cache " 33792
"KQR S SO " 8192
"partitioning i " 0
"KQR M PO " 210328
"trigger source " 0
"library cache " 3063304
"processes " 1056000
"sql area " 795296
"sessions " 597584
"MTTR advisory " 179472
"event statistics per sess" 2518368
"fixed allocation callback" 424
"KGK heap " 6448
"table definiti " 0
"db_block_hash_buckets " 352256
"ges resource hash table " 2490368
===============================
Memory Utilization of Subpool 3
===============================
Allocation Name Size
_________________________ __________
"free memory " 28924264
"miscellaneous " 15446808
"KQR M PO " 135704
"gcs resources " 5824744
"parameters " 0
"KGLS heap " 16456
"ges big msg buffers " 3835688
"Checkpoint queue " 1283200
"trigger defini " 0
"PLS non-lib hp " 2088
"ges resources " 72820856
"KQR L PO " 131176
"PL/SQL MPCODE " 37392
"joxs heap init " 4240
"enqueue " 1646960
"gcs shadows " 18621616
"MTTR advisory " 149216
"KSXR receive buffers " 1034000
"table definiti " 0
"ges process array " 1057320
"trigger source " 0
"sim memory hea " 520184
"dictionary cache " 1065728
"db_block_hash_buckets " 3924400
"partitioning i " 0
"1M buffer " 1049600
"PL/SQL DIANA " 0
"library cache " 2219312
"partitioning d " 0
"sql area " 128528
"trigger inform " 0
"sessions " 600288
"event statistics per sess" 2507024
"ges enqueues " 4264344
"PL/SQL PPCODE " 0
"errors " 0
"fixed allocation callback" 336
"ktlbk state objects " 521528
===============================
Memory Utilization of Subpool 4
===============================
Allocation Name Size
_________________________ __________
"free memory " 35164632
"miscellaneous " 16038016
"fixed allocation callback" 376
"partitioning i " 0
"table definiti " 224
"KGLS heap " 197648
"KQR L PO " 343440
"gcs resources " 5822416
"PL/SQL MPCODE " 2488
"PX subheap " 41008
"ges reserved msg buffers " 2096008
"gcs resource hash table " 524288
"PL/SQL PPCODE " 0
"transaction " 404520
"gcs shadows " 2519272
"partitioning d " 0
"trigger inform " 0
"1M buffer " 1049600
"message pool freequeue " 324464
"KSXR pending messages que" 853952
"PL/SQL SOURCE " 0
"ges enqueues " 4100120
"dictionary cache " 2103808
"ges resources " 85545768
"enqueue resources " 535104
"trigger defini " 0
"errors " 0
"library cache " 3616560
"PL/SQL DIANA " 44672
"sql area " 691424
"sessions " 597584
"KQR M PO " 28232
"event statistics per sess" 2507024
"parameters " 0
"DML lock " 820368
"sim memory hea " 515944
"Checkpoint queue " 1283200
"trigger source " 0
服务器有16个CPU,因此共享池被分为4个子池。每个子池128M。从上面看,当时的空闲空间超过100M。在分配一个2268字节的对象的时候报错。说明共享池的碎片化十分严重。什么导致共享池的碎片呢?我们注意到一个对象:ges resources,在每个子池中总计超过300M。大多数共享池空间都被GES RESOURCES占用了。而GES RESOURCE是可以动态扩展的PERMENT OBJECT,每个资源占用484个字节。在RAC环境中,由于GES RESOURCE的大量动态扩展,会导致共享池中碎片大规模出现,最终导致系统不可用。在这个案例中,处理这个问题的方法很多,最简单的情况,是内存充足的情况下,直接加大共享池的大小就可以解决问题了。如果要找到GES RESOURCES为何如此巨大的原因,要复杂的多,要配合应用一起来分析。这里就不做讨论了。
一个读取数据块的小程序
这几天由于客户的需求,写了一个修改错误块的小程序,把其中的一些代码贴出来给大家共享一下。由于只是临时使用,只关心了需要的几个字段,其他部分可能会存在错误,如果有错误,恕不更正。
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
typedef unsigned int ub4;
typedef unsigned short ub2;
typedef unsigned char ub1;
#ifndef LINUX
#define OFFSET 0 /* if it's needed specify an offset !=0 */
#else
#define OFFSET 0
#endif
#define FALSE 0
#define TRUE 1
#define NUMORABLOCK(fsize,orabsize) \
((fsize==(orabsize-OFFSET)) ? (1) : ((fsize/(orabsize-OFFSET))-1))
#define FILE_ID(dba) (dba >> 22) /* right shift dba over 22 to get file# */
#define BLOCK_ID(dba) (dba & 0x3fffff)/*mask 22 lower bits of dba to get block#*/
#define CHECKCONDITION(bh) ((bh->type==6) && (bh->flg & 0x4))
#define PRINT_HEADER(bh) fprintf(stdout,\
"file# %d,block# %d \n type: 0x%x fmt: 0x%x rdba: 0x%x base SCN: 0x%x\
\n wrap SCN: 0x%x chk: 0x%x", BLOCK_ID(bh->rdba),\
FILE_ID(bh->rdba),bh->type, bh->Fmt, bh->rdba, bh->bas, bh->wrp, bh->cks)
#define PRINT_COMPUTED_CHECKSUM(bh,cks) fprintf(stdout,\
" [kcbhxor: 0x%x]\n\n",cks)
#define PRINT_FILEINFO(fname,fstat,orablocks) \
fprintf(stdout,"name: %s size: %d n-blocks: %d\n",fname,\
fstat.st_size,orablocks)
typedef struct _bh {
ub1 type; /* type */
ub1 Fmt; /* format */
ub1 r1; /* not used */
ub1 r2; /* not used */
ub4 rdba; /* rdba data block address */
ub4 bas; /* base of SCN */
ub2 wrp; /* wrap of SCN */
ub1 seq; /* sequence of changes at same scn */
ub1 flg; /* flag for a bit mask */
ub2 cks; /* checksum */
ub1 r3; /* spare*/
ub1 r4; /*spare for word */
} block_header;
typedef struct kxid { /* 9207 struct kxid */
ub2 kxidusn; /* undo seg number */
ub2 kxidslt; /* slot number */
ub4 kxidsqn; /* wrap number */
} kxid_st;
typedef struct kuba { /* 9207 struct kuba undo block address */
ub4 kubadba; /* relative dba */
ub2 kubaseq; /* sequence number discussed above */
ub1 kubarec; /* record number index within that block */
} kuba_st;
typedef struct ktbbh
{
ub1 ktbbhtyp;
ub1 sp1;
ub4 object_id;
ub4 kscnbas; /* scn base */
ub2 kscnwrp; /* scn wrap */
ub2 itlno_hi;
ub1 itlno;
ub1 flags; /* 0x01:on freelist 0x10:bitmap */
ub1 fsl; /* free space lock */
ub4 krdba; /* next free block */
}ktbbh_st;
typedef struct ktbit { /* 9207 struct ktbit itl entry */
kxid_st ktbitxid; /* transaction id */
kuba_st ktbituba; /* undo address for last change */
ub2 ktbitflg; /* num of locks in block */
/* BitMask for "struct ktbit.ktbitflg"
KTBFCOM BIT 0x8000 // transaction is committed
KTBFIBI BIT 0x4000 // rollback of this uba gives a BI of the itl
KTBFUPB BIT 0x2000 // commit time is upper bound
KTBFTAC BIT 0x1000 // this xac is active as of ktbbhcsc
KTBFLKC BIT 0x0FFF // lock count mask for flag
*/
ub2 ktbiwrap; /* commit num wrap */
ub4 ktbitbas; /* sys commit num base */
} ktbit_st;
typedef struct kbh{
block_header bh;
ktbbh_st kbh_bbh;
ktbit_st kbh_it;
} kbh_st;
void printhex(unsigned char *buffer,int count)
{
int line=0;
int col=0;
int current=0;
printf(" 00 01 02 03 04 05 06 07 08 09\n");
printf("%04x ",line);
while(current<count)
{
printf("%02x ",buffer[current]);
current++;
col++;
if(col==10)
{
col=0;
line++;
printf("\n");
printf("%04x ",line);
}
}
}
void print_bh(kbh_st *buffer)
{
printf("file# %d,block# %d \n type: 0x%x fmt: 0x%x rdba: 0x%x base SCN: 0x%x \n wrap SCN: 0x%x chk: 0x%x seq=0x%x flg=0x%x\n",
FILE_ID(buffer->bh.rdba),BLOCK_ID(buffer->bh.rdba),buffer->bh.type, buffer->bh.Fmt, buffer->bh.rdba,
buffer->bh.bas, buffer->bh.wrp, buffer->bh.cks,buffer->bh.seq,buffer->bh.flg) ;
printf("Type:0x%x objid:%d scn:0x%x/0x%x itls:%d flags:0x%x fsl:0x%x next:0x%x(%d/%d)\n",
buffer->kbh_bbh.ktbbhtyp,buffer->kbh_bbh.object_id,buffer->kbh_bbh.kscnbas,buffer->kbh_bbh.kscnwrp,buffer->kbh_bbh.itlno&0X00FF,
buffer->kbh_bbh.flags,buffer->kbh_bbh.fsl,buffer->kbh_bbh.krdba,FILE_ID(buffer->kbh_bbh.krdba),BLOCK_ID(buffer->kbh_bbh.krdba));
}
void get_flg(ub2 flag,char *flg)
{
if(flag&0x8000)
flg[0]='C';
else
flg[0]='-';
if(flag&0x4000)
flg[1]='B';
else
flg[1]='-';
if(flag&0x2000)
flg[2]='U';
else
flg[2]='-';
if(flag&0x1000)
flg[3]='T';
else
flg[3]='-';
flg[4]='\0';
}
void print_itl(char * buffer,int count)
{
int i;
ktbit_st *itls;
char flg[5];
itls=(ktbit_st *)(buffer+44);
printf("\n Itl Xid Uba Flag Lck Scn/Fsc\n");
for(i=0;i<count;i++)
{
get_flg(itls[i].ktbitflg,flg);
printf("0x%03x 0x%04x.%03x.%08x 0x%08x.%04x.%02x %s %d %s 0x%04x.%08x\n",i+1,itls[i].ktbitxid.kxidusn,
itls[i].ktbitxid.kxidslt,itls[i].ktbitxid.kxidsqn,itls[i].ktbituba.kubadba,itls[i].ktbituba.kubaseq,itls[i].ktbituba.kubarec,
flg,itls[i].ktbitflg&0x00ff,flg[0]=='C'?"scn":"fsc",itls[i].ktbiwrap,itls[i].ktbitbas);
}
}
int main(argc,argv)
int argc;
char *argv[];
{
int BLOCKSIZE=8192; /* This must be equal to db_block_size */
char *filename; /* datafile name */
int orablocks; /* number of oracle block in datafile */
block_header *block_header; /* block header struct */
int i; /* simple counter */
ub2 cksum; /* old checksum del blocco */
ub2 cksumverify;
char blockbuffer[68000];
int fd;
struct stat fileinfo;
int blockid;
kbh_st *bf;
if(argc<3)
{
printf("usage :blockcheck <filename> <blocksize> <block#>\n");
exit(-1);
}
filename=argv[1];
if(filename==NULL)
{
printf("usage :blockcheck <filename> <blocksize> <block#>\n");
exit(-1);
}
BLOCKSIZE=atoi(argv[2]);
if(BLOCKSIZE<=0)
{
printf("usage :blockcheck <filename> <blocksize> <block#>\n");
exit(-1);
}
blockid=atoi(argv[3]);
if(blockid<=0)
{
printf("usage :blockcheck <filename> <blocksize> <block#>\n");
exit(-1);
}
printf("bc-I-begin to check file[%s]-block[%d],blocksize[%d],OFFSET[%d]\n",filename,blockid,BLOCKSIZE,OFFSET);
if((fd=open(filename,O_RDONLY))<0)
exit(1);
printf("file id=%d\n",fd);
printf("blocksize=%d,OFFSET=%d\n",BLOCKSIZE,OFFSET);
if(fstat(fd,&fileinfo )<0)
exit(1);
printf("blocksize=%d,OFFSET=%d\n",BLOCKSIZE,OFFSET);
orablocks=fileinfo.st_size/(BLOCKSIZE-OFFSET);
printf("blocks=%d\n",orablocks);
#ifndef LINUX
if(lseek(fd,OFFSET,SEEK_SET)<0)
exit(-1);
#endif
printf("bc-I-begin to allocate block_header buffer\n");
block_header=malloc(BLOCKSIZE);
if(lseek(fd,BLOCKSIZE*(blockid),SEEK_SET)<0) exit(1);
if(read(fd,blockbuffer,BLOCKSIZE)<0) exit(1);
printf("bc-I-read block[%d] success...\n",blockid);
block_header=&blockbuffer[0];
print_bh(block_header);
bf=block_header;
if(bf->bh.type==6)
print_itl(block_header,bf->kbh_bbh.itlno);
printhex(block_header,100);
return(0);
}
执行结果(测试的是10G的库):
E:\cygwin\home\jackson xu\blockcheck>blockcheck D:\ORACLE\ORADATA\ORCL\ORCL\USERS01.DBF 8192 40708
bc-I-begin to check file[D:\ORACLE\ORADATA\ORCL\ORCL\USERS01.DBF]-block[40708],blocksize[8192],OFFSET[0]
file id=3
blocksize=8192,OFFSET=0
blocksize=8192,OFFSET=0
blocks=82721
bc-I-begin to allocate block_header buffer
bc-I-read block[40708] success...
file# 4,block# 40708
type: 0x6 fmt: 0xa2 rdba: 0x1009f04 base SCN: 0xfe622
wrap SCN: 0x0 chk: 0x2882 seq=0x5 flg=0x6
Type:0x1 objid:51588 scn:0xfe5ab/0x0 itls:3 flags:0x0 fsl:0x32 next:0x1009f01(4/40705)
Itl Xid Uba Flag Lck Scn/Fsc
0x001 0xffff.000.00000000 0x00000000.0000.00 C--- 0 scn 0x0000.000fe5ab
0x002 0x0005.018.00000189 0x00801e2a.012c.22 --U- 4 fsc 0x0000.000fe622
0x003 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
以下是该块的BLOCK DUMP的数据:
buffer tsn: 4 rdba: 0x01009f04 (4/40708)
scn: 0x0000.000fe622 seq: 0x05 flg: 0x06 tail: 0xe6220605
frmt: 0x02 chkval: 0x2882 type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x09032200 to 0x09034200
9032200 0000A206 01009F04 000FE622 06050000 [........".......]
9032210 00002882 00000001 0000C984 000FE5AB [.(..............]
9032220 00000000 00320003 01009F01 0000FFFF [......2.........]
9032230 00000000 00000000 00000000 00008000 [................]
9032240 000FE5AB 00180005 00000189 00801E2A [............*...]
9032250 0022012C 00002004 000FE622 00000000 [,.".. ..".......]
9032260 00000000 00000000 00000000 00000000 [................]
9032270 00000000 00000000 00000000 00040100 [................]
9032280 001AFFFF 1F321F28 00001F32 1F4F0004 [....(.2.2.....O.]
9032290 1F351F42 00001F28 00000000 00000000 [B.5.(...........]
90322A0 00000000 00000000 00000000 00000000 [................]
Repeat 495 times
90341A0 00000000 0202022C 720604C1 656C6966 [....,......rfile]
90341B0 02022C33 0605C102 6C696672 022C3465 [3,......rfile4,.]
90341C0 03C10202 69667206 2C32656C C1020202 [.....rfile2,....]
90341D0 66720602 31656C69 2C000000 C1020100 [..rfile1...,....]
90341E0 00000004 0201002C 000005C1 01002C00 [....,........,..]
90341F0 0003C102 002C0000 02C10201 E6220605 [......,.......".]
Block header dump: 0x01009f04
Object id on Block? Y
seg/obj: 0xc984 csc: 0x00.fe5ab itc: 3 flg: E typ: 1 - DATA
brn: 0 bdba: 0x1009f01 ver: 0x01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0xffff.000.00000000 0x00000000.0000.00 C--- 0 scn 0x0000.000fe5ab
0x02 0x0005.018.00000189 0x00801e2a.012c.22 --U- 4 fsc 0x0000.000fe622
0x03 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
DBA的理论基础
最近总有人问我,做DBA,深入理解Oracle的原理有没有用,比如很多人喜欢DUMP Oracle内部的对象,这对于DBA提高能力有没有帮助。
我的观点是:
1、在学习初期,建议不要过于深入了解理论,因为那个时候主要是铺面,Oracle技术十分庞杂,就是花上1、2年时间也只能了解其中的一些侧面。如果要十分全面的了解Oracle的功能,就没有时间去做十分深入的理论研究。另外初学阶段,Oracle的一些基本概念没有很完整的形成,这个时候,你可能把某个Oracle内部原理搞清楚,但是这对于你把Oracle的知识串起来帮助不大。因为你的理解能力还不能达到一定的水平。初学者总是很羡慕别人能够做十分复杂的研究和实验,总想自己亲自去尝试一下。我的建议是,在这个阶段,深入分析某个Oracle的内部原理,还不如认认真真的读几遍Oracle concepts
2、当你已经达到一定层次后,理论学习和研究对你的DBA工作是十分有帮助的。特别是积累了一定的维护经验后,再来理解哪些原理性的东西,会有更大的收获。如果有DBA问我,为什么某个数据库的临时表空间启动后,没什么操作,也是100%,空间怎么不能释放呢?那我会给他一堆关于临时表空间和临时段的资料,让他先看明白再来问这个问题。对于一个处于初级阶段的DBA来说,问这个问题,是有情可原的,但是这句话如果出自于一个有经验的DBA之口的话,那么我会建议他尽快再去研究一下CONCEPTS,在这个阶段,理论知识对于维护实践的帮助十分的大。这个时期,应该多关注一些Oracle内部原理性的东西,这些理论有助于形成正确的思路。比如上面的例子,如果你了解了临时表空间的工作原理,SORT EXTENT POOL的机制,就不会问出这样的问题了。由于这个阶段,知识面已经比较宽了,实践经验也具备了,可以对某些基本的机制进行原理性的分析,比如共享池、DB CACE/DBWR、REDOLOG、UNDO、CHECKPOINT、CONTROL FILE、TEMP SEGMENT等等。但是这个阶段还不宜过于深入,因为要学习和研究的东西太多,过于深入需要太多的时间。
3、当你已经突破了某个层次的时候,你会发现,你又遇到了一个瓶颈,经验在不断的丰富,但是总的技术水平提高却很缓慢。这个时候你就需要更深入的分析原理了。因为在上个阶段你只是初步的了解了一些原理性的东西,很多更为细致的内容你还没有了解。不把这些东西了解清楚,可能会影响你的水平的提升。这个时候,你就需要把一些关键的技术深入的分析,并把各个独立的部件关联起来。这个时候,原理性的东西可以作为你的工作指导了。你在做某个事情的时候,根据Oracle的原理,就会识别这个事情的好处、风险。举个例子前几天有个朋友问我为什么他们的应用里一个SELECT .. FOR UPDATE产生了大量的REDO,导致归档目录撑满了。他觉得SELECT FOR UPDATE操作并没有修改数据,怎么会产生这么大量的REDO呢。实际上如果理解REDO的原理这个问题就不难回答了。从REDO OPCODE上可以看到:
Layer 11 : Row Access - KCOCODRW [kdocts.h]
Opcode 1 : Interpret Undo Record (Undo)
Opcode 2 : Insert Row Piece
Opcode 3 : Drop Row Piece
Opcode 4 : Lock Row Piece
Opcode 5 : Update Row Piece
Opcode 6 : Overwrite Row Piece
Opcode 7 : Manipulate First Column (add or delete the 1rst column)
Opcode 8 : Change Forwarding address
Opcode 9 : Change the Cluster Key Index
Opcode 10 :Set Key Links (change the forward & backward key links
on a cluster key)
Opcode 11 :Quick Multi-Insert (ex: insert as select ...)
Opcode 12 :Quick Multi-Delete
Opcode 13 :Toggle Block Header flags
在ROW ACCESS里,就有LOCK ROW PIECE这种OPCODE,当LOCK了某个ROW PIECE的时候,就需要修改相关的锁标志位,这也会对数据块进行修改。
对于一个初、中级的DBA来说,遵循某些规则性的东西,是十分关键的,比如那个时候,资深的DBA会和你说,要用绑定变量、索引不能随便乱建,等等。但是,如果你的理论知识达到一定水平的时候,你就可以挥洒自如了,你可以不拘泥于某种约束,而是从Oracle的原理的层面来看某个问题,因为你已经深入的了解了Oracle的主要原理,你的所有处理都是符合Oracle的原理的,而且你也十分清楚每个操作的风险,这个时候,你就是一个高手了。
简单说说数据块结构(3)
于回家换了台电脑,因此数据块换了一个,继续介绍下面的数据结构。
其逻辑DUMP:
tsiz: 0x1f98
hsiz: 0x14
pbl: 0x0cebec64
bdba: 0x0100028e
76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0x1f8e
avsp=0x1f7a
tosp=0x1f7a
0xe:pti[0] nrow=1 offs=0
0x12:pri[0] offs=0x1f8e
block_row_dump:
tab 0, row 0, @0x1f8e
tl: 10 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 3] 31 31 31
col 1: [ 2] c1 03
end_of_block_dump
这个块有2个ITL槽,今后计算所有的位置都要根据这个来计算。
下面一个重要的结构就是KDBH
struct kdbh {
ub1 kdbhflag; /* FLAGs */
ktno kdbhntab; /* Number of TABles in the table index */
ub2 kdbhnrow; /* Number of ROWs in the row index */
sb2 kdbhfrre; /* first FRee Row index Entry */
sb2 kdbhfsbo; /* Free Space Beginning Offset */
sb2 kdbhfseo; /* Free Space Ending Offset */
b2 kdbhavsp; /* AVailable SPace in the block */
b2 kdbhtosp; /* TOtal Space that will be available */
}
KDBH的位置的计算方法如下:
对于ASSM:76+(itls-1)*24
对于MSSM:68+(itls-1)*24
本例是使用ASSM的,并且有2个ITL槽,因此是76+24=100
我们来看这部分数据:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00 00 00 00 00 01 01 00 FF FF 14 00 8E 1F 7A 1F
7a 1f 00 00 01 00 8e 1f
100:FLAG 0(--------------)
101:NTAB 1
102-103:NROW 01 00: (nrow=1)
104-105:frre ff ff (-1)
106-107:fsbo 14 00:0x14
108-109:fseo 8e 1f:0x1f8e
110-111:avsp 7a 1f: 0x1f7a
112-113:tosp 7a 1f: 0x1f7a
下面是KDBT结构:
struct kdbt {
b2 kdbtoffs; /* OFFSet in the block from kdbpri */
b2 kdbtnrow; /* Number of Rows in the table */
}
114-115: 00 00:0x0000
116-117: 01 00 :0x0001 (这个块有1行数据)
下面紧接着是KDBR结构,KDBR结构是一个数组,是sb2类型的,指向每一行的头,这里只有1行,指向0x 1f8e,
对于ASSM加上76就是这个记录的位置:0x1f8e+76+24=8178(0x1FF2)
找出这些数据:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
04 00 2c 01 02 03 31 31 31 02 c1 03 01 06 63 77
2c是行的开头,属于kdrh结构
ub1 kdrhflag; /* the flag byte for the piece being inserte
ub1 kdrhlock; /* locking itl index */
ub1 kdrhccnt; /* the column count for the row piece */
2c是记录头的flag
01:ITL曹的索引(锁所在的)
02:这个记录有2个字段
后面是第一个字段的数据
03 31 31 31
03表示字段长度,后面3个31就是字符串'111'
02 c1 03
第二个字段是Number类型,长度是2(02),C1 03是数值2的内部表示
最后四个字节是
01:SEQ
06: TYPE
最后两个字节是 scn base的低4个字节:0x7763 ,这个块的SCN是:0x005f7763
注意的是:这个例子是最简单的,如果有字段的长度超过253字节,那么8位是表示不了的,这个时候,会使用前导字符FE
比如FE 03 06表示该字段的长度是0x603,就是1539字节
要注意的是在数据块里面是没有字段类型的,因此如果SYSTEM表空间损坏,需要导出数据,就必须了解表的结构,否则需要根据扫描的结果进行猜测
简单说说数据块结构(2)
从44开始是ITL表,每个ITL记录的长度为24,从1可以看到这个块有3个ITL槽,因此ITL占72字节
我们开始分析:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00 00 00 00 03 00 32 00 11 A7 00 01 FF FF 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00
6D 48 25 00 00 00 00 00 00 00 00 00 00 00 00 00
struct ktbit {
kxid ktbitxid; /* transaction id */
kuba ktbituba; /* undo address for last change */
b2 ktbitflg; /* num of locks in block */
ktbitun_t _ktbitun;
ub4 ktbitbas; /* sys commit num base */
}
KXID: UB2 :UNDO SEGMENT NUMBER
UB2 :SLOT NUMBER
UB4 :WRAP
44-51 XID(8):FF FF 00 00 00 00 00 00 :0xffff.0000.00000000
52-59UBA(8):00 00 00 00 00 00 00 00 :0x00000000.0000.00
60-61(2): FLAG:00 80,0X0800, c--- LOCK 0
62-67(6):scn:00 00 6D 48 25 00 ,0x00254864.00
简单说说数据块结构(1)
这里介绍一下Oracle type: 0x06=trans data的数据块的结构(本文涉及的数据库版本为10.2.0.1)
以下是一个块的逻辑结构:
buffer tsn: 4 rdba: 0x0100a714 (4/42772)
scn: 0x0000.0025486e seq: 0x02 flg: 0x04 tail: 0x486e0602
frmt: 0x02 chkval: 0xddf1 type: 0x06=trans data
Block header dump: 0x0100a714
Object id on Block? Y
seg/obj: 0xcc5c csc: 0x00.25486d itc: 3 flg: E typ: 1 - DATA
brn: 0 bdba: 0x100a711 ver: 0x01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0xffff.000.00000000 0x00000000.0000.00 C--- 0 scn 0x0000.0025486d
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
0x03 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
data_block_dump,data header at 0x8eb227c
===============
tsiz: 0x1f80
hsiz: 0x16
pbl: 0x08eb227c
bdba: 0x0100a714
76543210
flag=--------
ntab=1 ----有1个表,如果是CLUSTER,可能大于1
nrow=2 -----有2行
frre=-1
fsbo=0x16 ----空闲空间的开始(44+NO_OF_ITLS*24+0X16) NO_OF_ITLS:itl插槽的数量
fseo=0x1e70 ----空闲空间尾部 (44+NO_OF_ITLS*24 +0x1e70)
avsp=0x1e5a
tosp=0x1e5a
0xe:pti[0] nrow=2 offs=0
0x12:pri[0] offs=0x1f79 ----第一行的地址0x1f79+(44+NO_OF_ITLS*24)
0x14:pri[1] offs=0x1e70 ----第二行的地址0x1e70+(44+NO_OF_ITLS*24)
block_row_dump:
tab 0, row 0, @0x1f79 ---第一行
tl: 7 fb: --H-FL-- lb: 0x0 cc: 2
col 0: *NULL*
col 1: [ 2] c1 02 ---数值1
tab 0, row 1, @0x1e70 ---第二行
tl: 263 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [254]
31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35
36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30
31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35
36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30
31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35
36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30
31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35
36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30
31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35
36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30
31 32 33 34
col 1: [ 2] c1 03 --数值2
end_of_block_dump
下面我们通过裸文件来分析:

首先我们看前面的20个字节,这20个字节是
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
06 A2 00 00 14 A7 00 01 6E 48 25 00 00 00 02 04
F1 DD 00 00
对应的数据结构为kcbh:
typedef struct kcbh_ {
ub1 type_kcbh;
ub1 frmt_kcbh;
ub1 spare1_kcbh;
ub1 spare2_kcbh;
krdba rdba_kcbh;
ub4 bas_kcbh; /* base of SCN */
ub2 wrp_kcbh; /* wrap of SCN */
ub1 seq_kcbh; /* seq# of changes at same scn, KCBH_NLCSEQ */
ub1 flg_kcbh; /* see KCBHFNEW etc below */
ub2 chkval_kcbh;
ub2 spare3_kcbh;
} kcbh;
第0个字节为type:06表示是数据块
第1个字节是FRMT:一般是0X02 ,这里是0xa2,用掩码0x0f取出就是0x02
第4-7个字节开始:14 A7 00 01 是RDBA 0X100A714(4/42772),就是这个块
8-13是SCN(前面四个是BASE,后面是WRAP):6E 48 25 00 00 00 :0x254864.00
14是SEQ:02 : SEQ=0x02
15:FLAG: 04: FLAG=0x04
16-17:CHECKSUM:F1 DD :0xddf1
正好和逻辑DUMP的数据完全吻合
buffer tsn: 4 rdba: 0x0100a714 (4/42772)
scn: 0x0000.0025486e seq: 0x02 flg: 0x04 tail: 0x486e0602
frmt: 0x02 chkval: 0xddf1 type: 0x06=trans data
从20字节开始是24字节长度的ktbbh
typedef struct ktbbh_ { /* 10201 struct ktbbh block header */
ub1 ktbbhtyp; /* block type */
ub4 ktbbhsid;
kscn ktbbhcsc; /* effective time of last cleanout */
b2 ktbbhict; /* number of itl entries mask 0x00ff*/
ub1 ktbbhflg; /* flags */
ub1 ktbbhfsl; /* free space lock */
krdba ktbbhfnx; /* next block in free list */
} ktbbh;
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
F1 DD 00 00 01 00 00 00 5C CC 00 00 6D 48 25 00
00 00 00 00 03 00 32 00 11 A7 00 01 FF FF 00 00
20字节:01 :typ=01
24-27:OBJECTID 5C CC 00 00 :0xcc5c(注意,这里有UB4的字节对齐问题,所以中间空了3个字节)
28-35紧接着的6个字节是6D 48 25 00 00 00,SCN: 0x0025486d.0000
36-37:ITL插槽的数量:用0x00ff掩码:03 00 :有3个ITL槽
38:FLAG 32
39:FSL:00
40-43 KDBA,下一个FREE块的地址:11 A7 00 01 ,0x100a711
kcvfh结构和BOOTSTRAP$
最近我从粉丝网搬过来一些以前的博客,大家如果看过就不用再浪费时间了
KCVFH是文件头结构。每个数据库的SYSTEM表空间中都存在一个SUPER BLOCK,这个BLOCK位于文件1的1号块。
我们首先以10G为蓝本来看一下KCVFH的结构:
struct kcvfh {
kcbh kcvfhbfh; /* 标准块头,每个块都有的结构,20个字节 */
kccfhg kcvfhhdr;
krdba kcvfhrdb;/* 指向bootstrap$的RDBA地址,这个是我们今天要关注的重点,这个值只有在FILE# 1才存在 */
kscn kcvfhcrs; /* 文件创建的SCN */
ub4 kcvfhcrt; /* 文件创建的时间戳 */
ub4 kcvfhrlc;
kscn kcvfhrls;
ub4 kcvfhbti;
kscn kcvfhbsc;
ub2 kcvfhbth;
ub2 kcvfhsta;
ub4 kcvfhcpc;
ub4 kcvfhrts;
ub4 kcvfhccc;
kcvcpg kcvfhbcp;
ub4 kcvfhbhz;
kcvmxcd kcvfhxcd;
ktsn kcvfhtsn;
ub2 kcvfhtln;
ktsn_name_t kcvfhtnm;
。。。。
(略)
}
我们用BBED来协助分析:
BBED> set file 1
FILE# 1
BBED> set block 1
BLOCK# 1
BBED> map /v
File: /opt/oracle/oradata/orcl/system01.dbf (1)
Block: 1 Dba:0x00400001
------------------------------------------------------------
Data File Header
struct kcvfh, 676 bytes @0
struct kcvfhbfh, 20 bytes @0
struct kcvfhhdr, 76 bytes @20
ub4 kcvfhrdb @96
struct kcvfhcrs, 8 bytes @100
ub4 kcvfhcrt @108
ub4 kcvfhrlc @112
struct kcvfhrls, 8 bytes @116
ub4 kcvfhbti @124
struct kcvfhbsc, 8 bytes @128
ub2 kcvfhbth @136
ub2 kcvfhsta @138
struct kcvfhckp, 36 bytes @484
ub4 kcvfhcpc @140
ub4 kcvfhrts @144
ub4 kcvfhccc @148
struct kcvfhbcp, 36 bytes @152
ub4 kcvfhbhz @312
struct kcvfhxcd, 16 bytes @316
word kcvfhtsn @332
ub2 kcvfhtln @336
text kcvfhtnm[30] @338
ub4 kcvfhrfn @368
struct kcvfhrfs, 8 bytes @372
ub4 kcvfhrft @380
struct kcvfhafs, 8 bytes @384
ub4 kcvfhbbc @392
ub4 kcvfhncb @396
ub4 kcvfhmcb @400
ub4 kcvfhlcb @404
ub4 kcvfhbcs @408
ub2 kcvfhofb @412
ub2 kcvfhnfb @414
ub4 kcvfhprc @416
struct kcvfhprs, 8 bytes @420
struct kcvfhprfs, 8 bytes @428
ub4 kcvfhtrt @444
ub4 tailchk @8188
BBED> print kcvfhrdb
ub4 kcvfhrdb @96 0x00400179
0X00400179对应的是:(1/377)
我们来看看1/377的block dump:
Start dump data blocks tsn: 0 file#: 1 minblk 377 maxblk 385
buffer tsn: 0 rdba: 0x00400179 (1/377)
scn: 0x0000.0000014e seq: 0x01 flg: 0x04 tail: 0x014e1001
frmt: 0x02 chkval: 0xe733 type: 0x10=DATA SEGMENT HEADER - UNLIMITED
Hex dump of block: st=0, typ_found=1
Extent Control Header
-----------------------------------------------------------------
Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 7
last map 0x00000000 #maps: 0 offset: 4128
Highwater:: 0x0040017d ext#: 0 blk#: 3 ext size: 7
#blocks in seg. hdr's freelists: 1
#blocks below: 3
mapblk 0x00000000 offset: 0
Unlocked
Map Header:: next 0x00000000 #extents: 1 obj#: 56 flag: 0x40000000
Extent Map
-----------------------------------------------------------------
0x0040017a length: 7
nfl = 1, nfb = 1 typ = 1 nxf = 0 ccnt = 3
SEG LST:: flg: USED lhd: 0x0040017c ltl: 0x0040017c
我们来看看OBJID=56的是什么对象:
SQL> select name from sys.obj$ where obj#=56;
NAME
------------------------------
BOOTSTRAP$
对应的表是BOOTSTRAP$,而BOOTSTRAP$是个什么对象呢?我们来看看
SQL> desc sys.bootstrap$
名称 是否为空? 类型
----------------------------------------- -------- ----------------------------
LINE# NOT NULL NUMBER
OBJ# NOT NULL NUMBER
SQL_TEXT NOT NULL VARCHAR2(4000)
SQL> select * from sys.bootstrap$;
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
-1 -1
8.0.0.0.0
0 0
CREATE ROLLBACK SEGMENT SYSTEM STORAGE ( INITIAL 112K NEXT 1024K MINEXTENTS 1 M
AXEXTENTS 32765 OBJNO 0 EXTENTS (FILE 1 BLOCK 9))
20 20
CREATE TABLE ICOL$("OBJ#" NUMBER NOT NULL,"BO#" NUMBER NOT NULL,"COL#" NUMBER NO
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
T NULL,"POS#" NUMBER NOT NULL,"SEGCOL#" NUMBER NOT NULL,"SEGCOLLENGTH" NUMBER NO
T NULL,"OFFSET" NUMBER NOT NULL,"INTCOL#" NUMBER NOT NULL,"SPARE1" NUMBER,"SPARE
2" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE
6" DATE) STORAGE ( OBJNO 20 TABNO 4) CLUSTER C_OBJ#(BO#)
40 40
CREATE INDEX I_ICOL1 ON ICOL$(OBJ#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE (
INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO
40 EXTENTS (FILE 1 BLOCK 249))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
28 28
CREATE TABLE CON$("OWNER#" NUMBER NOT NULL,"NAME" VARCHAR2(30) NOT NULL,"CON#" N
UMBER NOT NULL,"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2
(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) PCTFREE 10 PCTUSED 40 INITRANS 1 M
AXTRANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 OBJNO 28 EXTENTS (FILE 1 BLOCK 169))
48 48
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
CREATE UNIQUE INDEX I_CON1 ON CON$(OWNER#,NAME) PCTFREE 10 INITRANS 2 MAXTRANS 2
55 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCRE
ASE 0 OBJNO 48 EXTENTS (FILE 1 BLOCK 313))
49 49
CREATE UNIQUE INDEX I_CON2 ON CON$(CON#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STOR
AGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 O
BJNO 49 EXTENTS (FILE 1 BLOCK 321))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
15 15
CREATE TABLE UNDO$("US#" NUMBER NOT NULL,"NAME" VARCHAR2(30) NOT NULL,"USER#" NU
MBER NOT NULL,"FILE#" NUMBER NOT NULL,"BLOCK#" NUMBER NOT NULL,"SCNBAS" NUMBER,"
SCNWRP" NUMBER,"XACTSQN" NUMBER,"UNDOSQN" NUMBER,"INST#" NUMBER,"STATUS$" NUMBER
NOT NULL,"TS#" NUMBER,"UGRP#" NUMBER,"KEEP" NUMBER,"OPTIMAL" NUMBER,"FLAGS" NUM
BER,"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPA
RE5" VARCHAR2(1000),"SPARE6" DATE) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREAS
E 0 OBJNO 15 EXTENTS (FILE 1 BLOCK 105))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
34 34
CREATE UNIQUE INDEX I_UNDO1 ON UNDO$(US#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STO
RAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0
OBJNO 34 EXTENTS (FILE 1 BLOCK 201))
35 35
CREATE INDEX I_UNDO2 ON UNDO$(NAME) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE (
INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
35 EXTENTS (FILE 1 BLOCK 209))
29 29
CREATE CLUSTER C_COBJ#("OBJ#" NUMBER) PCTFREE 0 PCTUSED 50 INITRANS 2 MAXTRANS 2
55 STORAGE ( INITIAL 56K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCRE
ASE 0 OBJNO 29 EXTENTS (FILE 1 BLOCK 177)) SIZE 300
30 30
CREATE INDEX I_COBJ# ON CLUSTER C_COBJ# PCTFREE 10 INITRANS 2 MAXTRANS 255 STORA
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
GE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OB
JNO 30 EXTENTS (FILE 1 BLOCK 185))
25 25
CREATE TABLE PROXY_ROLE_DATA$("CLIENT#" NUMBER NOT NULL,"PROXY#" NUMBER NOT NULL
,"ROLE#" NUMBER NOT NULL) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 STORAGE
( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO
25 EXTENTS (FILE 1 BLOCK 145))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
26 26
CREATE INDEX I_PROXY_ROLE_DATA$_1 ON PROXY_ROLE_DATA$(CLIENT#,PROXY#) PCTFREE 10
INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTEN
TS 2147483645 PCTINCREASE 0 OBJNO 26 EXTENTS (FILE 1 BLOCK 153))
27 27
CREATE UNIQUE INDEX I_PROXY_ROLE_DATA$_2 ON PROXY_ROLE_DATA$(CLIENT#,PROXY#,ROLE
#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTEN
TS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 27 EXTENTS (FILE 1 BLOCK 161))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
17 17
CREATE TABLE FILE$("FILE#" NUMBER NOT NULL,"STATUS$" NUMBER NOT NULL,"BLOCKS" NU
MBER NOT NULL,"TS#" NUMBER,"RELFILE#" NUMBER,"MAXEXTEND" NUMBER,"INC" NUMBER,"CR
SCNWRP" NUMBER,"CRSCNBAS" NUMBER,"OWNERINSTANCE" VARCHAR2(30),"SPARE1" NUMBER,"S
PARE2" NUMBER,"SPARE3" VARCHAR2(1000),"SPARE4" DATE) PCTFREE 10 PCTUSED 40 INITR
ANS 1 MAXTRANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 214
7483645 PCTINCREASE 0 OBJNO 17 EXTENTS (FILE 1 BLOCK 113))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
41 41
CREATE UNIQUE INDEX I_FILE1 ON FILE$(FILE#) PCTFREE 10 INITRANS 2 MAXTRANS 255 S
TORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE
0 OBJNO 41 EXTENTS (FILE 1 BLOCK 257))
42 42
CREATE UNIQUE INDEX I_FILE2 ON FILE$(TS#,RELFILE#) PCTFREE 10 INITRANS 2 MAXTRAN
S 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTIN
CREASE 0 OBJNO 42 EXTENTS (FILE 1 BLOCK 265))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
13 13
CREATE TABLE UET$("SEGFILE#" NUMBER NOT NULL,"SEGBLOCK#" NUMBER NOT NULL,"EXT#"
NUMBER NOT NULL,"TS#" NUMBER NOT NULL,"FILE#" NUMBER NOT NULL,"BLOCK#" NUMBER NO
T NULL,"LENGTH" NUMBER NOT NULL) STORAGE ( OBJNO 13 TABNO 1) CLUSTER C_FILE#_BL
OCK#(TS#,SEGFILE#,SEGBLOCK#)
19 19
CREATE TABLE IND$("OBJ#" NUMBER NOT NULL,"DATAOBJ#" NUMBER,"TS#" NUMBER NOT NULL
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
,"FILE#" NUMBER NOT NULL,"BLOCK#" NUMBER NOT NULL,"BO#" NUMBER NOT NULL,"INDMETH
OD#" NUMBER NOT NULL,"COLS" NUMBER NOT NULL,"PCTFREE$" NUMBER NOT NULL,"INITRANS
" NUMBER NOT NULL,"MAXTRANS" NUMBER NOT NULL,"PCTTHRES$" NUMBER,"TYPE#" NUMBER N
OT NULL,"FLAGS" NUMBER NOT NULL,"PROPERTY" NUMBER NOT NULL,"BLEVEL" NUMBER,"LEAF
CNT" NUMBER,"DISTKEY" NUMBER,"LBLKKEY" NUMBER,"DBLKKEY" NUMBER,"CLUFAC" NUMBER,"
ANALYZETIME" DATE,"SAMPLESIZE" NUMBER,"ROWCNT" NUMBER,"INTCOLS" NUMBER NOT NULL,
"DEGREE" NUMBER,"INSTANCES" NUMBER,"TRUNCCNT" NUMBER,"SPARE1" NUMBER,"SPARE2" NU
MBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DA
TE) STORAGE ( OBJNO 19 TABNO 3) CLUSTER C_OBJ#(BO#)
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
39 39
CREATE UNIQUE INDEX I_IND1 ON IND$(OBJ#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STOR
AGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 O
BJNO 39 EXTENTS (FILE 1 BLOCK 241))
14 14
CREATE TABLE SEG$("FILE#" NUMBER NOT NULL,"BLOCK#" NUMBER NOT NULL,"TYPE#" NUMBE
R NOT NULL,"TS#" NUMBER NOT NULL,"BLOCKS" NUMBER NOT NULL,"EXTENTS" NUMBER NOT N
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
ULL,"INIEXTS" NUMBER NOT NULL,"MINEXTS" NUMBER NOT NULL,"MAXEXTS" NUMBER NOT NUL
L,"EXTSIZE" NUMBER NOT NULL,"EXTPCT" NUMBER NOT NULL,"USER#" NUMBER NOT NULL,"LI
STS" NUMBER,"GROUPS" NUMBER,"BITMAPRANGES" NUMBER NOT NULL,"CACHEHINT" NUMBER NO
T NULL,"SCANHINT" NUMBER NOT NULL,"HWMINCR" NUMBER NOT NULL,"SPARE1" NUMBER,"SPA
RE2" NUMBER) STORAGE ( OBJNO 14 TABNO 2) CLUSTER C_FILE#_BLOCK#(TS#,FILE#,BLOCK
#)
6 6
CREATE CLUSTER C_TS#("TS#" NUMBER) PCTFREE 10 PCTUSED 40 INITRANS 2 MAXTRANS 255
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREAS
E 0 OBJNO 6 EXTENTS (FILE 1 BLOCK 57))
7 7
CREATE INDEX I_TS# ON CLUSTER C_TS# PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE (
INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO
7 EXTENTS (FILE 1 BLOCK 65))
21 21
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
CREATE TABLE COL$("OBJ#" NUMBER NOT NULL,"COL#" NUMBER NOT NULL,"SEGCOL#" NUMBER
NOT NULL,"SEGCOLLENGTH" NUMBER NOT NULL,"OFFSET" NUMBER NOT NULL,"NAME" VARCHAR
2(30) NOT NULL,"TYPE#" NUMBER NOT NULL,"LENGTH" NUMBER NOT NULL,"FIXEDSTORAGE" N
UMBER NOT NULL,"PRECISION#" NUMBER,"SCALE" NUMBER,"NULL$" NUMBER NOT NULL,"DEFLE
NGTH" NUMBER,"DEFAULT$" LONG,"INTCOL#" NUMBER NOT NULL,"PROPERTY" NUMBER NOT NUL
L,"CHARSETID" NUMBER,"CHARSETFORM" NUMBER,"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE
3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) STORAGE
( OBJNO 21 TABNO 5) CLUSTER C_OBJ#(OBJ#)
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
45 45
CREATE UNIQUE INDEX I_COL1 ON COL$(OBJ#,NAME) PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE ( INITIAL 32K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREAS
E 0 OBJNO 45 EXTENTS (FILE 1 BLOCK 289))
46 46
CREATE INDEX I_COL2 ON COL$(OBJ#,COL#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAG
E ( INITIAL 32K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJ
NO 46 EXTENTS (FILE 1 BLOCK 297))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
47 47
CREATE UNIQUE INDEX I_COL3 ON COL$(OBJ#,INTCOL#) PCTFREE 10 INITRANS 2 MAXTRANS
255 STORAGE ( INITIAL 32K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCR
EASE 0 OBJNO 47 EXTENTS (FILE 1 BLOCK 305))
5 5
CREATE TABLE CLU$("OBJ#" NUMBER NOT NULL,"DATAOBJ#" NUMBER,"TS#" NUMBER NOT NULL
,"FILE#" NUMBER NOT NULL,"BLOCK#" NUMBER NOT NULL,"COLS" NUMBER NOT NULL,"PCTFRE
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
E$" NUMBER NOT NULL,"PCTUSED$" NUMBER NOT NULL,"INITRANS" NUMBER NOT NULL,"MAXTR
ANS" NUMBER NOT NULL,"SIZE$" NUMBER,"HASHFUNC" VARCHAR2(30),"HASHKEYS" NUMBER,"F
UNC" NUMBER,"EXTIND" NUMBER,"FLAGS" NUMBER,"DEGREE" NUMBER,"INSTANCES" NUMBER,"A
VGCHN" NUMBER,"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3" NUMBER,"SPARE4" NUMBER,"S
PARE5" VARCHAR2(1000),"SPARE6" VARCHAR2(1000),"SPARE7" DATE) STORAGE ( OBJNO 5
TABNO 2) CLUSTER C_OBJ#(OBJ#)
23 23
CREATE TABLE PROXY_DATA$("CLIENT#" NUMBER NOT NULL,"PROXY#" NUMBER NOT NULL,"CRE
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
DENTIAL_TYPE#" NUMBER NOT NULL,"CREDENTIAL_VERSION#" NUMBER NOT NULL,"CREDENTIAL
_MINOR#" NUMBER NOT NULL,"FLAGS" NUMBER NOT NULL) PCTFREE 10 PCTUSED 40 INITRANS
1 MAXTRANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 214748
3645 PCTINCREASE 0 OBJNO 23 EXTENTS (FILE 1 BLOCK 129))
24 24
CREATE UNIQUE INDEX I_PROXY_DATA$ ON PROXY_DATA$(CLIENT#,PROXY#) PCTFREE 10 INIT
RANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 21
47483645 PCTINCREASE 0 OBJNO 24 EXTENTS (FILE 1 BLOCK 137))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
16 16
CREATE TABLE TS$("TS#" NUMBER NOT NULL,"NAME" VARCHAR2(30) NOT NULL,"OWNER#" NUM
BER NOT NULL,"ONLINE$" NUMBER NOT NULL,"CONTENTS$" NUMBER NOT NULL,"UNDOFILE#" N
UMBER,"UNDOBLOCK#" NUMBER,"BLOCKSIZE" NUMBER NOT NULL,"INC#" NUMBER NOT NULL,"SC
NWRP" NUMBER,"SCNBAS" NUMBER,"DFLMINEXT" NUMBER NOT NULL,"DFLMAXEXT" NUMBER NOT
NULL,"DFLINIT" NUMBER NOT NULL,"DFLINCR" NUMBER NOT NULL,"DFLMINLEN" NUMBER NOT
NULL,"DFLEXTPCT" NUMBER NOT NULL,"DFLOGGING" NUMBER NOT NULL,"AFFSTRENGTH" NUMBE
R NOT NULL,"BITMAPPED" NUMBER NOT NULL,"PLUGGED" NUMBER NOT NULL,"DIRECTALLOWED"
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
NUMBER NOT NULL,"FLAGS" NUMBER NOT NULL,"PITRSCNWRP" NUMBER,"PITRSCNBAS" NUMBER
,"OWNERINSTANCE" VARCHAR2(30),"BACKUPOWNER" VARCHAR2(30),"GROUPNAME" VARCHAR2(30
),"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3" VARCHAR2(1000),"SPARE4" DATE) STORAGE
( OBJNO 16 TABNO 2) CLUSTER C_TS#(TS#)
43 43
CREATE UNIQUE INDEX I_TS1 ON TS$(NAME) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAG
E ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJ
NO 43 EXTENTS (FILE 1 BLOCK 273))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
8 8
CREATE CLUSTER C_FILE#_BLOCK#("TS#" NUMBER,"SEGFILE#" NUMBER,"SEGBLOCK#" NUMBER)
PCTFREE 10 PCTUSED 40 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 24K NEXT 1024K
MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 8 EXTENTS (FILE 1 BLOCK
73)) SIZE 225
9 9
CREATE INDEX I_FILE#_BLOCK# ON CLUSTER C_FILE#_BLOCK# PCTFREE 10 INITRANS 2 MAXT
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
RANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PC
TINCREASE 0 OBJNO 9 EXTENTS (FILE 1 BLOCK 81))
10 10
CREATE CLUSTER C_USER#("USER#" NUMBER) PCTFREE 10 PCTUSED 40 INITRANS 2 MAXTRANS
255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINC
REASE 0 OBJNO 10 EXTENTS (FILE 1 BLOCK 89)) SIZE 372
11 11
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
CREATE INDEX I_USER# ON CLUSTER C_USER# PCTFREE 10 INITRANS 2 MAXTRANS 255 STORA
GE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OB
JNO 11 EXTENTS (FILE 1 BLOCK 97))
56 56
CREATE TABLE BOOTSTRAP$("LINE#" NUMBER NOT NULL,"OBJ#" NUMBER NOT NULL,"SQL_TEXT
" VARCHAR2(4000) NOT NULL) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 STORAGE
( INITIAL 56K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJN
O 56 EXTENTS (FILE 1 BLOCK 377))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
12 12
CREATE TABLE FET$("TS#" NUMBER NOT NULL,"FILE#" NUMBER NOT NULL,"BLOCK#" NUMBER
NOT NULL,"LENGTH" NUMBER NOT NULL) STORAGE ( OBJNO 12 TABNO 1) CLUSTER C_TS#(TS
#)
32 32
CREATE TABLE CCOL$("CON#" NUMBER NOT NULL,"OBJ#" NUMBER NOT NULL,"COL#" NUMBER N
OT NULL,"POS#" NUMBER,"INTCOL#" NUMBER NOT NULL,"SPARE1" NUMBER,"SPARE2" NUMBER,
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) S
TORAGE ( OBJNO 32 TABNO 2) CLUSTER C_COBJ#(OBJ#)
54 54
CREATE INDEX I_CCOL1 ON CCOL$(CON#,COL#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STOR
AGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 O
BJNO 54 EXTENTS (FILE 1 BLOCK 361))
55 55
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
CREATE UNIQUE INDEX I_CCOL2 ON CCOL$(CON#,INTCOL#) PCTFREE 10 INITRANS 2 MAXTRAN
S 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTIN
CREASE 0 OBJNO 55 EXTENTS (FILE 1 BLOCK 369))
22 22
CREATE TABLE USER$("USER#" NUMBER NOT NULL,"NAME" VARCHAR2(30) NOT NULL,"TYPE#"
NUMBER NOT NULL,"PASSWORD" VARCHAR2(30),"DATATS#" NUMBER NOT NULL,"TEMPTS#" NUMB
ER NOT NULL,"CTIME" DATE NOT NULL,"PTIME" DATE,"EXPTIME" DATE,"LTIME" DATE,"RESO
URCE$" NUMBER NOT NULL,"AUDIT$" VARCHAR2(38),"DEFROLE" NUMBER NOT NULL,"DEFGRP#"
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
NUMBER,"DEFGRP_SEQ#" NUMBER,"ASTATUS" NUMBER NOT NULL,"LCOUNT" NUMBER NOT NULL,
"DEFSCHCLASS" VARCHAR2(30),"EXT_USERNAME" VARCHAR2(4000),"SPARE1" NUMBER,"SPARE2
" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6
" DATE) STORAGE ( OBJNO 22 TABNO 1) CLUSTER C_USER#(USER#)
44 44
CREATE UNIQUE INDEX I_USER1 ON USER$(NAME) PCTFREE 10 INITRANS 2 MAXTRANS 255 ST
ORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0
OBJNO 44 EXTENTS (FILE 1 BLOCK 281))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
18 18
CREATE TABLE OBJ$("OBJ#" NUMBER NOT NULL,"DATAOBJ#" NUMBER,"OWNER#" NUMBER NOT N
ULL,"NAME" VARCHAR2(30) NOT NULL,"NAMESPACE" NUMBER NOT NULL,"SUBNAME" VARCHAR2(
30),"TYPE#" NUMBER NOT NULL,"CTIME" DATE NOT NULL,"MTIME" DATE NOT NULL,"STIME"
DATE NOT NULL,"STATUS" NUMBER NOT NULL,"REMOTEOWNER" VARCHAR2(30),"LINKNAME" VAR
CHAR2(128),"FLAGS" NUMBER,"OID$" RAW(16),"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3
" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) PCTFREE
10 PCTUSED 40 INITRANS 1 MAXTRANS 255 STORAGE ( INITIAL 16K NEXT 1024K MINEXTEN
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
TS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 18 EXTENTS (FILE 1 BLOCK 121))
36 36
CREATE UNIQUE INDEX I_OBJ1 ON OBJ$(OBJ#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STOR
AGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 O
BJNO 36 EXTENTS (FILE 1 BLOCK 217))
37 37
CREATE UNIQUE INDEX I_OBJ2 ON OBJ$(OWNER#,NAME,NAMESPACE,REMOTEOWNER,LINKNAME,SU
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
BNAME) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 16K NEXT 1024K MINE
XTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 37 EXTENTS (FILE 1 BLOCK 225)
)
38 38
CREATE INDEX I_OBJ3 ON OBJ$(OID$) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE (
INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 38
EXTENTS (FILE 1 BLOCK 233))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
2 2
CREATE CLUSTER C_OBJ#("OBJ#" NUMBER) PCTFREE 5 PCTUSED 40 INITRANS 2 MAXTRANS 25
5 STORAGE ( INITIAL 136K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCRE
ASE 0 OBJNO 2 EXTENTS (FILE 1 BLOCK 25)) SIZE 800
3 3
CREATE INDEX I_OBJ# ON CLUSTER C_OBJ# PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE
( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJN
O 3 EXTENTS (FILE 1 BLOCK 49))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
4 4
CREATE TABLE TAB$("OBJ#" NUMBER NOT NULL,"DATAOBJ#" NUMBER,"TS#" NUMBER NOT NULL
,"FILE#" NUMBER NOT NULL,"BLOCK#" NUMBER NOT NULL,"BOBJ#" NUMBER,"TAB#" NUMBER,"
COLS" NUMBER NOT NULL,"CLUCOLS" NUMBER,"PCTFREE$" NUMBER NOT NULL,"PCTUSED$" NUM
BER NOT NULL,"INITRANS" NUMBER NOT NULL,"MAXTRANS" NUMBER NOT NULL,"FLAGS" NUMBE
R NOT NULL,"AUDIT$" VARCHAR2(38) NOT NULL,"ROWCNT" NUMBER,"BLKCNT" NUMBER,"EMPCN
T" NUMBER,"AVGSPC" NUMBER,"CHNCNT" NUMBER,"AVGRLN" NUMBER,"AVGSPC_FLB" NUMBER,"F
LBCNT" NUMBER,"ANALYZETIME" DATE,"SAMPLESIZE" NUMBER,"DEGREE" NUMBER,"INSTANCES"
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
NUMBER,"INTCOLS" NUMBER NOT NULL,"KERNELCOLS" NUMBER NOT NULL,"PROPERTY" NUMBER
NOT NULL,"TRIGFLAG" NUMBER,"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3" NUMBER,"SPA
RE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) STORAGE ( OBJNO 4 TA
BNO 1) CLUSTER C_OBJ#(OBJ#)
33 33
CREATE INDEX I_TAB1 ON TAB$(BOBJ#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE (
INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 3
3 EXTENTS (FILE 1 BLOCK 193))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
31 31
CREATE TABLE CDEF$("CON#" NUMBER NOT NULL,"OBJ#" NUMBER NOT NULL,"COLS" NUMBER,"
TYPE#" NUMBER NOT NULL,"ROBJ#" NUMBER,"RCON#" NUMBER,"RRULES" VARCHAR2(3),"MATCH
#" NUMBER,"REFACT" NUMBER,"ENABLED" NUMBER,"CONDLENGTH" NUMBER,"CONDITION" LONG,
"INTCOLS" NUMBER,"MTIME" DATE,"DEFER" NUMBER,"SPARE1" NUMBER,"SPARE2" NUMBER,"SP
ARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) STOR
AGE ( OBJNO 31 TABNO 1) CLUSTER C_COBJ#(OBJ#)
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
50 50
CREATE UNIQUE INDEX I_CDEF1 ON CDEF$(CON#) PCTFREE 10 INITRANS 2 MAXTRANS 255 ST
ORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0
OBJNO 50 EXTENTS (FILE 1 BLOCK 329))
51 51
CREATE INDEX I_CDEF2 ON CDEF$(OBJ#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE (
INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO
51 EXTENTS (FILE 1 BLOCK 337))
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
52 52
CREATE INDEX I_CDEF3 ON CDEF$(ROBJ#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE
( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO
52 EXTENTS (FILE 1 BLOCK 345))
53 53
CREATE INDEX I_CDEF4 ON CDEF$(ENABLED) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAG
E ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJ
LINE# OBJ#
---------- ----------
SQL_TEXT
--------------------------------------------------------------------------------
NO 53 EXTENTS (FILE 1 BLOCK 353))
已选择57行。
BOOTSTRAP$里包含了数据库创建最主要的系统数据字典。我们通过BOOTSTRAP$可以找到OBJ$等数据字典表的OBJNO,以及SEGMENT HDR的地址。
什么是BOOTSTRAP呢?从计算机术语上来看:
Bootstrap is a technique for loading the first few instructions of a computer program into active memory and then using them to bring in the rest of the program.
如果一个软件是很复杂的,那么在软件启动的时候需要把某些结构先载入内存,以便于访问其他的软件结构。包括继续启动软件以及完成软件的后续操作。
那么对于Oracle数据库,bootstrap指的是什么呢?
In Oracle, Bootstrap refers to loading of metadata (data dictionary) before we OPEN the database.
Bootstrap objects are classified as the objects (tables / indexes / clusters) with the object_id below 56 as bootstrap objects.
These objects are mandatory to bring up an instance, as this contains the most important metadata of the database.
因此如果我们要想去分析Oracle数据库的结构,那么我们首先需要通过SUPER BLOCK去找到BOOTSTRAP$的位置,然后通过BOOTSTRAP$中的数据字典定义,找出OBJ$,C_OBJ$,TAB$,COL$等主要数据字典表的存储信息,然后将这些数据找到,从而建立数据字典,并通过数据字典,找到所需要分析的表的信息,从而取出这些数据。
以下是9i的结构:
struct kcvfh { /* 9201 struct kcvfh */
kcbh kcvfhbfh;
kccfh kcvfhhdr;
krdba kcvfhrdb;
kscn kcvfhcrs;
ub4 kcvfhcrt;
ub4 kcvfhrlc;
kscn kcvfhrls;
ub4 kcvfhbti;
kscn kcvfhbsc;
ub2 kcvfhbth;
ub2 kcvfhsta;
kcvcp kcvfhckp;
ub4 kcvfhcpc;
ub4 kcvfhrts;
ub4 kcvfhccc;
kcvcp kcvfhbcp;
ub4 kcvfhbhz;
kcvmxcd kcvfhxcd;
ktsn kcvfhtsn;
ub2 kcvfhtln;
text kcvfhtnm[30];
krfil kcvfhrfn;
kscn kcvfhrfs;
ub4 kcvfhrft;
kscn kcvfhafs;
ub4 kcvfhbbc;
ub4 kcvfhncb;
ub4 kcvfhmcb;
ub4 kcvfhlcb;
ub4 kcvfhbcs;
ub2 kcvfhofb;
ub2 kcvfhnfb;
ub4 kcvfhprc;
kscn kcvfhprs;
kscn kcvfhprfs;
kscn kcvfhtrs;
ub4 kcvfhtrt;
}
8174的KCVFH
struct kcvfh { /* 8174 struct kcvfh */
kcbh kcvfhbfh;
kccfh kcvfhhdr;
krdba kcvfhrdb;
kscn kcvfhcrs;
ub4 kcvfhcrt;
ub4 kcvfhrlc;
kscn kcvfhrls;
ub4 kcvfhbti;
kscn kcvfhbsc;
ub2 kcvfhbth;
ub2 kcvfhsta;
kcvcp kcvfhckp;
ub4 kcvfhcpc;
ub4 kcvfhrts;
ub4 kcvfhccc;
kcvcp kcvfhbcp;
ub4 kcvfhbhz;
kcvmxcd kcvfhxcd;
ktsn kcvfhtsn;
ub2 kcvfhtln;
text kcvfhtnm[30];
krfil kcvfhrfn;
kscn kcvfhrfs;
ub4 kcvfhrft;
kscn kcvfhafs;
ub4 kcvfhbbc;
ub4 kcvfhncb;
ub4 kcvfhmcb;
ub4 kcvfhlcb;
ub4 kcvfhbcs;
ub2 kcvfhofb;
ub2 kcvfhnfb;
ub4 kcvfhprc;
kscn kcvfhprs;
}