专栏首页数据和云【千里之行始于足下】谈Oracle的system表空间

【千里之行始于足下】谈Oracle的system表空间

编辑手记:SYSTEM表空间是Oracle数据库最重要的表空间,在创建数据库时被最先创建,其中包含了数据库的元数据,对于数据库来说生死攸关。对于很多初学者,全面了解system表空间就格外重要。

系统表空间是永远不能OFFLINE的,如果SYSTEM表空间OFFLINE,则数据库就无法打开,如果SYSTEM表空间出现故障,则数据库就需要进行介质恢复。在数据库的启动过程中,Oracle也需要通过SYSTEM表空间进行引导。

SYSTEM表空间及root dba

在系统表空间文件头存在一个重要的数据结构root dba,我们可以通过转储数据文件头获得这个信息。在5.2.2中我们曾经提到过,转储文件头可以通过如下命令:

alter session set events 'immediate trace nameFILE_HDRS level 10'

从生成的trace文件中,可以获得如下信息(Oracle 9i环境信息摘录):

root dba仅在SYSTEM表空间的文件头存在,用于定位数据库引导的bootstrap$信息。root dba存储的是用十六进制表示的二进制数,其中包含10位的文件号以及22位的数据块号,将0x004001a1转换为二进制就是0000 0000 0100 0000 00000001 1010 0001,前10位为1,代表文件号为1,后22位转换为十进制为417,代表数据文件1上的417号数据块。

当然在数据库中无须如此复杂,我们可以用5.3.2中提到的getbfno来转换上述root dba:

SQL> select getbfno('0x004001a1') bfno from dual; BFNO ------------------------------ datafile# is:1 datablock is:417

那么这个Block上存放的是什么对象呢?

Oracle中独一无二的Cache对象

可以查询一下数据库中file1 block 417上存放的对象:

在Oracle 9i中这里存放的是Oracle数据库中独一无二的Cache对象。这个对象的名称来自于文件号和数据块号,1.417正好就是文件1的第417个数据块。

这个Cache对象在Oracle数据库中的含义非同一般,在数据库启动的bootstrap过程中,这个对象之前的所有对象都需要用来bootstrap:

这些对象在CREATEDATABASE过程中通过sql.bsq文件创建,其对象号同样代表了这些对象的创建顺序。再来看看1.417对象中存储的信息,转储数据块可以使用如下命令:

alter system dump datafile 1 block 417

检查生成的跟踪文件,可以获得主要信息如下:

这个信息记录了BOOTSTRP的信息,00400179正好指向的是file 1 block 377:

SQL> select getbfno('0x00400179') bfno from dual; BFNO ------------------------------ datafile# is:1 datablock is:377

这一数据块上存储的正是数据库的BOOTSTRP$引导表:

SQL> select segment_name from dba_extents 2 where block_id between 377 and blocks + 377 -1; SEGMENT_NAME ------------------------- BOOTSTRAP$

而1.417对象的前一个对象正是BOOTSTRAP$,这个对象中存放的就是创建这些对象的语句,这些语句在数据库启动时,需要被获取以在内存中创建这些对象,再从硬盘上加载启动数据库必须的元数据,从而启动Oracle数据库:

注意在Oracle 10g/11g中,Cache对象已经不再存在:

此时Oracle的root dba里直接存储了指向obj#=56的object,也就是存储指向了表bootstrap$的数据块的地址。

我们现在来模拟一下在10g/11g里,Oracle在启动数据库的时候是如何找到表bootstrap$和bootstrap$里存储的各个基表的创建语句的。

首先,Oracle会去读1号数据文件(通常是system表空间的第一个datafile,如system01.dbf )的文件头,Oracle通过读取文件头里记录的root dba,就知道了指向表bootstrap$的数据块的地址:

从上述结果里我们可以看到,现在root dba指向了0x00400179(即file 1,block 377),接着Oracle会去读root dba指向的数据块,以获得bootstrap$的对象号和其存储的各个基表的创建语句:

可以看到这里root dba指向的object的对象号实际上是0x00000038,也就是10进制的56,即bootstrap$。

SQL> select to_number('38','XX') from dual; TO_NUMBER('38','XX') -------------------- 56 SQL> select name from sys.obj$ where obj#=56; NAME ------------------------------ BOOTSTRAP$

