前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Oracle数据库的初始化与跟踪学习方法

Oracle数据库的初始化与跟踪学习方法

作者头像
数据和云
发布2018-03-07 11:50:36
1.5K0
发布2018-03-07 11:50:36
举报
文章被收录于专栏:数据和云

编辑说明:《Oracle性能优化与诊断案例精选》出版以来,收到很多读者的来信和评论,我们会通过连载的形式将书中内容公布出来,希望书中内容能够帮助到更多的读者朋友们。

10046 事件是 Oracle 提供的内部跟踪事件,是对 SQL_TRACE 的增强,通过10046可以通知Oracle内核执行SQL_TRACE类的跟踪操作。如果我们需要获得更多的跟踪信息,就需要用到10046事件,而在实际工作中最常用的就是10046事件。

自11g开始,10046获得了更多的增强,包括明确的在设置中指定SQL_trace,类似'SQL_trace wait=false, bind=true'这样的设定。

在DBA的职业生涯中,会面临众多的挑战,其中最重要的一种情况是数据库无法启动,所以深入理解Oracle数据库的初始化非常重要。通过Oracle的跟踪手段,可以帮助我们获取这些知识,在我的学习过程中,一直在不断地通过跟踪去研究熟悉的或不熟悉的特性和功能,从而加深自己对于数据库的理解。

对于Oracle数据库的初始化,我最初的思考是:数据库的核心信息都是存放在数据文件当中的,但是当数据库尚未打开之前,Oracle是无法获得这部分数据的。那么Oracle是怎样完成这个从数据文件到内存的初始化过程的呢?

首先通过以下步骤对数据库的OPEN过程进行跟踪,研究获得的跟踪文件。

SQL> startup mount; SQL> alter session set events='10046 trace name context forever,level 12'; SQL> alter database open;

以上通过10046跟踪获得一个跟踪文件,跟踪文件里将记录从mount到open的过程中,Oracle所执行的后台操作。可以通过tkprof工具对跟踪文件进行格式化,使得其中的信息更便于阅读。

首先我们来参考跟踪文件的前面部分(我的研究首先从Oracle 9i开始,逐渐推演到Oracle 12c,研究不同版本的引导过程方法完全相同),这是第一个对象的创建。

create table bootstrap$ ( line# number not null, obj# number not null, SQL_text varchar2(4000) not null) storage (initial 50K objno 56 extents (file 1 block 520))

注意:在这一步骤中,实际上Oracle是在内存中创建bootstrap$的结构,然后从数据文件中读取数据到内存中,完成第一次初始化。在9i中,读取的位置是文件1的377块,自从11g之后变更为文件1的520块。注意此处的file 1 block 520子句是内部语句,意味这这些对象的存储位置是固定的,该语法对用户创建对象是不可用的。

从数据库的创建脚本 $ORACLE_HOME/rdbms/admin/SQL.bsq 文件中,可以获得bootstrap$表的初始创建语句,直至12c这些定义未曾变化(在12c中SQL.bsq分解为一系列的bsq文件,dcore.bsq中记录了下面这段代码)。

create table bootstrap$ ( line# number not null, /* statement order id */ obj# number not null, /* object number */ SQL_text varchar2("M_VCSZ") not null) /* statement */ storage (initial 50K) /* to avoid space management during IOR I */ // /* "//" required for bootstrap */

接下来从数据库中查询一下,file 1 block 520 上存储的是什么对象。

SQL> select segment_name,file_id,block_id 2 from dba_extents where block_id=520 and file_id=1; SEGMENT_NAME FILE_ID BLOCK_ID --------------- ---------- --------- BOOTSTRAP$ 1 520

File 1 Block 520开始存放的正是Bootstrap$对象。继续查看Trace文件的内容,Oracle进一步执行的是如下操作。

select line#, SQL_text from bootstrap$ where obj# != :1

在创建并从数据文件中装载了bootstrap$的内容之后,Oracle开始递归的从该表中读取信息,加载数据。那么bootstrap$中记录的是什么信息呢?

在数据库中,bootstrap$是一张实际存在的系统表。

SQL> desc bootstrap$ Name Null? Type --------------- -------- -------------------- LINE# NOT NULL NUMBER OBJ# NOT NULL NUMBER SQL_TEXT NOT NULL VARCHAR2(4000)

来看一下这张表的具体内容。

以上输出只显示了表中的4条记录,大家可以自行研究一下其他记录的内容。从这些语句中可以看出,bootstrap$ 中实际上是记录了一些数据库系统基本对象的创建语句。Oracle通过bootstrap$进行引导,进一步创建相关的重要对象,从而启动了数据库。

如果向前追溯,可以继续考察一下bootstrap$的创建过程。查看一下创建数据库的脚本,可以发现数据库在创建过程中最先运行的是一个叫做CreateDB.SQL的脚本。这个脚本发出CREATE DATABASE的命令,具体类似如下的例子。

CREATE DATABASE eygle MAXINSTANCES 1 MAXLOGHISTORY 1 MAXLOGFILES 5 MAXLOGMEMBERS 3 MAXDATAFILES 100 DATAFILE '/opt/oracle/oradata/eygle/system01.dbf' SIZE 250M REUSE AUTOEXTEND ON NEXT 10240K MAXSIZE UNLIMITED EXTENT MANAGEMENT LOCAL DEFAULT TEMPORARY TABLESPACE TEMP TEMPFILE '/opt/oracle/oradata/eygle/temp01.dbf' SIZE 40M REUSE AUTOEXTEND ON NEXT 640K MAXSIZE UNLIMITED UNDO TABLESPACE "UNDOTBS1" DATAFILE '/opt/oracle/oradata/eygle/undotbs01.dbf' SIZE 200M REUSE AUTOEXTEND ON NEXT 5120K MAXSIZE UNLIMITED CHARACTER SET ZHS16GBK NATIONAL CHARACTER SET AL16UTF16 LOGFILE GROUP 1 ('/opt/oracle/oradata/eygle/redo01.log') SIZE 10240K, GROUP 2 ('/opt/oracle/oradata/eygle/redo02.log') SIZE 10240K, GROUP 3 ('/opt/oracle/oradata/eygle/redo03.log') SIZE 10240K; exit;

在这个创建过程中,Oracle会隐含的调用$ORACLE_HOME/rdbms/admin/SQL.bsq脚本,用于创建数据字典。这个文件的位置受到一个隐含的初始化参数 (_init_SQL_file )的控制。

SQL> @GetParDescrb.SQL Enter value for par: init_SQL NAME VALUE DESCRIB --------------- --------------------- -------------------------------------------- _init_SQL_file ?/rdbms/admin/SQL.bsq File containing SQL statements to execute upon database creation

如果在创建过程中,Oracle无法找到SQL.bsq文件,则数据库创建将会出错。我们可以测试一下移除SQL.bsq文件,再看这样一个数据库创建过程。

SQL> startup nomount; SQL> @CreateDB.SQL CREATE DATABASE eygle * ERROR at line 1: ORA-01092: ORACLE instance terminated. Disconnection forced

此时日志中会记录以下信息。

Fri Aug 18 15:45:49 2006 Errors in file /opt/oracle/admin/eygle/udump/eygle_ora_3632.trc: ORA-01501: CREATE DATABASE failed ORA-01526: error in opening file '?/rdbms/admin/SQL.bsq' ORA-07391: sftopn: fopen error, unable to open text file. Error 1526 happened during db open, shutting down database USER: terminating instance due to error 1526

这就是SQL.bsq文件在数据库创建过程中的作用。那么在数据库的引导过程中,又该如何去定位bootstrap$的位置呢?

这就不得不提到了SYSTEM表空间了。在系统表空间文件头存在一个重要的数据结构root dba,我们可以通过转储数据文件头获得这个信息,从生成的trace文件中,我们可以获得以下信息(Oracle 12c环境信息摘录)。

V10 STYLE FILE HEADER: Compatibility Vsn = 202375680=0xc100200 Db ID=2903506423=0xad0ffdf7, Db Name='PRODCDB' Activation ID=0=0x0 Control Seq=60695=0xed17, File size=103680=0x19500 File Number=1, Blksiz=8192, File Type=3 DATA Tablespace #0 - SYSTEM rel_fn:1 Creation at scn: 0x0000.00000007 07/07/2014 05:38:57 Backup taken at scn: 0x0000.00000000 01/01/1988 00:00:00 thread:0 reset logs count:0x35f7cd7a scn: 0x0000.0018531f prev reset logs count:0x32cc9b67 scn: 0x0000.00000001 recovered at 03/02/2016 12:59:30 status:0x2004 root dba:0x00400208 chkpt cnt: 941 ctl cnt:940

root dba仅在SYSTEM表空间的文件头存在,用于定位数据库引导的bootstrap$信息。

Root dba存储的是用16进制表示的二进制数,其中包含10位的文件号以及22位的数据块号,将0x00400208转换为二进制就是0000 0000 0100 0000 0000 0010 0000 1000,前10位为1,代表文件号为1,后22位转换为10进制为520,代表数据文件1上的520号数据块。

当然在数据库中无须如此复杂,Oracle提供工具用于数据块及文件号的转换。

SQL> variable file# number SQL> execute :file#:=dbms_utility.data_block_address_file(to_number('400208','xxxxxxx')); PL/SQL procedure successfully completed. SQL> variable block# number SQL> execute :block#:=dbms_utility.data_block_address_block(to_number('400208','xxxxxxx')) PL/SQL procedure successfully completed. SQL>print file# FILE# ---------- 1 SQL> print block# BLOCK# ---------- 520

现在可以全面的来回顾一下数据库的内部引导过程,通过10046事件可以跟踪一下数据库的打开过程,使用前面曾经提到过的步骤。

oracle@enmocoredb admin]$ SQLplus / as sysdba SQL*Plus: Release 12.2.0.0.3 Production on Thu Aug 4 15:26:49 2016 Copyright (c) 1982, 2016, Oracle. All rights reserved. SQL> shutdown immediate; SQL> startup mount; Database mounted. SQL> alter session set events='10046 trace name context forever,level 12'; SQL> alter database open; SQL> shutdown immediate;

从跟踪文件(以下跟踪文件来自Oracle 12.2版本)中我们可以获得以下重要信息。

===================== PARSING IN CURSOR #0x7fdf6c93ae70 len=19 dep=0 uid=0 oct=35 lid=0 tim=2699657623431 hv=1907384048 ad='0x61ce6470' SQLid='a01hp0psv0rrh' alter database open END OF STMT PARSE #0x7fdf6c93ae70:c=2999,e=2961,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,plh=0,tim=2699657623426 WAIT #0x7fdf6c93ae70: nam='db file sequential read' ela= 12 file#=1 block#=520 blocks=1 obj#=-1 tim=2699658571220 ===================== PARSING IN CURSOR #0x7fdf6c938d48 len=188 dep=1 uid=0 oct=1 lid=0 tim=2699658571988 hv=4006182593 ad='0x61c4bd28' SQLid='32r4f1brckzq1' create table bootstrap$ ( line# number not null, obj# number not null, SQL_text varchar2(4000) not null) storage (initial 50K objno 59 extents (file 1 block 520)) END OF STMT PARSE #0x7fdf6c938d48:c=0,e=658,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,plh=0,tim=2699658571988 WAIT #0x7fdf6c938d48: nam='PGA memory operation' ela= 13 p1=65536 p2=2 p3=0 obj#=-1 tim=2699658572091 EXEC #0x7fdf6c938d48:c=0,e=215,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,plh=0,tim=2699658572285 CLOSE #0x7fdf6c938d48:c=0,e=3,dep=1,type=0,tim=2699658572352 ===================== PARSING IN CURSOR #0x7fdf6c938d48 len=65 dep=1 uid=0 oct=3 lid=0 tim=2699658572771 hv=1762642493 ad='0x61c4a500' SQLid='aps3qh1nhzkjx' select line#, SQL_text from bootstrap$ where obj# not in (:1, :2) END OF STMT PARSE #0x7fdf6c938d48:c=0,e=404,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,plh=0,tim=2699658572770 BINDS #0x7fdf6c938d48: Bind#0 oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00 oacflg=08 fl2=1000001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fdf6c938900 bln=22 avl=02 flg=05 value=59 Bind#1 oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00 oacflg=08 fl2=1000001 frm=00 csi=00 siz=24 off=0 kxsbbbfp=7fdf6c9388d0 bln=24 avl=06 flg=05 value=4294967295 EXEC #0x7fdf6c938d48:c=1000,e=817,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,plh=867914364,tim=2699658573677 WAIT #0x7fdf6c938d48: nam='db file sequential read' ela= 9 file#=1 block#=520 blocks=1 obj#=59 tim=2699658573738 WAIT #0x7fdf6c938d48: nam='PGA memory operation' ela= 9 p1=65536 p2=1 p3=0 obj#=59 tim=2699658573827 WAIT #0x7fdf6c938d48: nam='db file scattered read' ela= 19 file#=1 block#=521 blocks=3 obj#=59 tim=2699658573931

从等待事件上可以明确看到,单块读读取了文件1的第520个数据块,这也正是引导块的定位过程。

WAIT #0x7fdf6c93ae70: nam='db file sequential read' ela= 12 file#=1 block#=520 blocks=1 obj#=-1 tim=2699658571220

了解了SYSTEM表空间的重要作用,也就可以理解,为什么系统表空间的文件头损坏,或者如果启动对象的数据块损坏后,Oracle数据库就将无法启动。

我们曾经见过很多案例,很多用户的数据库运行在非归档模式下,又没有备份,最后当SYSTEM表空间出现故障后,数据库就无法打开了,这是最为严重的情况,通常是没有办法恢复数据的。

所以我们经常反复建议,SYSTEM表空间极其重要,备份重于一切,希望通过我们的不断呼吁,数据库的安全能够更加引起重视,用户的数据能够更加安全。

数据库的引导过程还可以通过GDB工具在Linux、UNIX上进行跟踪,分步骤来观察这个启动过程,以下输出可以帮助读者进一步了解这些内部操作。

首先将数据库启动到Mount状态,找到进程SPID。

SQL> startup mount; ORACLE instance started. Database mounted. SQL> select spid from v$process where addr in (select paddr from v$session where sid=(select distinct sid from v$mystat)); SPID ------------ 1518

然后通过gdb跟踪这个进程。

localhost:~ oracle$ gdb $ORACLE_HOME/bin/oracle 1518 GNU gdb 6.3.50-20050815 (Apple version gdb-1518) (Sat Feb 12 02:52:12 UTC 2011) Attaching to program: `/oracle/product/10.2.0/bin/oracle', process 1518. Reading symbols for shared libraries .+++++++++++ done 0x00007fff80616984 in read () (gdb)

然后跟踪两个内部指令。

(gdb) break kcrf_commit_force Breakpoint 1 at 0x1025a2d4c (gdb) break kqlobjlod Breakpoint 2 at 0x1006c78b4

此时执行数据库OPEN操作会被挂起。

SQL> alter database open;

然后重新开启一个SQL*Plus进程,查询此时数据库加载的ROWCACHE对象。

SQL> select parameter,count,gets from v$rowcache where count!=0; no rows selected

然后继续执行,我们看到在第三个步骤之后,数据库加载了一个ROW Cache对象。

(gdb) c Continuing. Breakpoint 1, 0x00000001025a2d4c in kcrf_commit_force () (gdb) c Continuing. Breakpoint 1, 0x00000001025a2d4c in kcrf_commit_force () (gdb) c Continuing. Breakpoint 2, 0x00000001006c78b4 in kqlobjlod () SQL> select parameter,count,gets from v$rowcache where count!=0; PARAMETER COUNT GETS -------------------------------- ---------- ---------- dc_objects 1 1

这个对象是什么呢?

SQL> select address,cache_name,existent,lock_mode,saddr,substr(key,1,40) keystr from v$rowcache_parent; ADDRESS CACHE_NAME E LOCK_MODE SADDR KEYSTR ---------------- -------------------- - ---------- ---------------- ---------------------------------------- 00000001942E9080 dc_objects N 3 0000000194782EB0 000000000A00424F4F5453545241502400000000

解析其KEY值,正是bootstrap$,这就是数据库初始化时加载的第一个对象。

SQL> select dump('BOOTSTRAP$',16) from dual; DUMP('BOOTSTRAP$',16) -------------------------------------------- Typ=96 Len=10: 42,4f,4f,54,53,54,52,41,50,24

然后数据库将递归查询该对象中的数据,向内存中加载其他对象。更进一步。

这里可以看到数据库加载了回滚段信息,首先加载的是SYSTEM的回滚段,转储Row Cache信息之后,就可以看到这些详细的内容。

SQL> ALTER SESSION SET EVENTS 'immediate trace name row_cache level 10';

这里得到的BUCKET 37包含了回滚段信息。

其中53595354454d正是SYSTEM回滚段。

SQL> select dump('SYSTEM',16) from dual; DUMP('SYSTEM',16) ------------------------------- Typ=96 Len=6: 53,59,53,54,45,4d

而另外一个BUCKET上正是BOOTSTRAP$对象。

这就是数据库启动过程中,BOOTSTRAP$的加载与引导过程。由上面的讨论我们可以知道bootstrap$表的重要,如果bootstrap$表发生损坏,数据库将无法启动。


本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-03-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据和云 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档