Oracle已经通过root dba找到了表bootstrap$的对象号(obj#),但现在的问题是:只知道bootstrap$的obj#是不够的,bootstrap$中的记录到底存在哪里?

答案是表bootstrap$中记录的存储地址实际上是存在root dba所指向的数据块的ktetb这个结构里。好了,我们这里来证明上述观点:

上述记录里SQL_TEXT为“CREATE ROLLBACKSEGMENT SYSTEM STORAGE ( INITIAL 112KNEXT 1024K MINEXTENTS 1 MAXEXTENTS 32765 OBJNO 0 EXTENTS (FILE 1 BLOCK 9))”,在ultraEdit里看一下其16进制编码,上述语句的16进制编码为:

按照上述观点,在ktetb[0]. ktetbdba所指向的的那个block里一定会有一条记录,这条记录有三个column,这三个column的值分别为80,80和80

好了,我们现在来验证一下:

这里我们可以看到,bootstrap$ 中obj#=0的那条记录确实是存在上述block中,即我们的观点得到证明。

另外,我们从上述证明过程中也可以看出Oracle在10g/11g中会首先访问root dba(这里是0x00400179,即file 1 block 377)以获得表bootstrap$的对象号(obj#)和结构ktetb中所指向的存储bootstrap$中记录的数据块地址,接着就会去读取这个数据块(这里是0x0040017a,即file 1 block 378)以获得bootstrap$存储的各个基表的创建语句。关于这一点,我们也可以从下一节中我们会提到的Oracle在open过程中的10046事件的trace文件中得到佐证:

WAIT #1: nam='db file sequential read' ela= 35 file#=1 block#=377 blocks=1 obj#=-1 tim=17525910818553 WAIT #1: nam='db file scattered read' ela= 7618 file#=1 block#=378 blocks=3 obj#=-1 tim=17525910826329

现在我们来总结一下——Oracle在启动数据库的过程中,会先去读1号数据文件的文件头中记录的rootdba,再通过root dba去找bootstrap$中存储的那些数据字典的基表的定义,最后根据这些定义创建数据字典。即所谓的一生二,二生三,三生万物。

Oracle数据库的引导

现在我们可以全面地来回顾一下数据库的内部引导过程(已经熟悉了nomount、mount、open的过程),通过10046事件可以跟踪一下数据库的启动过程:

SQL> startup nomount; ORACLE instance started. Total System Global Area 139531744 bytes Fixed Size 452064 bytes Variable Size 121634816 bytes Database Buffers 16777216 bytes Redo Buffers 667648 bytes SQL> alter session set events='10046 trace name context forever,level 12'; Session altered. SQL> alter database mount; Database altered. SQL> alter database open; Database altered.

从跟踪文件中可以获得如下重要信息

从以上信息中可以注意到,Oracle首先通过direct path read方式从每个数据文件头读取了第一个Block的信息,然后通过db file sequential read的单块读方式分别读取了数据文件1的第417个block和第377个block。

417上存放的正是1.417号对象,通过1.417对象进而找到bootstrap$对象,也就是block 377,找到了block 377,Oracle进而读取其内容,在内存中创建了这个对象:

再接下来,Oracle通过递归查询,从bootstrap$中获取其他对象的创建语句:

PARSING IN CURSOR #2 len=55 dep=1 uid=0 oct=3 lid=0 tim=1149404325233023 hv=3952717224 ad='533984d8' select line#, sql_text from bootstrap$ where obj# != :1 END OF STMT

进而创建这些对象:

PARSING IN CURSOR #2 len=129 dep=1 uid=0 oct=36 lid=0 tim=1149404325255090 hv=0 ad='b700de24' CREATE ROLLBACK SEGMENT SYSTEM STORAGE ( INITIAL 112K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 32765 OBJNO 0 EXTENTS (FILE 1 BLOCK 9)) END OF STMT

在读取了1.417号对象之前的所有对象后,Oracle将可以正常打开数据库。

注意:在上一节我们已经指出——在Oracle 10g/11g中,Oracle将root dba直接指向了bootstrap$对象,从而消除了Oracle数据库中这个唯一的Cache对象。

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

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

所以我们经常强调:SYSTEM表空间极其重要,备份重于一切。希望大家能够更加重视数据库和用户数据的安全

本文分享自微信公众号 - 数据和云(OraNews),作者:盖国强

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-01-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 一文了解华为Gauss数据库:开发历程、OLTP&OLAP特点、行式&列式存储,及与Oracle和AWS对比

    数据库是计算机行业的基础核心软件,所有应用软件的运行和数据处理都要与其进行数据交互。2008年阿里提出“去IOE”,而10年之后,我们现在来看,发现Oracle...

    数据和云
  • DBA入门之路:学习与进阶之经验谈

    初入数据库之门的朋友们,总是关心如何能够快速提高,不断进步,事实上任何一个技术方向,都没有太多的捷径可走,勤奋与坚持必不可少,但是有一些方法和他人的经验可做借鉴...

    数据和云
  • 2020年4月数据库流行度排行:MySQL 成事实王者,国产openGauss引期待

    2020年4月号 DB-Engines 数据库流行度排行出炉。在本月的排行榜上,Oracle 较上月微涨 4.78 分,MySQL 微涨 8.62 分,甲骨文公...

    数据和云
  • jupyter 导入csv文件方式

    补充知识:在jupyter中读取CSV文件时出现‘utf-8′ codec can’t decode byte 0xd5 in position 0: inva...

    砸漏
  • 打包出现your account does not have permission to create iOS distribution

    rectinajh
  • 内网渗透 | IPC$入侵大全

    IPC$(Internet Process Connection)是共享"命名管道"的资源(大家都是这么说的),它是为了让进程间通信而开放的命名管道,可以通过验...

    HACK学习
  • 三个Python爬虫版本,爬取校花网,轻松入门爬虫

    Python现在非常火,语法简单而且功能强大,很多同学都想学Python!所以小的给各位看官们准备了高价值Python学习视频教程及相关电子版书籍,欢迎前来领取...

    python学习教程
  • leetcode410. Split Array Largest Sum

    将一个长度为n的正整数数组分割为m个非空的连续子数组,并分别计算每个子数组中所有元素的和。求一种分割方式,使得该分割方式生成的最大子数组和为所有分割方式中最小的...

    眯眯眼的猫头鹰
  • SAS市场研究应用介绍:多维偏好分析

    一多维偏好分析(multidimensional preference analysis)介绍 在联合分析中,被访者需要描述他们对产品的偏好情况,这些产品有若...

    小莹莹
  • LeetCode 217. Contains Duplicate

    ShenduCC

扫码关注云+社区

领取腾讯云代金券