循序渐进Oracle:数据库管理、优化与备份恢复

978-7-115-25317-0
作者: 盖国强
译者:
编辑: 杜洁
分类: Oracle

图书目录:

详情

本书从基础知识入手,详细讨论了Oracle数据库管理、第三方工具的应用、故障诊断及分析方法等热点问题,并通过大量取自实际工作现场的实例,力图将Oracle知识全面、系统、深入地展现给读者。

图书摘要

循序渐进Oracle:数据库管理、优化与备份恢复
盖国强 著
人民邮电出版社

北京

其他

应Eygle的邀请,我参与修订了本书中关于“自动存储管理(ASM)”部分内容,也因此知道对于书中每一部分,Eygle都很负责任地搭建测试环境进行了详细测试,他在用心地更新这本书,我相信作为读者的你们也一定可以感觉得到。

实际上,我比较诧异Eygle在忙碌的工作之余怎么还能找出时间来重新修订这本4年前出版的作品,这并不是一件轻松的工作,于是再次证明了,只要用心,时间总是有的。

Oracle ACE总监,恩墨科技技术总监 张乐奕

这些年,收集Eygle出版的每一本书已经成了我的一个习惯,从2006年的《深入浅出Oracle》到2010年的《Oracle DBA 手记 2》,他的每一本书我都曾仔细阅读,慢慢体会,看到会心之处往往禁不住拍案叫绝,深刻地体会到 Oracle的博大精深与Eygle行文的严谨和圆润自如。

而《循序渐进Oracle》就是这其中很特别的一本,它从Oracle数据库的创建开始讲起,沿着Oracle的字符集、用户的创建与管理、表空间与数据文件等一直讲到Oracle的备份与恢复,几乎构成了一条完整的学习链条,我揣摩Eygle的用意大概是你把我书中的这些内容都吃透了,Oracle应该就可以算入门了。

事实上,自打我入行以来,Eygle一直是我的榜样和努力的目标,从我当年看《深入浅出Oracle》的不明就里到如今我居然可以参与《循序渐进Oracle》的修订工作,除了有我个人努力的原因之外,从Eygle他们持续不断地分享中学习也是一个极为重要的因素!

这次我参与修订的章节是“表空间和数据文件”与“ASM自动存储管理”中的部分内容,经过扩展、补充与修订,这两章所涵盖的内容已经非常广泛和深入,希望我的参与能为本书增辉,能为读者助力。

Oracle ACE 崔华(dbsnake)

何谓良师益友?一本好书,一杯茗茶……

还清楚地记得曾经阅读此书时的那种畅快淋漓的感觉,字斟句酌的品味与躬亲,时间仿佛在那里停滞,一种窒息的美感油然而生。

深入浅出的知识讲解配以大量实例和实验操作,读者可边学习边实践。对于一贯主张“躬亲”的本人来说,本书极强的实践性无疑是我极为推崇的。本人坚持认为,此书不可“读”,唯有“践行”方可领悟其中的真谛。技术是在反复操练中领悟真知的过程。格物致知,本书体现了理论与实践的结合。

本书的实例兼顾广度和深度,实例涵盖 Oracle 核心知识点,关键知识点又通过实例深挖细究。书中的实例具有很强的实用性,大部分例子取自DBA真正的日常工作,也许您昨天刚刚碰到的、百思不得其解的问题,今天就会在这本书里找到答案。而最重要的是这本书不仅“授人以鱼”,更是“授人以渔”,它不仅给出问题的答案,还会带您一起分析,找到解决问题的思路,让您开始了解“高手”是如何思考的。

对于本书的学习,本人有以下几点建议。

如果您是一名刚刚起步的“学生级”DBA,不如和着本书的步调,按部就班地从最初的数据库创建、OEM及Grid Control等工具的使用开始学起,慢慢升级到数据库备份与恢复、故障诊断及分析等高级课题,重点可放在基础知识的学习上。

如果您是一名刚刚“毕业”、初出茅庐的初级DBA,本书便是一本“武功秘笈”,它可以助您提升功力。您可以略过熟知的基础知识,重点关注书中的实例,挑选您感兴趣或者有疑惑的部分细细体味、动手实践,看高手如何拆招,像高手那样思考。

作为一名高级DBA,本书也会给您带来诸多裨益。正所谓“他山之石,可以攻玉”,书中涵盖了Eygle对诸多技术问题的看法和见解,给出了他解决问题的方法和思路,相信您从中定会有所收获、有所借鉴。

雏鹰成长为雄鹰并非只是时间使然,它需要充足的养分长出健硕的翅膀,它需要搏击长空练就高旋的本领,DBA的成长又何尝不是如此呢?汲取、沉淀、实践、反思、成长。最爱在夜阑人静、万籁俱寂之时,泡上一杯香茗,在幽幽灯光下,捧上一本好书,且读且思,思而复做,倾听指尖触键的噼啪声,任思绪沉淀、飞扬。唯有此时,方能感受到内心的充实与成长。

一本好书犹如源头活水,用涓涓清流滋养我们的心智。读本书如饮甘冽清泉,畅快淋漓、欲罢不能。开卷有益,不若始于今日;韶华易逝,切莫空待明朝!

国际航空运输协会(IATA)数据架构师,OCM,ACOUG成员 侯圣文(Secooler)

新版序

距离本书第一版的出版,转眼已有4个年头,写第一版时,我的儿子还没有出生,而现在,他已经上了幼儿园,可以和我认真地说话和沟通……静静地回头思量,时光悄然无声地流逝却给我们留下了刻骨铭心的痕迹,总想着,写点什么为时光留下一些纪念,也正因为这个念头,我才萌生了修订本书第一版的念头。

在这4年之中,甲骨文公司发生了巨大的变化,它已经不再是一家单纯的软件公司,随着对SUN公司的并购完成,硬件业务以及随之衍生的Oracle Exadata Database Machine、Oracle Exalogic Elastic Cloud等产品成为了市场的新生力量,并且 MySQL 也成为了甲骨文产品家族中的一员,现在甲骨文的企业理念变成了“Hardware and Software Engineered toWork Together”。从数据库产品来说,Oracle Database 10g已经成为市场的主流,Oracle Database 11g 正在迅速普及,甲骨文公司在不断地引领市场的技术进步。

在这 4年之中,我也收到了大量读者对于本书第一版的反馈,有读者能够领略到作者的写作意图,也有读者表达了对于本书第二版的美好期待;在2010年,我使用本书第一版指导了公司的实习生进行学习,发现往往他们不能抓住我认为非常重要的知识点,这虽然与阅读者的阅读习惯和思考方式有关,但是作者也有不可推卸的责任,在编写本书第二版的过程中,我选择性地将一些重点字句用黑体字体表示出来,希望读者在阅读时要特别关注并掌握这些重要内容。

在编写每一章时,我试图从数据库创建的每一个点出发,将相关知识拓展开来,充分展示给读者,这种由点及面的发散式学习方式是我一直以来的重要学习方法,然而这种学习不可避免地涉及了大量的知识拓展,要求读者能够抓住主线,深入阅读与实验,这个学习过程可能是艰苦的,但是经过这样的磨炼,初学者就能够快速地成长起来。记得公司的小罗刚进公司时所做的工作就是使用 DBMS_BACKUP_RESTORE 包去解析和抽取数据文件,攻克了种种难题之后,再进行学习就会是信手拈来的事情。本书的第1章就是这样最为典型的核心章节,我尽量控制了这一章的篇幅,虽然我们完全可能将这一章展开成一本独立的书。

在本书在修订的过程中,我获得了一些朋友的帮助,在此要表示深深地感谢。

感谢侯圣文(secooler)协助审阅了本书的第2章,他补充完善了Grid Control的内容,这是Oracle Database 10g 之后甲骨文公司非常重要的产品,圣文以他丰富的OCM理论与实践为本章增添了无与伦比的光辉。

感谢崔华(dbsnake)帮忙修订了本书的第5章,他在Oracle数据格式、数据恢复方面的理解无人能出其右,崔华补充并完善了本章的相关知识点,使其大放异彩。

感谢张乐奕、崔华协助修订了本书的第6章,这一章从第一版的第5章中拆分出来,主要介绍了Oracle的ASM技术,ASM技术自Oracle 10g 引入以来,已经发展成为Oracle RAC的核心支撑技术,并由此发展出ACFS集群文件系统等新特性,鉴于ASM的重要性及广泛应用,我们将这部分内容补充完善为独立的一章。

感谢读者的支持,使得本书有机会再次修订出版;感谢我的编辑,也正是她的不断督促,我才不敢松懈,终于完成了本书的修订。

感谢我的太太Julia和我的儿子Enmo,这本书也是献给你们的,你们和我一起走过那些难忘的岁月,成为我生命中的珍宝!

盖国强(Eygle)

2011年5月 于北京

前言

关于本书第一版

在本书第一版出版时,根据当时IDC的统计数据(2006年)Oracle 数据库以 44.4%的市场占有率稳居关系数据库市场的首位,占据第二位的IBM其份额为21.2%(IDC 2005年的数据为Oracle占有44.3%,IBM占有21.6%);而根据Gartner最新的统计数据(2011年3月30日发布),Oracle数据库的市场份额已经上升到 48.1%。数据库市场迅速发展和扩大,相关的从业机会也进一步增加,这对于学习和选择Oracle技术的朋友们来说,是一个很好的时机和机遇。

《深入浅出Oracle——DBA入门、进阶与诊断案例》(以下简称“深入浅出Oracle”,该书已于2009年出版升级版,更名为《深入解析Oracle——DBA入门、进阶与诊断案例》)一书在2006年出版后,得到了市场的普遍欢迎与广泛好评,应广大读者建议,作者继续撰写了本书的第一版,本书的第一版在继承“深入浅出 Oracle”一书优点的同时,极力避免和修正了之前读者所指出的不足,这些努力也得到了广大读者的认可。

本书作者 Eygle 活跃于国内著名 Oracle 技术论坛ITPUB(www.itpub.net),并全力打造国内极具影响力的个人 Oracle 技术站点 Eygle.com(www.eygle.com)。虽然图书作为作者经验积累与分享知识的一种载体,可以为读者展示比较严谨、系统的知识,但是如果能够有效地利用已有的各种网络资源,就可能获得更多的知识与交流,得到更快的进步与提高。

本书的第一版是ITPUB技术丛书的第4本,是在《Oracle数据库DBA专题技术精粹》和《Oracle数据库性能优化》、《深入浅出Oracle》之后,ITPUB论坛推出的又一本技术图书,而时至今天,ITPUB出版的图书已经多达10数种,IT市场的发展和繁荣可见一斑。

本书新版特点

在数据库技术日益普及的今天,浅尝辄止的学习显然已经站不住脚,当今企业对于 DBA的要求也越来越高,而本书由浅入深循序渐进的讲解正是希望引导读者学习并深入探索 Oracle技术。

本书既名为“循序渐进”,继续贯彻了作者“由浅入深、由点到线再及面”的学习方法,作者在写作过程中一直遵循了这个原则,内容从数据库的创建开始,从表空间管理深入,从备份恢复展开,从Statspack优化延伸,到故障诊断结束,全书章节按照一个DBA需要具备的从业素质进行布局,内容循序渐进,既可以引导初学者入门,又可以帮助具备一定基础的数据库从业人员进阶,希望不同层次的读者都能从本书中受益。

本书是作者多年工作实践的积累和总结,针对 DBA 在工作中的必备知识与技能,作者精心安排了本书的篇章结构。本书从基础入手,面向实际应用,力图从点到面,让读者对每个主题都有深入的了解和认识。

在数据库版本方面,本书内容更涉及Oracle 9i/Oracle 10g/Oracle 11g,将Oracle的版本变化、功能改进,一以贯之地展现出来,让大家看到这些变革的真正原因以及Oracle的不断技术创新。关于Oracle技术的很多问题是因跨越版本而存在的,所以我们必须了解一项技术的来龙去脉,才能知道一个革新、一个新特性的真正意义所在。

本书既独立成书,又是《深入解析 Oracle——DBA 入门、进阶与诊断案例》一书的姊妹篇,因此在内容上这两本书相辅相成,在布局结构上也遥相呼应,清晰地展现了 DBA 从入门到进阶的学习路线,有兴趣的读者可以对照阅读。

本书新版结构

本书分为13章,具体结构划分如下。

第1章 Oracle数据库的创建,这一章是全书的书眼,通过数据库的创建,由点及面,很多知识在这一章全面展开,甚至包括数据库迁移与RMAN。

第2章 从OEM到Grid Control,这是讲究实用的一章,在可能的环境下,Oracle的这些工具对于简化数据库的管理与维护会起到极大的推进作用。

第3章 Oracle的字符集,是否很多朋友都曾经为乱码所困惑,是否一个查询返回的是一堆莫明其妙的“靠”字或其他字符?这一章对字符集问题进行了全面的解析。

第4章 用户的创建与管理,在完成了数据库创建之后以及在提供用户使用之前,数据库用户必须被创建,作为DBA,用户的创建和管理是必备的知识。

第5章 表空间和数据文件,作为Oracle的逻辑和物理存储,理解空间管理非常重要,这一章从外部管理到内部机制上对表空间和数据文件等内容进行了深入分析,Oracle 10g 的ASM新特性也被包含在这一章内。

第6章 自动存储管理,这一章介绍了自Oracle 10g开始引入的ASM技术,这一技术已经成为Oracle数据库管理中不可或缺的重要技术,尤其是在Oracle的RAC集群架构中。

第7章 临时表空间和临时文件,这一章介绍了临时表空间和临时文件的原理及管理维护。

第8章 备份与恢复,作为 DBA 需要具备的一个最重要的技能就是备份和恢复,一个生产数据库的备份是重于一切的,本章全面介绍了Oracle数据库的备份与恢复知识。

第9章 备份方案与特例恢复,定制一个基本的备份方案,保障数据库安全,是对DBA的基本要求;在特殊情况下,执行异常恢复是对DBA的重要考验,本章从初级到高级,以备份恢复作为切入点进行了探讨。

第10章 Oracle的闪回特性,Oracle从9i到10g不停地演进着一个强大的功能,这个功能就是闪回(Flashback),这项重要功能已经简化了无数DBA的工作,本章从原理到应用上深入地介绍了Oracle的这一强大特性。

第11章 Oracle的数据加载和卸载,怎样和数据库进行数据交互是实践中经常遇到的问题,Oracle的外部表和DataPump都是常用的工具,这一章通过多个实例,介绍了一些同Oracle数据库进行数据交换的方法。

第12章 从Statspack到ADDM,Statspack是Oracle 10g之前DBA最常用的数据库性能诊断工具,ADDM是Oracle 10g引入的自动数据库诊断与监控程序,本章对这两者的用法与分析进行全面的介绍。

第13章 故障诊断及分析方法,在具备了全面的学习和知识掌握之后,本章将告诉大家如何有效地将这些知识结合起来,形成稳定的分析方法和经验积累。

本书的读者对象

本书适用于打算进入Oracle领域的初学者,也适用于具备一定数据库基础、打算深入学习Oracle技术的数据库从业人员,尤其适用于入门、进阶以及希望深入研究Oracle技术的数据库管理人员。

本书也可以作为各大中专院校相关专业的教学辅导参考用书,也可以作为相关培训机构的培训教材。

本书约定

1.为了给读者提供更多的学习资源,同时弥补本书篇幅有限的遗憾,本书提供了部分的参考链接,许多本书无法详细介绍的问题都可以通过这些链接找到答案。相关文档可以从作者的网站(www.eygle.com)上找到。

2.本书所列出的插图、运行结果可能会与读者实际环境中的操作界面有所差别,这可能是由于操作系统平台、Oracle版本的不同而引起的,在此特别说明,一切以实际情况为准。

3.广大读者如有好的建议或在学习本书中遇到疑难问题,欢迎到作者个人技术网站(http://www.eygle.com)上进行探讨,也可发电子邮件联系作者(eygle@eygle.com)。

第1章 Oracle数据库的创建

对于很多初学者来说,安装数据库软件、创建数据库通常是Oracle学习的开始。

在完成软件安装之后,就可以开始创建数据库。数据库的创建可以通过 DBCA(Database Configuration Assistant)工具或者手工方式来完成,通常我们习惯使用DBCA,但是我建议大家都能够尝试一下使用手工的方式进行数据库创建,因为那将使你更加了解Oracle数据库的创建过程。

如果从数据库创建进行深入,你会发现相关知识会延展到各个层面,由这一个点开始,广阔的Oracle知识会逐渐展现在你面前,本书就从这样一个起点开始。

从这样一个起点开始,我试图将所有的相关知识点拓展剖析,以扩大和加深读者对于Oracle数据库技术的理解和认知,全面了解数据库的功能和特性,并恰如其分地应用到合适的场景,就是一个DBA的使命。

本章主要以Oracle10g/11g为讲解模板,在实际建库的过程中,不管是在Linux/UNIX还是Windows上、不管是Oracle10g还是Oracle11g,创建数据库的步骤都是基本相同的。

 

1.1 Oracle 软件的获取与安装

在学习和接触Oracle数据库时,首先需要获取相关软件并安装创建数据库,本节简要介绍一下Oracle软件的获取与安装。

 

1.1.1 Oracle软件的获取

Oracle 的软件可以从官方网站上下载,主要的网址链接为:http://www.oracle.com/us/products/database/index.html。

在这里可以找到Oracle数据库产品的详细信息,如图1-1所示。

注册一个OTN的账户后,就可以下载Oracle最新的软件版本,目前Oracle数据库的最新版本为 11.2.0,下载的数据库软件企业版在非商业应用中,不存在任何功能上的限制,注意这里有一个重要提示:2010年9月13日,Oracle Patch Set11.2.0.2已经发布,该PatchSet是一个完整的安装版本,不需要预先安装11.2.0.1,该Patch Set 需要从support.oracle.com 站点下载,该站点仅对Oracle付费用户开放,对于常规的测试目的,11.2.0.1通常已经足够,如图1-2所示。

图1-1 Oracle数据库软件主页
图1-2 OTN数据库下载

为了推广 Oracle Database 11g 产品,Oracle 公司还注册了一个独立的站点(http://www.oracledatabase11g.com/),从这里可以找到大量的关于Oracle Database 11g的相关文档信息。

在安装 Oracle 软件的过程中,有一个类似如图 1-3 所示的界面(以下两图可以比较从Oracle10gR2到Oracle11gR2安装界面的变化),Oracle 11gR2的安装步骤列表显示变得更加直观。

图1-3 安装软件与创建数据库的选择

在这个页面中,可以选择在安装软件结束后同时创建数据库,也可以选择“仅安装数据库软件”,建议大家选择“仅安装数据库软件”项,该选项可以将软件安装和数据库创建分离开来,这样既可以将独立的两个过程分步进行,又可以在安装软件后进行从容的检查、配置和补丁应用等。

 

1.1.2 Oracle的补丁集

部署生产环境时,在安装完成数据库软件之后,需要安装和软件版本相关的最新补丁包,目前 Oracle10gR2 最新的补丁包为 Oracle 10.2.0.5,这也是 Oracle 10gR2 的最终补丁包;对于Oracle Database 11gR2,目前最新的补丁集是11.2.0.2版本。Oracle的补丁软件通过Metalink支持站点(http://support.oracle.com )发布,该站点仅对购买了Oracle服务的用户开放。

在Oracle 11gR2之前,补丁集以一个修正包的形式发布,安装补丁包,覆盖原有数据库安装的相关文件后完成升级,如果需要升级已有的数据库,还需要按照指定的步骤运行一系列的脚本文件,完成升级;从Oracle 11gR2的第一个补丁集开始(也即11.2.0.2),Oracle修改了补丁发布策略,现在发布的补丁文件是一个完整的数据库版本,可以独立安装,在安装时建议选择独立的安装目录,保持原有的安装不变,安装完成之后,可以调用DBUA(Database Upgrade Assistant)来完成既有数据库的升级。

11.2.0.2的补丁集,其Patch号为10098816,共包含7个压缩包,前两个为安装数据库的软件,如果仅安装数据库,这两个就够了;第三个是Grid的安装包;7个文件大约5GB左右,以下给出了压缩包集的内容列表,如表1-1所示。

表1-1 11.2.0.2的补丁集包含了7个压缩包

以下通过Oracle Database 11g 11.2.0.2的补丁集安装过程,简要介绍一下Oracle的这一重要变化。在初始的步骤中,如果是在软件安装过程中,请选择“仅安装数据库软件”即可,如果需要升级数据库,请选择“升级现有的数据库”,如图1-4所示。

在图 1-5 中,如果安装路径选择了现有的 Oracle 11g 安装目录,安装程序会给出重要提示,建议安装11.2.0.2到不同于11.2.0.1的目录,独立安装的好处是,当升级过程出现异常时,原有的软件目录未有丝毫改变,可以无损地启动原有数据库,这就是独立安装带来的重要好处。

如图1-6所示是补丁软件的安装过程。

图1-4 补丁升级的选择
图1-5 独立安装补丁的建议
图1-6 安装产品的进度

补丁安装完成之后,会自动启动DBUA升级程序,可以选择要升级的数据库进行升级,如图1-7所示。

图1-7 选择需要升级的数据库

在升级之前,基于性能的考虑,DBUA建议启用并行、关闭归档等,同时建议对数据库进行备份,这些以前需要DBA根据经验调整的内容现在都可以通过DBUA来自动完成,如图1-8所示。

图1-8 DBUA的升级建议

升级过程会较为缓慢,在生产数据库的升级中,尤其需要谨慎。

 

1.2 使用 DBCA 创建数据库

如果我们之前仅安装了数据库软件(或者也应用了补丁软件),在完成安装之后,可以通过运行DBCA(Database Configuration Assistant)来启动数据库创建过程。

 

1.2.1 DBCA的启动

DBCA可以通过“开始”菜单中的选项来启动,也可以通过命令行方式启动,在命令行键入“dbca”则可以启动数据库创建助手界面,如图1-9所示。

在Windows系统上,通过命令行来运行dbca命令,实际上调用的是$ORACLE_HOME\bin\下的dbca.bat批处理文件,可以简略地看一下这个批处理文件的内容(省略了部分内容):

图1-9 Database Configuration Assistant欢迎界面

D:\oracle\11.2.0\BIN>type dbca.bat

@set OH=D:\oracle\11.2.0

@set CLASSPATH=%DBCA_CLASSPATH%;%ORACLE_OEM_CLASSPATH%

@set PATH=%OH%\bin;%PATH%

"D:\oracle\11.2.0\jdk\jre\BIN\JAVA"  -DORACLE_HOME="%OH%"  -DJDBC_PROTOCOL=thin  -mx128m oracle.sysman.assistants.dbca.Dbca

可以看到在设置了一系列的环境变量之后,通过调用Java运行时环境启动了Java工具DBCA。

在 UNIX 系统中原理类似,来看下面一段取自 Sun Solaris 环境(现在已经变成了 Oracle Solaris)下的代码:

bash-2.05$ uname -a

SunOS db210-rac2 5.9 Generic_117171-12 sun4u sparc SUNW,Sun-Fire-V210

bash-2.05$ which dbca

/opt/oracle/product/10.2.0/db/bin/dbca

摘录一点dbca文件的代码:

bash-2.05$ more /opt/oracle/product/10.2.0/db/bin/dbca

#!/bin/sh -f

# Classpath

JRE_CLASSPATH=$JRE_DIR/lib/$JRE_FILE

# Run DBCA

$JRE_DIR/bin/java -Dsun.java2d.font.DisableAlgorithmicStyles=true

-DORACLE_HOME=$OH -DDISPLAY=$DISPLAY -DJDBC_PROTOCOL=thin -mx128m

-classpath $CLASSPATH oracle.sysman.assistants.dbca.Dbca $ARGUMENTS

同样最后一行命令启动了Java应用DBCA工具。以上就是DBCA的初始化及启动。

 

1.2.2 模板选择及EM选项

启动DBCA之后,就可以通过图形界面进行数据库各项参数的配置,下面对几个重要步骤进行一点说明。

在如图1-10所示的选择数据库模板界面中,可以选择使用模板来创建数据库或者通过自定义方式来创建。注意,右图来自Oracle Database 11gR2版本的相同界面,在这个界面上,已经带有明确的提示文字,指出“带数据文件的模板包含预先创建的数据库”,使用这样的模板可以在数分钟内创建完数据库,否则需要一个小时甚至更长时间。这些说明解释清楚了很多必要的问题。

图1-10 选择数据库模板

我们选择通过自定义方式创建数据库,在界面中选择“定制数据库”即可。定制数据库不包含数据文件,需要实时创建,使用模板则会使用“种子数据库(Seed Database)”的备份集恢复出预先创建好的数据文件。

接下来的步骤3 需要定义一个数据库名称和SID,步骤4 则引入了自Oracle Database 10g开始的基于浏览器的Database Control项,此处通常选择缺省配置“使用Enterprise Manger配置数据库”复选框即可,如图1-11所示。

图1-11 设置数据库标识和OEM选项

在Oracle Database 11gR2的步骤4中,增加了一个选项页,用于定义自动维护任务,在这个页面,用户可以选择是否启用自动维护任务,这些任务包括“优化程序统计信息收集和预防性指导报告”,如图1-12所示。

图1-12 Oracle Database 11gR2的自动维护任务定义

Oracle的每一个小的改动都有其背后的深层原因,在Oracle Database 10g中,自动运行的维护任务影响了很多正常的业务运行,导致故障,所以在这里,Oracle 将选择权交给用户。观察Oracle的每个变动非常有助于我们理解数据库的变革。参考1.4小节可以获得相关诊断案例。

这些缺省启用的任务可以通过 dba_autotask_task 视图查询获得,以下是 Oracle 11gR211.2.0.2版本的自动任务定义:

SQL> select client_name,task_name,status from dba_autotask_task;

CLIENT_NAME TASK_NAME STATUS

---------------------------------------- ---------------------------------------- --------

sql tuning advisor AUTO_SQL_TUNING_PROG ENABLED

auto optimizer stats collection gather_stats_prog ENABLED

auto space advisor auto_space_advisor_prog ENABLED

 

1.2.3 数据库安全与口令

我们知道在Oracle 9i之前,数据库会为数据库用户指定缺省口令,SYS用户的缺省口令为change_on_install,SYSTEM的缺省口令为manager,但是由于很多用户经常忘记修改缺省口令,进而可能为数据库留下安全隐患,所以从Oracle 9i开始,Oracle要求用户在创建数据库时自行指定用户口令。

在图1-13左图中可以简单地为所有初始用户定义一个缺省口令,但是这样显然不够安全,右图是Oracle 11gR2版本的界面,Oracle将左图中选项上下置换,缺省的就要求为所有用户指定不同的口令,小小的变化昭示着安全上的重视与增强。

图1-13 数据库身份证明

 

1.2.4 存储管理及选件

步骤6是如图1-14所示的存储选项界面,该界面用于选择数据库的存储机制,通常可以选择文件系统存储,从Oracle 10g开始Oracle引入了自动存储管理(Automatic Storage Management)的新特性,我们将在后面章节详细介绍这一新特性。从Oracle Database 11gR2开始,Oracle放弃了对于裸设备的支持,在选择存储选项时也就少了一个选项(仅有文件系统和 ASM 两个选项),图1-14的右图来自Oracle 11gR2的安装截图。

注意,由于ASM技术主要是为RAC集群数据库开发的,所以在单机上使用ASM需要进行一些特殊的配置,在Oracle 10g中,需要启动CSS服务,在Oracle 11gR2中,需要安装Grid Infrastructure,图1-15的左图是10g中的提示信息,右图是11gR2中的提示信息,详细内容可以参考本书的第6章。

图1-14 存储选项的选择
图1-15 单实例ASM安装的必要条件

步骤7和步骤8涉及空间位置的设置。其中步骤7指定数据库文件所在位置界面,数据库文件存储位置可以选择“使用Oracle管理的文件”选项,这实际上就是利用了Oracle 9i中引入的一个新特新OMF(Oracle Managed Files),在Oracle 11g的安装界面中,这个步骤被整合到了步骤6中。步骤8中恢复配置界面,该界面用于指定快速恢复区(Flash Recovery Area),这是Oracle 10g的一个新特性,用于简化用户的备份管理,快速恢复区可以是磁盘上的一个存储目录,也可以使用 ASM 存储,这里可以按照具体的需要设置。同时还可以在这个页面上选择是否启动数据库的归档模式,如图1-16所示。

图1-16 指定文件位置及闪回区设置

单击“下一步”按钮,进入如图1-17所示的选择数据库组件和定制脚本界面,Oracle的数据库组件有很多,为了简化和快速安装,可以去除大部分选项(这要根据需要进行选择,如果为了构建一个简化的测试数据库,则可以去除多数选件)。

图1-17 选择数据库组件和定制脚本

 

1.2.5 初始化参数选择设定

步骤10中包含了多个选项页,其中涵盖了大量重要的配置选项。

进入如图1-18所示的初始化参数界面,其中内存选项可以暂时接受数据库的初始推荐,这些参数可以在建库后再进行修改;右图是11g的设置页面,变化不大。

图1-18 设置初始化参数

在这个内存设置页面,实际上隐含了Oracle数据库从10g到11g的内存管理变化,在10g中,通过设置 SGA_TARGET 参数可以实现对于 SGA 的自动管理,而在 11g 中,通过设置MEMORY_TARGET参数可以实现对于SGA+PGA的统一内存调整和管理,这一变化隐藏在这一页面设置的背后,Oracle的内存管理自动化在不同版本中在不断改进和增强。

在这个页面可以为Oracle的内存使用选择一个比例,缺省的是40%,这是一个较为合理的开始,在数据库运行中,我们也可以根据需要对数据库的内存使用进行配置更改。

注意:数据块大小需要认真选择,如图1-19所示,一旦创建数据库之后,这个参数将不可修改(从Oracle 9i开始,Oracle支持在同一数据库中容纳不同block_size的表空间,但是初始定义的block_size将用于SYSTEM、UNDO等表空间,不可修改)。

字符集部分也需要认真选择,在中文的Windows平台上,默认的字符集就是ZHS16GBK,如图1-20所示,可以不需要修改,但是在Linux/UNIX下,如果系统语言环境默认不是中文,则这里需要根据需要进行调整;对于连接模式,可以选择默认的“专用服务器模式”选项,如右图所示。

图1-19 设置数据块大小
图1-20 设置字符集和连接模式

 

1.2.6 文件存储及创建选项

下一个步骤是数据库存储界面,如图1-21所示,给出了存储及文件信息,可以按照需要进行调整,通常选择默认设置即可。需要注意控制文件选项,其中定义了对于控制文件至关重要的几个参数,这些参数在此一旦确定,以后往往需要重建控制文件才能修改。

最后一个步骤,可以选择将此前的设置存储为一个数据库模板,并生成创建数据库的脚本,如果接受“创建数据库”的选项,接下来就可以进行数据库的创建了(此处仅选择生成了模板和创建脚本),如图1-22所示。

图1-21 数据库存储选项

单击“确定”按钮,进入如图1-23所示的界面,数据库完成了脚本生成工作。如果选择了创建数据库,此时将开始数据库创建工作。

图1-22 创建选项
图1-23 生成建库所需的脚本

 

------------------------------------ ----------- ------------------------------

1.2.7 告警日志及跟踪文件

在创建数据库的过程中遇到的错误,可以通过查找Oracle数据库的告警日志文件(alert file)获得,某些情况下,还会有详细的跟踪文件(trace file)生成,这些文件的位置,在Oracle 11g之前,由*dump 参数指定,告警日志文件 alert_<ORACLE_SID>.log 的位置由参数background_dump_dest定义:

SQL> show parameter background_dump_dest

NAME TYPE VALUE

background_dump_dest string D:\ORACLE\diag\rdbms\eyglee\eyglee\trace

可以在该参数的设置路径下,找到日志文件。从 Oracle11g 开始,alert 文件的格式发生了变化,除原有的文本格式外,还引入了 XML 格式。现在告警日志文件的存储位置受到一个新的参数影响,这个参数是diagnostic_dest,原有的*dump参数被废弃:

SQL> show parameter diag

NAME TYPE VALUE

------------------------------------ ----------- ------------------------------

diagnostic_dest string D:\ORACLE

diagnostic_dest是Oracle11g的新特性自动诊断库(Automatic Diagnostic Repository,ADR)的设置,该目录用于存放数据库诊断日志、跟踪文件等,通常称为称作ADRbase,该参数的默认值和环境变量ORACLE_BASE有关:

如果设置了ORACLE_BASE,则DIAGNOSTIC_DEST= ORACLE_BASE。

如果未设置ORACLE_BASE,则DIAGNOSTIC_DEST= ORACLE_HOME/log。

通过该目录结构,数据库整合存储了大量动态变化的日志及跟踪文件,方便管理及查看。在数据库出现问题时需要优先检查该文件,获得最及时的故障提示信息等。

查询v$diag_info视图可以获得跟踪诊断的相关信息,其中“Default Trace File”指出进程跟踪文件的可能名称:

SQL> select name,value from v$diag_info;

NAME VALUE

------------------------------ ------------------------------------------------------------

Diag Enabled TRUE

ADR Base D:\ORACLE

ADR Home D:\ORACLE\diag\rdbms\eyglee\eyglee

Diag Trace D:\ORACLE\diag\rdbms\eyglee\eyglee\trace

Diag Alert D:\ORACLE\diag\rdbms\eyglee\eyglee\alert

Diag Incident D:\ORACLE\diag\rdbms\eyglee\eyglee\incident

Diag Cdump D:\ORACLE\diag\rdbms\eyglee\eyglee\cdump

Health Monitor D:\ORACLE\diag\rdbms\eyglee\eyglee\hm

Default Trace File D:\ORACLE\diag\rdbms\eyglee\eyglee\trace\eyglee_ora_3360.trc

Active Problem Count 3

Active Incident Count 45

 

1.3 数据库创建的脚本

在DBCA的最后一个步骤,如果保存生成了创建数据库的脚本,则可以通过手工执行这些脚本,在命令行完成数据库的创建工作,这可以使我们摆脱图形界面的困扰,特别是在一些不易于运行图形界面的环境。此外,很多时候通过DBCA创建数据库可能会遇到一些错误,这些错误在图形界面下可能不易判断,但是通过命令行则要容易定位得多。

 

1.3.1 数据库创建脚本

现在通过数据库的创建脚本来深入地了解一下数据库的创建过程。按照上面的路径找到生成的数据库创建脚本。

C:\Oracle\admin\eygle\scripts>dir

2007-01-05 15:32 <DIR> .

2007-01-05 15:32 <DIR> ..

2007-01-05 15:32 1,139 CreateDB.sql

2007-01-05 15:32 600 CreateDBCatalog.sql

2007-01-05 15:32 326 CreateDBFiles.sql

2007-01-05 15:32 253 emRepository.sql

2007-01-05 15:32 614 eygle.bat

2007-01-05 15:32 698 eygle.sql

2007-01-05 15:32 2,408 init.ora

2007-01-05 15:33 1,108 postDBCreation.sql

在Linux/UNIX环境下,同样存在这样一系列的脚本:

[oracle@jumper scripts]$ pwd

/opt/oracle/admin/eygle/scripts

[oracle@jumper scripts]$ ll

total 24

-rw-r--r-- 1 oracle dba 713 Apr 24 2006 CreateDBCatalog.sql

-rw-r--r-- 1 oracle dba 338 Apr 24 2006 CreateDBFiles.sql

-rw-r--r-- 1 oracle dba 769 Apr 24 2006 CreateDB.sql

-rwxr-xr-x 1 oracle dba 628 Aug 18 2006 eygle.sh

-rw-r--r-- 1 oracle dba 2764 Apr 24 2006 init.ora

-rw-r--r-- 1 oracle dba 442 Apr 24 2006 postDBCreation.sql

 

1.3.2 创建的起点

如果通过手工执行脚本来创建数据库,需要执行的脚本为 eygle.bat(在 Linux/UNIX 下是eygle.sh脚本),来看一下这个脚本的内容:

C:\Oracle\admin\eygle\scripts>type eygle.bat

mkdir C:\oracle\10.2.0\cfgtoollogs\dbca\eygle

mkdir C:\oracle\10.2.0\database

mkdir C:\oracle\admin\eygle\adump

mkdir C:\oracle\admin\eygle\bdump

mkdir C:\oracle\admin\eygle\cdump

mkdir C:\oracle\admin\eygle\dpdump

mkdir C:\oracle\admin\eygle\pfile

mkdir C:\oracle\admin\eygle\udump

mkdir C:\oracle\flash_recovery_area

mkdir C:\oracle\oradata

set ORACLE_SID=eygle

C:\oracle\10.2.0\bin\oradim.exe -new -sid EYGLE -startmode manual -spfile

C:\oracle\10.2.0\bin\oradim.exe -edit -sid EYGLE -startmode auto -srvcstart system

C:\oracle\10.2.0\bin\sqlplus /nolog @C:\oracle\admin\eygle\scripts\eygle.sql

这就是Oracle创建数据库的过程。

(1)建立一系列的目录。

注意,这里建立的 bdump 目录是 Oracle 重要的警告日志的存放地点,其缺省名称为alert_<sid>.log,我们应该定期检查该文件以发现数据库的故障或错误信息;在Oracle Database 11g中,这些文件的统一路径由参数diagnostic_dest定义。

第二个需要格外注意的是cfgtoollogs\dbca\eygle目录,在创建数据库时,主要的日志文件或输出信息会记录在该目录中,通过检查这些文件可以用来诊断创建过程中出现的一些错误。

(2)设置ORACLE_SID环境变量。

(3)通过oradim创建并配置实例。

(4)通过sqlplus运行脚本开始创建数据库。

 

1.3.3 ORADIM工具的使用

ORADIM工具是Oracle在Windows上的一个命令行工具,用于手工进行Oracle服务的创建、修改、删除等工作。ORADIM的使用很简单,通过帮助文件可以看到常用的命令示例,此处不再赘述。

ORADIM在数据库恢复中也常被用到,很多朋友都问过这样的问题:在Windows上,如果系统崩溃了,可能数据库软件丢掉了,但是数据文件、控制文件、日志文件等都还在,该怎样来恢复Oracle数据库?

其实过程很简单,通常只要按原来的目录结构重新安装Oracle软件,然后通过ORADIM工具重建服务,就可以启动实例、加载数据库(当然,相关的参数文件和口令文件等需要保存在$ORACLE_HOME\database目录中)。

来看以下过程,通过ORADIM创建一个服务后,实例会随之启动:

C:\>oradim -new -sid eygle

实例已创建。

用net命令可以查看系统启动了哪些服务,看到Oracle的服务已经启动:

C:\>net start

已经启动以下 Windows 服务:

...............

OracleServiceeygle 

Plug and Play

Print Spooler

命令成功完成。

如果你的系统装了一些UNIX增强工具(强烈建议在Windows上安装UNIX增强工具集,熟悉常用UNIX命令),那么可以通过grep过滤一下:

C:\>net start |grep Oracle

OracleServiceeygle

使用ORADIM工具后,会在$ORACLE_HOME\database目录下生成一个日志文件。

 

1.3.4 ORACLE_SID的含义

注意到在ORADIM创建服务之前,首先设置了ORACLE_SID:

setORACLE_SID=eygle

在Linux/UNIX系统的创建中,同样要设置ORACLE_SID,不过Linux/UNIX上不存在服务这项内容,实例是可以通过参数文件直接启动的(注意:启动数据库实例还和一些内核参数有关,在产品环境中需要按手册认真设定)。

看一下Linux上正常情况下启动到nomount状态的过程:

[oracle@jumper oracle]$ cd $ORACLE_HOME/dbs

[oracle@jumper dbs]$ ls

initconner.ora init.ora lkCONNER orapwconner spfileconner.ora spfile.ora

[oracle@jumper dbs]$ exportORACLE_SID=conner

[oracle@jumper dbs]$ sqlplus "/ as sysdba" 

SQL> startupnomount

ORACLE instance started.

Total System Global Area 80811208 bytes

Fixed Size 451784 bytes

Variable Size 37748736 bytes

Database Buffers 41943040 bytes

Redo Buffers 667648 bytes

注意这里,Oracle根据参数文件的内容,创建了instance,分配了相应的内存区域,启动了一组后台进程。

回顾一下前面的内容,注意到SID和ORACLE_SID已经多次出现,那么SID是什么?在数据库启动过程中又起到什么作用呢?

SID是System IDentifier的缩写,而ORACLE_SID就是Oracle System Identifier的缩写,在Oracle系统中,ORACLE_SID以环境变量的形式出现,在特定版本的Oracle软件安装(也就是ORACLE_HOME)下,当Oracle实例启动时,操作系统上fork的进程必须通过这个SID将实例与其他实例区分开来,这就是SID的作用。

我们知道 Oracle 的实例( instance )是由一块共享内存区域( SGA )和一组后台进程(background processes)共同组成;而后台进程正是数据库和操作系统进行交互的通道,这些进程的名称就是通过ORACLE_SID决定的。

实例的启动仅需要一个参数文件,而这个参数文件的名称就是由 ORACLE_SID 决定的。对于init文件,缺省的文件名称是init<ORACLE_SID>.ora,对于spfile文件,缺省的文件名为spfile<ORACLE_SID>.ora,Oracle依据ORACLE_SID来决定和寻找参数文件启动实例,参数文件的缺省位置为$ORACLE_HOME/dbs(Windows上为$ORACLE_HOME\database目录)。

spfile从Oracle 9i开始引入并成为了缺省使用的参数文件,Oracle启动实例时按照以下顺序从缺省目录查找参数文件:

spfile<ORACLE_SID>.ora→spfile.ora→init<ORACLE_SID>.ora。

如果这3个文件都不存在,则Oracle实例将无法启动。

通过这些信息可以知道,在同一个ORACLE_HOME下,Oracle能够根据ORACLE_SID将实例区分开来;但是如果在不同的ORACLE_HOME下,Oracle将不屏蔽相同名称的ORACLE_SID,也就是说在同一台主机的不同ORACLE_HOME下,Oracle也是能够创建相同ORACLE_SID的实例的。

以下是一个测试。首先启动一个Oracle 8i下ORACLE_SID为eygle的实例:

$ exportORACLE_SID=eygle

$ sqlplus "/ as sysdba"

SQL*Plus: Release 8.1.7.0.0 - Production on Fri Feb 16 10:23:58 2007

(c) Copyright 2000 Oracle Corporation. All rights reserved.

Connected to an idle instance.

SQL> startup nomount;

ORACLE instance started. 

SQL> ! ps -ef|grep smon

oracle8 11092 1 0 10:24:02 ? 0:00 ora_smon_eygle

接下来又可以启动另外ORACLE_HOME下ORACLE_SID为eygle的实例:

$ export ORACLE_SID=eygle

$ sqlplus "/ as sysdba"

SQL*Plus:Release9.2.0.4.0 - Production on Fri Feb 16 10:24:43 2007

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

Connected to an idle instance.

SQL> startup nomount;

ORACLE instance started. 

SQL> ! ps -ef|grep pmon_eygle

oracle9 11180 1 0 10:24:48 ? 0:00 ora_pmon_eygle

oracle8 11084 1 0 10:24:02 ? 0:00 ora_pmon_eygle

现在这同一台主机上就启动了两个相同名称的实例,在操作系统上,Oracle能够通过ID标识将共享内存或信号量区分开来:

$ ipcs -i

IPC status from <running system> as of Fri Feb 16 10:30:02 CST 2007

T ID KEY MODE OWNER GROUP

Message Queues:

q 0 0x2e781d5 --rw-r--r-- root root

T ID KEY MODE OWNER GROUP ISMATTCH

Shared Memory:

m 4096 0xabdc9b64 --rw-r----- oracle8 dba 12

m 1025 0x79552064 --rw-r----- oracle9 dba 11

Semaphores:

s 1245184 0x79978bac --ra-r----- oracle8 dba

s 458753 0xa0e9f594 --ra-r----- oracle9 dba

通过Oracle提供的一个小工具sysresv,我们可以找到对应于不同的ORACLE_SID,操作系统上创建的共享内存段ID(Shared Memory)和信号量ID(Semaphores)等信息。

$ sysresv -l eygle julia

IPC Resources for ORACLE_SID "eygle" :

Shared Memory:

ID KEY

2560 0x79552064

Semaphores:

ID KEY

720896 0xa0e9f594

Oracle Instance alive for sid "eygle"

IPC Resources for ORACLE_SID "julia" :

Shared Memory:

ID KEY

514 0xab281214

Semaphores:

ID KEY

196610 0xa7645a54

Oracle Instance alive for sid "julia"

在Linux/UNIX上,一个名为oratab的文件还记录有ORACLE_SID信息。在Solaris环境中,这个文件一般位于/var/opt/oracle目录下,在Linux及其他UNIX平台,这个文件一般位于/etc目录下。

该文件的主要内容如下:

# This file is used by ORACLE utilities. It is created by root.sh

# and updated by the Database Configuration Assistant when creating a database.

# A colon, ':', is used as the field terminator. A new line terminates

# the entry. Lines beginning with a pound sign, '#', are comments.

#

# Entries are of the form:

# $ORACLE_SID:$ORACLE_HOME:<N|Y>: 

# The first and second fields are the system identifier and home

# directory of the database respectively. The third filed indicates

# to the dbstart utility that the database should , "Y", or should not,

# "N", be brought up at system boot time.

#

# Multiple entries with the same $ORACLE_SID are not allowed.

*:/opt/oracle/product/9.2.0:N 

当执行dbstart脚本时,Oracle会根据这里记录的ORACLE_SID的<N|Y>的设置来决定是否启动相关实例。

与Linux/UNIX上的情况类似,Windows上的Oracle环境也依赖于服务而存在,如图1-24所示。

图1-24 Windows上的Oracle环境依赖于服务

我们注意到 Oracle 环境的初始化是通过ORACLE.EXE eygle来完成的,至于实例和数据库是否随服务启动要依赖于注册表中的设置。

通过手动在命令行执行类似命令,可以初始化任意的Oracle应用环境,例如,以下命令就初始化了名为julia的运行时环境:

C:\>oracle julia

Press CTRL-C to exit server:

此后就可以连接到这个环境启动实例:

C:\>set ORACLE_SID=julia

C:\>set nls_lang=american_america.us7ascii

C:\>sqlplus "/ as sysdba"

SQL*Plus: Release 11.2.0.1.0 Production on Tue Aug 31 22:09:31 2010

Copyright (c) 1982, 2010, Oracle. All rights reserved.

Connected to an idle instance.

SQL> startup

ORA-01078: failure in processing system parameters

LRM-00109: 无法打开参数文件 'D:\ORACLE\11.2.0\DATABASE\INITJULIA.ORA'

当然还需要创建参数文件和口令文件等:

C:\>cp c:\oracle\10.2.0\database\SPFILEEYGLE.ORA c:\Oracle\10.2.0\database\spfilejulia.ora

C:\>orapwd file=c:\oracle\10.2.0\database\PWDjulia.ora password=oracle entries=5

此后,实例可以顺利启动,并可以挂接和打开数据库:

C:\>sqlplus "/ as sysdba"

SQL*Plus: Release 10.2.0.1.0 - Production on 星期六 2月 17 10:13:10 2007

Copyright (c) 1982, 2005, Oracle. All rights reserved.

已连接到空闲例程。

SQL> startup nomount;

ORACLE 例程已经启动。

SQL> set linesize 120

SQL> show parameter instance_name

NAME TYPE VALUE

------------------------------------ ---------------------- ---------------

instance_name string julia

SQL> show parameter db_name

NAME TYPE VALUE

------------------------------- ------------------ ------------------------------

db_name string eygle

SQL> alter database mount;

数据库已更改。

SQL> alter database open;

数据库已更改。

如果在环境窗口中按下CTRL+C组合键退出,则数据库将异常中断。

总结一下,实际上不管在Windows还是Linux/UNIX环境下,ORACLE_SID的作用就是设置一个Oracle环境窗口,通过这个环境变量来标示和命名系统进程,此后Oracle的活动可以由此展开。

 

1.3.5 INSTANCE_NAME的含义及作用

作为Oracle数据库的重要组成部分INSTANCE也存在一个参数标识:INSTANCE_NAME。

INSTANCE_NAME是Oracle数据库的一个参数,在参数文件中定义,用于标示数据库实例的名称,其缺省值通常就是 ORACLE_SID,但是不同的实例可以有相同的实例名。通过简单的参数文件复制,我们就可以在同一台服务器上创建多个具有相同instance_name参数设置的实例。

首先确认当前的参数文件:

bash-2.03$ cd $ORACLE_HOME/dbs

bash-2.03$ ls initeygle.ora

initeygle.ora

复制参数文件,更改名称:

bash-2.03$ cp initeygle.ora initjulia.ora

接下来通过导入新的ORACLE_SID我们就可以启动新的实例:

bash-2.03$ export ORACLE_SID=julia

bash-2.03$ sqlplus "/ as sysdba"

SQL*Plus: Release 9.2.0.4.0 - Production on Fri Feb 16 10:34:00 2007

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

Connected to an idle instance.

SQL> startup nomount;

ORACLE instance started.

现在ORACLE_SID为julia的实例已经启动,操作系统上的进程以julia名称标记:

bash-2.03$ ps -ef|grep pmon

oracle 12396 1 0 16:30 ? 00:00:00 ora_pmon_julia

oracle 16201 1 0 18:13 ? 00:00:00 ora_pmon_eygle

oracle 16256 16219 0 18:14 pts/1 00:00:00 grep pmon

但是新实例的instance_name参数设置仍然是eygle:

SQL> show parameter instance_name

NAME TYPE VALUE

------------------------------------ ---------------------- -----------------------

instance_name string eygle

总结一下,ORACLE_SID在这里用于标示进程,而instance_name则用来标示实例,两者可以具有不同的名称。但是如果不同往往带来歧义,不具备实际的意义,所以从Oracle Database 10g开始,缺省的情况下,Oracle将 instance_name这个参数从参数文件中剔除,这样就能够尽量保证ORACLE_SID和instance_name的一致。

此外Oracle的监听器(listener)配置文件中的SID_NAME就是来自instance_name参数,监听器通过instance_name才能确定需要将连接请求注册到哪一个实例上。通常listener.ora文件中SID_NAME相关设置类似如下示例:

SID_LIST_LISTENER =

(SID_DESC =

(GLOBAL_DBNAME = eygle)

(ORACLE_HOME = /opt/oracle/product/9.2.0)

(SID_NAME = eygle)

)

 

1.3.6 Oracle的口令文件

继续前面的脚本,在创建和启动了实例之后,Oracle开始调用eygle.sql脚本,我们将这个脚本分开来介绍。

这个脚本的最初部分是要求定义用户口令,然后使用定义的sys用户口令创建口令文件:

C:\Oracle\admin\eygle\scripts>type eygle.sql

set verify off

PROMPT specify a password for sys as parameter 1;

DEFINE sysPassword = &1

PROMPT specify a password for system as parameter 2;

DEFINE systemPassword = &2

PROMPT specify a password for sysman as parameter 3;

DEFINE sysmanPassword = &3

PROMPT specify a password for dbsnmp as parameter 4;

DEFINE dbsnmpPassword = &4

host C:\oracle\10.2.0\bin\orapwd.exe file=C:\oracle\10.2.0\database\PWDeygle.ora

password=&&sysPassword force=y

这里又引入了另外一个工具orapwd,这个工具在Linux/UNIX上同样存在,当口令文件丢失或损坏之后,可以通过这个工具重建口令文件,这个工具的语法为:

D:\oracle\11.2.0\BIN>orapwd

Usage: orapwd file=<fname> entries=<users> force=<y/n> ignorecase=<y/n> nosysdba=<y/n>

where

file - name of password file (required),

password - password for SYS will be prompted if not specified at command line,

entries - maximum number of distinct DBA (optional),

force - whether to overwrite existing file (optional),

ignorecase - passwords are case-insensitive (optional),

nosysdba - whether to shut out the SYSDBA logon (optional Database Vault only).

There must be no spaces around the equal-to (=) character.

注意:force参数是Oracle 10g中增加的,ignorecase参数是11g新增加的。

Oracle 在启动过程中,会在$ORACLE_HOME/dbs ( Windows 下相应的目录则是$ORACLE_HOME\database)目录下查找口令文件,查找的顺序是首先检查orapw<ORACLE_SID>文件,如果不存在则查找orapw文件,如果orapw文件也不存在,就会报出如下错误:

SQL> startup force;

ORACLE instance started.

ORA-01990: erroropeningpassword file '/opt/oracle/product/9.2.0/dbs/orapw' 

ORA-27037: unable to obtain file status

Linux Error: 2: No such file or directory

Additional information: 3

口令文件丢失或损坏后,通常可以通过如下命令重建口令文件:

[oracle@jumper dbs]$ orapwd file=orapwhsjf password=oracle entries=5

在数据库没有启动之前,数据库内建用户是无法通过数据库来验证身份的,此时口令文件的作用就体现了出来。口令文件中存放了具有sysdba/sysoper身份用户的用户名及口令,Oracle允许用户通过口令文件验证,在数据库未启动之前登录,从而启动实例进而加载并打开数据库;而如果没有口令文件,在数据库未启动之前就只能通过操作系统认证方式来启动实例。在Oracle DataGuard环境中,要求主数据库和备用数据库的口令文件SYS用户密码相同,这时候经常会用到使用orapwd工具重建口令文件的技能。

Oracle通过一个初始化参数remote_login_passwordfile来限制口令文件的使用,通过这个参数可以设置用户登录时是否检查口令文件,以及有多少个数据库可以使用口令文件。这个参数有3个选项:EXCLUSIVE、SHARED和NONE。

当remote_login_passwordfile设置为NONE时,远程用户将不能通过sysdba/sysoper身份登录数据库:

SQL> show parameter pass

NAME TYPE VALUE

------------------------- ----------- ------------------------------

remote_login_passwordfile string NONE

此时,通过远程连接会收到如下错误:

SQL> connect sys/oracle@hsjf as sysdba

ERROR:ORA-01017: invalid username/password; logon denied

此处实际上是无法通过口令文件验证。

缺省的remote_login_passwordfile参数设置为exclusive,支持远程sysdba的登录操作:

SQL> alter system set remote_login_passwordfile=exclusive scope=spfile;

System altered.

这个参数是静态参数,修改后重启数据库才能生效。当remote_login_passwordfile参数设置为exclusive时,可以通过远程以sysdba身份登录数据库:

E:\Oracle\ora92\bin>sqlplus /nolog

SQL*Plus: Release 9.2.0.4.0 -

Production on 星期四 4月 15 09:47:11 2004

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

SQL> connect sys/oracle@hsjf as sysdba

已连接。

SQL> show user

USER 为"SYS"

当remote_login_passwordfile参数设置为shared时,则多个数据库可以共享一个口令文件,但是此时口令文件中只能存储SYS用户的口令,此时其他用户不能被授予sysdba身份:

SQL> select * from v$pwfile_users;

USERNAME SYSDB SYSOP

--------- ----- -----

SYS TRUE TRUE

SQL> grant sysdba to eygle;

grant sysdba to eygle

*

ERROR at line 1:

ORA-01994:GRANT failed: cannot addusers topublicpassword file 

SQL> show parameter password

NAME TYPE VALUE

---------------------------- ------ ------------------------------

remote_login_passwordfile string SHARED

此时的口令文件中是不能添加用户的。很多朋友的疑问在于:口令文件的缺省名称是orapw<ORACLE_SID>,怎么能够共享?

前面已经提到,Oracle数据库在启动时,首先查找的是orapw<ORACLE_SID>的口令文件,如果该文件不存在,则开始查找 orapw 的口令文件;如果同一主机上的多个数据库同时使用orapw文件,则口令文件就可以共享(当然通过其他方式,如符号链接等也可以实现共享)。

来看一下测试,首先移动缺省的口令文件:

[oracle@jumper dbs]$ mv orapweygle orapweygle.b

此时,启动数据库会出现如下错误:

SQL> startup force;

ORACLE instance started.

ORA-01990: error opening password file '/opt/oracle/product/9.2.0/dbs/orapw'

ORA-27037: unable to obtain file status

Linux Error: 2: No such file or directory

Additional information: 3

复制一个orapw口令文件,这时候再启动数据库就不会出现这个错误:

SQL> ! cp orapweygle.b orapw

SQL> startup force;

ORACLE instance started.

Database mounted.

Database opened.

SQL> show parameter password

NAME TYPE VALUE

------------------------------------ ----------- ------------------------------

remote_login_passwordfile string SHARED

那么你可能会有这样的疑问:多个 Exclusive 的数据库是否可以共享一个口令文件(orapw)呢?

继续这个测试,首先查看一下口令文件的内容,注意这里仅记录着INTERNAL/SYS的口令:

[oracle@jumper dbs]$ strings orapw

]\[Z

ORACLE Remote Password file

INTERNAL

AB27B53EDC5FEF41

8A8F025737A9097A

当REMOTE_LOGIN_PASSWORDFILE=EXCLUSIVE时:

SQL> alter system set remote_login_passwordfile=exclusive scope=spfile;

System altered.

SQL> startup force;

ORACLE instance started.

Database mounted.

Database opened.

SQL> ! stringsorapw

]\[Z

ORACLE Remote Password file

EYGLE 

INTERNAL

AB27B53EDC5FEF41

8A8F025737A9097A

注意:这里以EXCLUSIVE方式启动以后,实例名称信息被写入口令文件。

此时,如果有其他实例以Exclusive模式启动,仍然可以使用这个口令文件,口令文件中的实例名称同时被改写,也就是说,数据库只在启动过程中才读取口令文件,数据库运行过程中并不锁定该文件,类似于pfile/spfile文件。

进一步地,如果对其他用户授予SYSDBA的身份:

SQL> select * from v$pwfile_users;

USERNAME    SYSDB     SYSOP

----------------- -------- --------

SYS       TRUE     TRUE

SQL> grant sysdba to eygle;

Grant succeeded.

SQL> select * from v$pwfile_users;

USERNAME     SYSDB  SYSOP

----------------- ----- -----

SYS     TRUE     TRUE

EYGLE  TRUE  FALSE

SQL> ! strings orapw

]\[Z ORACLE Remote Password file

EYGLE

INTERNAL

AB27B53EDC5FEF41

8A8F025737A9097A

>EYGLE

B726E09FE21F8E83

注意此时增加的SYSDBA用户,其相关信息可以被写入到口令文件,一旦口令文件中增加了其他SYSDBA用户,此文件就不再能够被其他Exclusive的实例共享。

 

1.3.7 脚本的执行

继续来看eygle.sql的内容,接下来的脚本才是创建数据库中最关键的:

@C:\oracle\admin\eygle\scripts\CreateDB.sql

@C:\oracle\admin\eygle\scripts\CreateDBFiles.sql

@C:\oracle\admin\eygle\scripts\CreateDBCatalog.sql

@C:\oracle\admin\eygle\scripts\emRepository.sql

@C:\oracle\admin\eygle\scripts\postDBCreation.sql

第一个脚本是CreateDB.sql,其主要内容如下:

connect "SYS"/"&&sysPassword" as SYSDBA

set echo on

spool C:\oracle\admin\eygle\scripts\CreateDB.log

startup nomount pfile="C:\oracle\admin\eygle\scripts\init.ora";

CREATE DATABASE "eygle"

MAXINSTANCES 8 MAXLOGHISTORY 1 MAXLOGFILES 16 MAXLOGMEMBERS 3 MAXDATAFILES 100

DATAFILE SIZE 300M AUTOEXTEND ON NEXT 10240K MAXSIZE UNLIMITED EXTENT MANAGEMENT LOCAL

SYSAUX DATAFILE SIZE 120M AUTOEXTEND ON NEXT 10240K MAXSIZE UNLIMITED

SMALLFILE DEFAULT TEMPORARY TABLESPACE TEMP TEMPFILE SIZE 20M AUTOEXTEND ON NEXT 640K MAXSIZE UNLIMITED

SMALLFILE UNDO TABLESPACE "UNDOTBS1" DATAFILE SIZE 200M AUTOEXTEND ON NEXT 5120K MAXSIZE UNLIMITED

CHARACTER SETZHS16GBKNATIONAL CHARACTER SET AL16UTF16

LOGFILE GROUP 1 SIZE 51200K,GROUP 2 SIZE 51200K,GROUP 3 SIZE 51200K

USER SYS IDENTIFIED BY "&&sysPassword" USER SYSTEM IDENTIFIED BY "&&systemPassword";

set linesize 2048;

column ctl_files NEW_VALUE ctl_files;

select concat('control_files=''', concat(replace(value, ', ', ''','''), '''')) ctl_files from v$parameter wherename='control_files'; 

host "echo &ctl_files >>C:\oracle\admin\eygle\scripts\init.ora";

spool off

可以看到,这个文件的主要操作步骤如下:

(1)通过SYS连接;

(2)通过配置的参数文件init.ora启动实例;

(3)开始数据库创建;

(4)将数据库生成的控制文件名称追加到参数文件。

注意:由于选择了OMF管理文件,控制文件的名称在创建数据库之前是未知的,所以创建数据库之后才能得到名称加入参数文件中。

 

1.3.8 db_name参数和instance_name参数

在启动实例后执行的创建数据库中,第一个语句就是:

CREATEDATABASE"eygle"

这是数据库最重要的开始,其中"eygle"也就是图1-4中定义的数据库名称。

对于Oracle数据库来说,db_name代表数据库的名称,而instance_name代表实例的名称, instance_name通过参数文件即可修改,而db_name则不然。

我们来看一下Oracle对于数据库名称的定义:DB_NAME必须是一个不超过8个字符的文本串。在数据库创建过程中,db_name被记录在数据文件,日志文件和控制文件中。如果数据库实例启动过程中参数文件中的db_name和控制文件中的数据库名称不一致,则数据库不能启动。

通过以上定义可以看到,db_name 是最具有稳定意义的参数,在数据文件、日志文件和控制文件中都会记录数据库的名称,这个名称完全可以不同于instance_name。又由于db_name具有存储的稳定性,所以不能简单地随意更改。

以下的测试数据库拥有相同的db_name和instance_name:

[oracle@jumper oracle]$ cd $ORACLE_HOME/dbs

[oracle@jumper dbs]$ grep name initeygle.ora

*.db_name='eygle'

*.instance_name='eygle'

我们创建一个新的pfile为julia这个新的实例使用:

[oracle@jumper oracle]$ cd $ORACLE_HOME/dbs

[oracle@jumper dbs]$ cp initeygle.ora initjulia.ora

修改这个文件更改instance_name参数:

[oracle@jumper dbs]$ grep name initjulia.ora

*.db_name='eygle'

*.instance_name='julia'

然后我们启动实例名称为julia的instance:

[oracle@jumper dbs]$ export ORACLE_SID=julia

[oracle@jumper dbs]$ sqlplus "/ as sysdba"

SQL*Plus: Release 9.2.0.4.0 - Production on Tue Jul 25 14:04:15 2006

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

Connected to an idle instance.

SQL> startup mount;

ORACLE instance started.

ORA-01102: cannot mount database in EXCLUSIVE mode

注意,此时试图加载数据库时会出现错误,因为当前数据库被另外一个实例(eygle instance)加载。在非并行模式(OPS/RAC)下,一个数据库同时只能被一个实例加载。

此时已经启动了两个数据库实例,从后台进程可以看出:

[oracle@jumper dbs]$ ps -ef|grep ora_pmon

oracle 27321 1 0 Jul14 ? 00:00:00 ora_pmon_eygle

oracle 15445 1 0 14:04 ? 00:00:00 ora_pmon_julia

关闭eygle这个数据库实例后,就可以通过实例julia加载并打开db_name=eygle的数据库了:

[oracle@jumper dbs]$ exportORACLE_SID=julia

[oracle@jumper dbs]$ sqlplus "/ as sysdba"

SQL*Plus: Release 9.2.0.4.0 - Production on Tue Jul 25 14:05:06 2006

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

SQL> alter database mount;

alter database mount

*

ERROR at line 1:

ORA-01990: error opening password file '/opt/oracle/product/9.2.0/dbs/orapw'

ORA-27037: unable to obtain file status

Linux Error: 2: No such file or directory

Additional information: 3

SQL> alterdatabaseopen;

Database altered.

SQL> select name from v$datafile;

NAME

----------------------------------------------------------------------------

/opt/oracle/oradata/eygle/system01.dbf

/opt/oracle/oradata/eygle/undotbs01.dbf

/opt/oracle/oradata/eygle/users01.dbf

/opt/oracle/oradata/eygle/eygle01.dbf

新的实例具有独立的instance_name和db_name参数设置:

SQL> ! ps -ef|grep ora_pmon

oracle 15445 1 0 14:04 ? 00:00:00 ora_pmon_julia

SQL> show parameter instance_name

NAME TYPE VALUE

------------------------------------ ----------- ------------------------------

instance_name string julia

SQL> show parameter db_name

NAME TYPE VALUE

------------------------------------ ----------- ------------------------------

db_name string eygle

我们再来看一看如果参数文件中的db_name和控制文件中的db_name不一致会出现什么错误。

修改参数文件中的db_name参数:

[oracle@jumper dbs]$ grep name initjulia.ora

*.db_name='julia'

*.instance_name='julia'

在启动过程中,我们看到,在mount阶段,数据库会对参数文件和控制文件进行比较,如果两者记录的db_name不一致,则数据库无法启动:

SQL> startup nomount;

ORACLE instance started.

SQL> alter database mount;

alter database mount

*

ERROR at line 1:

ORA-01103:databasename 'EYGLE' in controlfile isnot 'JULIA' 

关于db_name在文件头上的存储,可以通过很多方式来读取,以下通过Oracle9i中随软件提供的BBED可以最为直观的观察和理解(这一工具在Windows平台上,Oracle9i之后不再提供):

D:\oracle\9.2.0\bin>bbed

口令:blockedit

BBED: Release 2.0.0.0.0 - Limited Production on 星期二 8月 31 22:23:27 2010

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

************* !!! For Oracle Internal Use only !!! ***************

BBED> set filename 'D:\oracle\oradata\EYGLEE\DATAFILE\O1_MF_SYSTEM_60VQT1WW_.DBF'

FILENAME D:\oracle\oradata\EYGLEE\DATAFILE\O1_MF_SYSTEM_60VQT1WW_.DBF

BBED> set blocksize 8192

BLOCKSIZE 8192

BBED> setblock2

BLOCK# 2

进行了如上设置之后,我们可以检查文件头的结构信息,KCVFH是文件头信息的结构体:

BBED> p kcvfh

struct kcvfh, 360 bytes @0

struct kcvfhbfh, 20 bytes @0

ub 1 type_kcbh @0 0x0b

ub 1 frmt_kcbh @1 0xa2

ub 1 spare1_kcbh @2 0x00

ub 1 spare2_kcbh @3 0x00

ub 4 rdba_kcbh @4 0x00400001

ub 4 bas_kcbh @8 0x00000000

ub 2 wrp_kcbh @12 0x0000

ub 1 seq_kcbh @14 0x01

ub 1 flg_kcbh @15 0x04 (KCBHFCKV)

ub 2 chkval_kcbh @16 0xa837

ub 2 spare3_kcbh @18 0x0000

struct kcvfhhdr, 76 bytes @20

ub 4 kccfhswv @20 0x00000000

ub 4 kccfhcvn @24 0x0b200000

ub 4 kccfhdbi @28 0xea51005a

  text kccfhdbn[0]   @32 E 

text kccfhdbn[1]   @33 Y 

text kccfhdbn[2]   @34 G 

text kccfhdbn[3]   @35 L 

text kccfhdbn[4]   @36 E 

text kccfhdbn[5]   @37 E 

text kccfhdbn[6]   @38 

text kccfhdbn[7]   @39 

ub 4 kccfhcsq @40 0x0000064a

ub 4 kccfhfsz @44 0x00015400

s_blkz kccfhbsz @48 0x00

在以上输出中,kccfhdbn就是db_name的保留空间,共保留了8位,也正因为如此,数据库的db_name不能超过8个字符。又因为每个文件头上的实体存储,修改db_name的动作会较为复杂,一个名为NID的小工具可以用来更改数据库名称:

E:\>nid -help

DBNEWID: Release 11.2.0.2.0 - Production on 星期日 1月 23 19:52:01 2011

Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.

关键字 说明 (默认值)

----------------------------------------------------

TARGET 用户名/口令 (无)

DBNAME 新的数据库名 (无)

LOGFILE 输出日志 (无)

REVERT 还原失败的更改 否

SETNAME 仅设置新的数据库名 否

APPEND 附加至输出日志 否

HELP 显示这些消息 否

最后总结一下,一个实例(instance_name)可以mount并打开任何数据库(db_name),但是同一时间一个实例只能打开一个数据库;一个数据库(db_name)同一时间可以为任一实例(instance_name)所打开,但是在非RAC情况下,同一时间只能被同一个实例所打开。

 

1.3.9 sql.bsq文件与数据库创建

在CREATE DATABASE的过程中,Oracle 会调用$ORACLE_HOME/rdbms/admin/sql.bsq脚本,用于创建数据字典,这是非常重要的一个脚本,其中存储了数据字典的创建语句及注释说明。当我们对某些数据字典存在兴趣时,可以通过检查这个文件得到更为详细的信息,例如,对于控制数据库启动的bootstrap$表,其创建语句就可以从这个文件中找到:

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 */

提示:sql.bsq文件值得每个接触Oracle数据的人,认真阅读理解。

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> startupnomount;

ORACLE instance started.

SQL>@CreateDB.sql

CREATE DATABASE eygle

*

ERROR at line 1:

ORA-01092: ORACLE instance terminated. Disconnection forced

此时警告日志(alert_<oracle_sid>.log)中会记录如下信息:

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 inopening 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文件在数据库创建过程中的作用。知道了这个内容之后,我们甚至可以通过手工修改sql.bsq文件来更改数据库字典对象参数,从而实现特殊要求数据库的创建或测试自定义库,也可以通过修改_init_sql_file参数来重定位sql.bsq文件的位置(但是通常这些是不建议变更的)。

sql.bsq文件中包含的数据库核心信息非常重要,在很多时候,这个文件可以帮助我们解答很多技术疑惑。

注意:在Oracle 11g中,sql.bsq文件的内容被分散隔离为多个文件。

 

1.3.10 数据文件及字典的创建

再来看CreateDBFiles.sql文件:

C:\Oracle\admin\eygle\scripts>type CreateDBFiles.sql

connect "SYS"/"&&sysPassword" as SYSDBA

set echo on

spool C:\oracle\admin\eygle\scripts\CreateDBFiles.log

CREATE SMALLFILE TABLESPACE "USERS" LOGGING DATAFILE SIZE 5M AUTOEXTEND ON NEXT 1280K MAXSIZE UNLIMITED EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO;

ALTERDATABASEDEFAULTTABLESPACE "USERS"; 

spool off

这个文件向数据库中追加了USERS表空间,并将该表空间设置为系统缺省的数据表空间,注意最后一句:

ALTER DATABASE DEFAULT TABLESPACE "USERS";

这是Oracle 10g增加的新特性,在Oracle 10g之前,如果创建用户不指定缺省的数据表空间,那么用户的缺省表空间会被指向系统表空间,增加了数据库缺省数据表空间后,如果不指定,那么创建用户的缺省数据表空间会被指向这里:

SQL> create user julia identified by eygle;

用户已创建。

SQL> select username,default_tablespace from dba_users

2 where username='JULIA';

USERNAME DEFAULT_TABLESPACE

------------------------------ ------------------------------

JULIA USERS

作为一个数据库属性,这个信息也可以从字典表props$中查询得到:

SQL> select name,value$ from props$

2 where name='DEFAULT_PERMANENT_TABLESPACE';

NAME VALUE$

------------------------------ ------------------

DEFAULT_PERMANENT_TABLESPACE USERS

继续前面的讨论,接下来Oracle通过CreateDBCatalog.sql创建数据字典:

C:\Oracle\admin\eygle\scripts>cat CreateDBCatalog.sql

connect "SYS"/"&&sysPassword" as SYSDBA

set echo on

spool C:\oracle\admin\eygle\scripts\CreateDBCatalog.log

@C:\oracle\10.2.0\rdbms\admin\catalog.sql;

@C:\oracle\10.2.0\rdbms\admin\catblock.sql;

@C:\oracle\10.2.0\rdbms\admin\catproc.sql;

@C:\oracle\10.2.0\rdbms\admin\catoctk.sql;

@C:\oracle\10.2.0\rdbms\admin\owminst.plb;

connect "SYSTEM"/"&&systemPassword"

@C:\oracle\10.2.0\sqlplus\admin\pupbld.sql;

connect "SYSTEM"/"&&systemPassword"

set echo on

spool C:\oracle\admin\eygle\scripts\sqlPlusHelp.log

@C:\oracle\10.2.0\sqlplus\admin\help\hlpbld.sql helpus.sql;

spool off

这个文件依次调用Oracle的字典创建文件等。

emRepository.sql文件是用于创建EM档案库的:

C:\Oracle\admin\eygle\scripts>type emRepository.sql

connect "SYS"/"&&sysPassword" as SYSDBA

set echo off

spool C:\oracle\admin\eygle\scripts\emRepository.log

@C:\oracle\10.2.0\sysman\admin\emdrep\sql\emreposcre C:\oracle\10.2.0 SYSMAN &&sysmanPassword TEMP ON;

WHENEVER SQLERROR CONTINUE;

spool off

最后一个执行的文件是postDBCreation.sql:

C:\Oracle\admin\eygle\scripts>cat postDBCreation.sql

connect "SYS"/"&&sysPassword" as SYSDBA

set echo on

spool C:\oracle\admin\eygle\scripts\postDBCreation.log

connect "SYS"/"&&sysPassword" as SYSDBA

set echo on

create spfile='C:\oracle\10.2.0\database\spfileeygle.ora'  FROMpfile='C:\oracle\admin\eygle\scripts\init.ora'; 

shutdown immediate;

connect "SYS"/"&&sysPassword" as SYSDBA

startup ;

alter user SYSMAN identified by "&&sysmanPassword" account unlock;

alter user DBSNMP identified by "&&dbsnmpPassword" account unlock;

select 'utl_recomp_begin: ' || to_char(sysdate, 'HH:MI:SS') from dual;

execute utl_recomp.recomp_serial();

select 'utl_recomp_end: ' || to_char(sysdate, 'HH:MI:SS') from dual;

hostC:\oracle\10.2.0\bin\emca.bat -configdbcontroldb -silent -DB_UNIQUE_NAME eygle 

-PORT1521 -EM_HOMEC:\oracle\10.2.0 -LISTENER LISTENER -SERVICE_NAME eygle 

-SYS_PWD&&sysPassword -SID eygle -ORACLE_HOMEC:\oracle\10.2.0 

-DBSNMP_PWD&&dbsnmpPassword -HOSTgqgai -LISTENER_OHC:\oracle\10.2.0 

-LOG_FILEC:\oracle\admin\eygle\scripts\emConfig.log -SYSMAN_PWD&&sysmanPassword; 

spool C:\oracle\admin\eygle\scripts\postDBCreation.log

exit;

在创建过程中,需要经历以下几个步骤后,数据库的创建才算正式完成:

(1)Oracle首先通过参数文件创建了spfile文件;

(2)解锁两个账号;

(3)编译;

(4)配置EM。

 

1.4 使用模板创建数据库

前面提到,除了定制数据库之外,还可以使用模板来创建数据库,接下来就让我们一起来了解一下使用模板创建数据库的过程。

 

1.4.1 启动创建

在1.1节中,我们提到可以通过命令行启动DBCA工具,可能更多的朋友是通过“开始”菜单中Oracle创建的快捷菜单来启动DBCA的,如图1-25所示,右图则是快捷方式的具体指向。

图1-25 DBCA及其快捷方式

注意到这个快捷项的目标执行的是以下命令:

C:\Oracle\10.2.0\BIN\launch.exe C:\oracle\10.2.0\assistants\dbca dbca.cl

此处的dbca.cl文件和前面的dbca.bat批处理文件执行的功能是一致的:

Command=("C:\oracle\10.2.0\jdk\jre\BIN\JAVA" -Dsun.java2d.font.DisableAlgorithmicStyles=true

-DORACLE_HOME="C:\oracle\10.2.0" -DJDBC_PROTOCOL=thin

-mx128m –classpath …..OraInstaller.jar" oracle.sysman.assistants.dbca.Dbca)

那么DBCA为什么指向这个目录呢?这个目录又是做什么用的呢?

实际上这个目录是Oracle的缺省模板目录,当使用模板来创建数据库时,就用到了这个目录下的文件。

 

1.4.2 数据库创建模板

下面来看一下使用模板创建数据库的过程。

使用模板和前面的过程主要不同之处在于第二个步骤,在这里选择“定制数据库”之外的选项,就都使用了模板,并且包含了数据文件(eygle模板是我们之前保存的),如图1-26左图所示;使用模板创建数据库通常速度都会很快,原因就在于数据文件是从种子数据库中恢复出来的,而不需要创建文件及字典对象等信息,右图展示创建过程的第一个步骤就是“复制数据库文件”。

这里通过脚本说明一下通过模板创建数据库和定制数据库的不同。

首先eygle.sql脚本记录如下内容:

……

host C:\oracle\10.2.0\bin\orapwd.exe

file=C:\oracle\10.2.0\database\PWDeygle.ora password=&&sysPassword force=y

@C:\oracle\admin\eygle\scripts\CloneRmanRestore.sql

@C:\oracle\admin\eygle\scripts\cloneDBCreation.sql

@C:\oracle\admin\eygle\scripts\postScripts.sql

host "echo SPFILE='C:\oracle\10.2.0/dbs/spfileeygle.ora'

> C:\oracle\10.2.0\database\initeygle.ora"

@C:\oracle\admin\eygle\scripts\postDBCreation.sql

图1-26 选择模板

该脚本首先调用的是CloneRmanRestore.sql脚本,该脚本记录如下内容:

C:\Oracle\admin\eygle\scripts>type CloneRmanRestore.sql

connect "SYS"/"&&sysPassword" as SYSDBA

set echo on

spool C:\oracle\admin\eygle\scripts\CloneRmanRestore.log

startupnomountpfile="C:\oracle\admin\eygle\scripts\init.ora"; 

@C:\oracle\admin\eygle\scripts\rmanRestoreDatafiles.sql; 

这个脚本首先启动实例到Nomount模式,然后调用rmanRestoreDatafiles.sql来恢复文件。

 

1.4.3 rman的引入

rmanRestoreDatafiles.sql 脚本是通过系统包 dbms_backup_restore 来恢复备份集中的文件,从而实现数据恢复,其主要内容如下:

set echo off;

set serveroutput on;

select TO_CHAR(systimestamp,'YYYYMMDD HH:MI:SS') from dual;

variable devicename varchar2(255);

declare

omfname varchar2(512) := NULL;

done boolean;

begin

dbms_output.put_line(' ');

dbms_output.put_line(' Allocating device.... ');

dbms_output.put_line(' Specifying datafiles... ');

:devicename := dbms_backup_restore.deviceAllocate;

dbms_output.put_line(' Specifing datafiles... ');

dbms_backup_restore.restoreSetDataFile; 

dbms_backup_restore.restoreDataFileTo(1,

'C:\oracle\oradata\eygle\SYSTEM01.DBF', 0, 'SYSTEM');

dbms_backup_restore.restoreDataFileTo(2,

'C:\oracle\oradata\eygle\UNDOTBS01.DBF', 0, 'UNDOTBS1');

dbms_backup_restore.restoreDataFileTo(3,

'C:\oracle\oradata\eygle\SYSAUX01.DBF', 0, 'SYSAUX');

dbms_backup_restore.restoreDataFileTo(4,

'C:\oracle\oradata\eygle\USERS01.DBF', 0, 'USERS');

dbms_output.put_line(' Restoring ... ');

dbms_backup_restore.restoreBackupPiece(

'C:\oracle\10.2.0\assistants\dbca\templates\Seed_Database.dfb', done); --种子数据库

if done then

dbms_output.put_line(' Restore done.');

else

dbms_output.put_line(' ORA-XXXX: Restore failed ');

end if;

dbms_backup_restore.deviceDeallocate;

end;

/

select TO_CHAR(systimestamp,'YYYYMMDD HH:MI:SS') from dual;

关于 RMAN 的有关知识,我们会在后面的章节详细介绍,但是关于 dbms_backup_restore包这里有必要提前介绍一下。

当通过 RMAN 进行数据库备份时,RMAN 会将多个数据文件写出到一个或多个备份文件(称为备份集)中,RMAN的相关备份信息或者存储在控制文件中,或者存储在RMAN的专用目录数据库(Catalog)中,如果 RMAN 的备份信息丢失,那么通常备份集中的文件是没有办法读取出来的,其他工具无法识别RMAN的备份集文件;而dbms_backup_restore就是针对这种情况提供的一种解决方案,dbms_backup_restore可以在数据库nomount状态下调用,直接从备份集中读取数据文件,功能十分强大。

DBMS_BACKUP_RESTORE包由dbmsbkrs.sql和prvtbkrs.plb这两个脚本创建,创建数据库时执行的 catproc.sql 脚本会调用这两个脚本以创建包,这些脚本文件可以在$ORACLE_HOME/rdbms/admin目录下找到,脚本文件中对包的内容有详细的介绍。

下面通过具体的例子来介绍一下这个工具的用法,以下是一次真实的恢复案例,由于控制文件丢失,只能通过 DBMS_BACKUP_RESTORE 包从备份集中恢复数据文件,当然恢复之前我们需要知道一些数据库的相关信息,了解备份集中包含了哪些文件。

首先启动数据库到nomount状态:

[oracle@jumper conner]$ sqlplus "/ as sysdba"

Connected to an idle instance.

SQL> startup nomount;

ORACLE instance started.

然后可以执行脚本,将数据文件恢复到指定目录:

SQL> DECLARE

2 devtype varchar2(256);

3 done boolean;

4 BEGIN

5 devtype:=sys.dbms_backup_restore.deviceAllocate (type=>'',ident=>'t1');

6 sys.dbms_backup_restore.restoreSetDatafile;

7 sys.dbms_backup_restore.restoreDatafileTo(dfnumber=>01,

toname=>'/opt/oracle/oradata/conner/system01.dbf');

8 sys.dbms_backup_restore.restoreDatafileTo(dfnumber=>02,

toname=>'/opt/oracle/oradata/conner/undotbs01.dbf');

9 sys.dbms_backup_restore.restoreDatafileTo(dfnumber=>03,

toname=>'/opt/oracle/oradata/conner/users01.dbf');

10 sys.dbms_backup_restore.restoreBackupPiece(done=>done,

handle=>'/opt/oracle/product/9.2.0/dbs/0ggmiabq_1_1', params=>null);

11 sys.dbms_backup_restore.deviceDeallocate;

12 END;

13 /

PL/SQL procedure successfully completed.

至此,从备份集中读取文件完毕,但是由于没有控制文件,就需要重建一个控制文件用于恢复,创建控制文件的脚本可以自己根据经验编写,也可以根据备份的文本进行修改,当然也可以从其他数据库中转储一个控制文件脚本,仿照改写。

正常情况下,可以通过如下的命令将控制文件的创建语句转储到跟踪文件中(位于udump目录中):

SQL> alterdatabasebackup controlfile to trace;

Database altered.

可以找到trace文件,编辑、执行重建控制文件的需要部分:

SQL> startup nomount;

ORACLE instance started.

SQL> set echo on

SQL> @ctl.sql

SQL> CREATE CONTROLFILE REUSE DATABASE "CONNER" RESETLOGS ARCHIVELOG

2 -- SET STANDBY TO MAXIMIZE PERFORMANCE

3 MAXLOGFILES 5

4 MAXLOGMEMBERS 3

5 MAXDATAFILES 100

6 MAXINSTANCES 1

7 MAXLOGHISTORY 1361

8 LOGFILE

9 GROUP 1 '/opt/oracle/oradata/conner/redo01.log' SIZE 10M,

10 GROUP 2 '/opt/oracle/oradata/conner/redo02.log' SIZE 10M,

11 GROUP 3 '/opt/oracle/oradata/conner/redo03.log' SIZE 10M

12 -- STANDBY LOGFILE

13 DATAFILE

14 '/opt/oracle/oradata/conner/system01.dbf',

15 '/opt/oracle/oradata/conner/undotbs01.dbf',

16 '/opt/oracle/oradata/conner/users01.dbf'

17 CHARACTER SET ZHS16GBK

18 ;

Control file created.

如果存在部分归档日志,创建控制文件之后可以执行恢复:

SQL> recoverdatabaseusingbackup controlfileuntil cancel; 

ORA-00279: change 240560269 generated at 06/09/2005 17:33:48 needed for thread 1

ORA-00289: suggestion : /oradata/conner/archive/1_7.dbf

ORA-00280: change 240560269 for thread 1 is in sequence #7

Specify log: {=suggested | filename | AUTO | CANCEL}

AUTO 

ORA-00279: change 240600632 generated at 06/10/2005 10:42:26 needed for thread 1

ORA-00289: suggestion : /oradata/conner/archive/1_8.dbf

ORA-00280: change 240600632 for thread 1 is in sequence #8

ORA-00278: log file '/oradata/conner/archive/1_7.dbf' no longer needed for this recovery

Specify log: {=suggested | filename | AUTO | CANCEL}

AUTO 

ORA-00279: change 240620884 generated at 06/10/2005 10:45:42 needed for thread 1

ORA-00289: suggestion : /oradata/conner/archive/1_9.dbf

ORA-00280: change 240620884 for thread 1 is in sequence #9

ORA-00278: log file '/oradata/conner/archive/1_8.dbf' no longer needed for this recovery

ORA-00283: recovery session canceled due to errors

ORA-00600: internal error code, arguments: [3020], [4242465], [1], [9], [314], [272], [], []

ORA-10567: Redo is inconsistent with data block (file# 1, block# 48161)

ORA-10564: tablespace SYSTEM

ORA-01110: data file 1: '/opt/oracle/oradata/conner/system01.dbf'

ORA-10560: block type 'DATA SEGMENT HEADER - UNLIMITED'

ORA-01112: media recovery not started

SQL> recoverdatabaseusingbackup controlfileuntil cancel;

ORA-00279: change 240620949 generated at 06/10/2005 10:45:44 needed for thread 1

ORA-00289: suggestion : /oradata/conner/archive/1_9.dbf

ORA-00280: change 240620949 for thread 1 is in sequence #9

Specify log: {=suggested | filename | AUTO | CANCEL}

cancel 

Media recovery cancelled.

恢复到最后可用日志后,通过resetlogs方式打开数据库:

SQL> alter database open resetlogs;

Database altered.

SQL> select name from v$datafile;

NAME

------------------------------------------------------------

/opt/oracle/oradata/conner/system01.dbf

/opt/oracle/oradata/conner/undotbs01.dbf

/opt/oracle/oradata/conner/users01.dbf

至此恢复完成。这是一次常规恢复,dbms_backup_restore的功能远不止于此,还可以通过该包恢复备份集中的控制文件、归档日志等文件。

继续前面的讨论,rmanRestoreDatafiles.sql 脚本通过 dbms_backup_restore 包从种子文件Seed_Database.dfb 恢复出数据文件,来看一下模板目录中存放的模板和种子数据库(自定义的模板也存放在这个目录中):

C:\Oracle\admin\eygle\scripts>dir C:\oracle\10.2.0\assistants\dbca\templates

2005-08-30 17:31 5,893 Data_Warehouse.dbc

2005-09-07 13:02 983,040 example.dmp

2005-09-07 13:02 20,897,792 example01.dfb

2005-08-30 17:31 5,770 General_Purpose.dbc

2005-05-16 15:49 12,411 New_Database.dbt

2005-09-07 13:02  7,061,504Seed_Database.ctl 

2005-09-07 13:02  95,543,296Seed_Database.dfb 

2005-08-30 17:31 5,829 Transaction_Processing.dbc

Seed_Database.dfb文件就是包含种子文件的一个备份集。

 

1.4.4 克隆数据库

数据文件具备了,接下来是通过这些文件“克隆”一个数据库,这个工作由cloneDBCreation.sql脚本继续执行,这个脚本更为复杂,下面分开介绍一下。

首先根据指定的数据库名称(测试数据库指定的名称为eygle)创建一个控制文件:

connect "SYS"/"&&sysPassword" as SYSDBA

set echo on

spool C:\oracle\admin\eygle\scripts\cloneDBCreation.log

Create controlfile reuse setdatabase "eygle" 

MAXINSTANCES 8 MAXLOGHISTORY 1 MAXLOGFILES 16 MAXLOGMEMBERS 3 MAXDATAFILES 100

Datafile

'C:\oracle\oradata\eygle\SYSTEM01.DBF',

'C:\oracle\oradata\eygle\UNDOTBS01.DBF',

'C:\oracle\oradata\eygle\SYSAUX01.DBF',

'C:\oracle\oradata\eygle\USERS01.DBF'

LOGFILE GROUP 1 ('C:\oracle/oradata/eygle/redo01.log') SIZE 51200K,

GROUP 2 ('C:\oracle/oradata/eygle/redo02.log') SIZE 51200K,

GROUP 3 ('C:\oracle/oradata/eygle/redo03.log') SIZE 51200K RESETLOGS;

然后通过dbms_backup_restore包清空dbid等信息:

exec dbms_backup_restore.zerodbid(0);

看到这里再次使用到了dbms_backup_restore包,zeroDbid是包中的一个过程,用于清空数据文件头的部分信息,新的dbid在之后的控制文件创建时可以被计算,对于数据库克隆,这是必须的。

zeroDbid有一个输入参数,即文件号:

PROCEDURE zeroDbid(fno IN binary_integer);

当fno==0时,控制文件中包含的所有数据文件头都将被清零,zeroDbid主要用于清除数据文件头的3类信息:Database id信息、Checksum信息和Checksum符号位信息。

继续看这个脚本,清零完成之后,数据库重新启动,控制文件被重新创建,此时新的dbid被计算并最终写入所有数据文件:

shutdown immediate;

startup nomount pfile="C:\oracle\admin\eygle\scripts\initeygleTemp.ora";

Create controlfile reuse set database "eygle"

MAXINSTANCES 8 MAXLOGHISTORY 1 MAXLOGFILES 16 MAXLOGMEMBERS 3 MAXDATAFILES 100

Datafile

'C:\oracle\oradata\eygle\SYSTEM01.DBF',

'C:\oracle\oradata\eygle\UNDOTBS01.DBF',

'C:\oracle\oradata\eygle\SYSAUX01.DBF',

'C:\oracle\oradata\eygle\USERS01.DBF'

LOGFILE GROUP 1 ('C:\oracle/oradata/eygle/redo01.log') SIZE 51200K,

GROUP 2 ('C:\oracle/oradata/eygle/redo02.log') SIZE 51200K,

GROUP 3 ('C:\oracle/oradata/eygle/redo03.log') SIZE 51200K RESETLOGS;

注意,在启动数据库时 Oracle 使用了一个临时的参数文件 initeygleTemp.ora,在这个参数文件的最后一行设置了一个内部参数:

C:\Oracle\admin\eygle.t\scripts>tail -1 initeygleTemp.ora

_no_recovery_through_resetlogs=true 

_no_recovery_through_resetlogs这个参数的作用是什么呢?可以从数据库中找到一点说明:

SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ

2 FROM SYS.x$ksppi x, SYS.x$ksppcv y

3 WHERE x.inst_id = USERENV ('Instance')

4 AND y.inst_id = USERENV ('Instance')

5 AND x.indx = y.indx AND x.ksppinm LIKE '%&par%';

Enter value for par: no_reco

NAME VALUE DESCRIB

------------------------------ ----- ----------------------------------------------

_no_recovery_through_resetlogs FALSE no recovery through this resetlogs operation

这个参数用于限制恢复能否跨越resetlogs,对于数据库的恢复来说,resetlogs通常意味着不完全恢复,在数据库resetlogs打开之后,控制文件中的很多信息被改写,在Oracle 10g之前,如果数据库resetlogs打开,那么将不再能够通过当前的控制文件再次进行resetlogs点之前的恢复,而Oracle 10g改变了这个历史。

在Oracle 10g 中,即使通过resetlogs 方式打开了数据库,Oracle 仍然支持再次从resetlogs时间点之前进行恢复;在Clone数据库时,Oracle设置这个参数为True,意思就是不允许再次进行跨越resetlogs时间点的恢复。关于这部分内容,我们将在后面章节进行更为详细的介绍。

继续解读这个脚本,接下来Oracle设置restricted session模式,resetlogs打开数据库:

alter system enable restricted session;

alter database "eygle" open resetlogs;

修改global_name,添加临时文件等:

alter database rename global_name to "eygle";

ALTER TABLESPACE TEMP ADD TEMPFILE  'C:\oracle\oradata\eygle\TEMP01.DBF' SIZE 20480K REUSE AUTOEXTEND ON NEXT 640K MAXSIZE UNLIMITED;

select tablespace_name from dba_tablespaces where tablespace_name='USERS';

select sid, program, serial#, username from v$session;

由于种子数据库的字符集通常与用户要求的不符,接下来Oracle通过内部操作强制更改了字符集、国家字符集(这个内容在后面的章节中有详细的介绍):

alterdatabase character set INTERNAL_CONVERTZHS16GBK; 

alterdatabasenational character set INTERNAL_CONVERTAL16UTF16; 

最后修改用户口令,禁用restricted session模式,这个克隆过程执行完毕:

alter user sys identified by "&&sysPassword";

alter user system identified by "&&systemPassword";

alter system disable restricted session;

至此,种子数据库已经按照用户的意图脱胎换骨得以重生。

 

1.4.5 传输表空间技术

在很多Oracle文档中,可能大家都注意过Oracle用来进行测试的一个表空间,这个表空间中有一系列预置的用户和数据,可以用于数据库或BI的很多测试实验。

这个表空间在使用模板建库时是可以选择的,在如图1-27所示的这个界面中,可以选择建库时包含这个范例表空间(缺省是未选择的)。

如果选择了包含示例方案,则cloneDBCreation.sql脚本将会有所改变,主要增加了如下语句:

connect "SYS"/"&&sysPassword" as SYSDBA

@C:\oracle\10.2.0\demo\schema\mkplug.sql&&sysPassword change_on_install change_on_install 

change_on_install change_on_install change_on_install change_on_install

C:\oracle\10.2.0\assistants\dbca\templates\example.dmp

C:\oracle\10.2.0\assistants\dbca\templates\example01.dfb

C:\oracle\oradata\eygle\example01.dbf C:\oracle\admin\eygle\scripts\ "'SYS/&&sysPassword as SYSDBA'";

图1-27 是否包含示例方案

看到这里,再次引用了模板目录中的文件:

C:\>dir C:\oracle\10.2.0\assistants\dbca\templates\ex*

2005-09-07 13:02  983,040 example.dmp 

2005-09-07 13:02  20,897,792 example01.dfb 

通过mkplug.sql脚本来加载这个范例表空间,来看一下这个脚本的主要内容。

同样,最重要的是通过dbms_backup_restore包从example01.dfb文件中恢复数据文件:

SELECT TO_CHAR(systimestamp, 'YYYYMMDD HH:MI:SS') FROM dual;

variable new_datafile varchar2(512)

declare

done boolean;

v_db_create_file_dest VARCHAR2(512);

devicename varchar2(255);

data_file_id number;

rec_id number;

stamp number;

resetlogs_change number;

creation_change number;

checkpoint_change number;

blksize number;

omfname varchar2(512);

real_file_name varchar2(512);

begin

dbms_output.put_line(' ');

dbms_output.put_line(' Allocating device.... ');

dbms_output.put_line(' Specifying datafiles... ');

devicename := dbms_backup_restore.deviceAllocate;

dbms_output.put_line(' Specifing datafiles... ');

SELECT MAX(file_id)+1 INTO data_file_id FROM dba_data_files;

SELECT value INTO v_db_create_file_dest FROM v$parameter WHERE name ='db_create_file_dest';

IF v_db_create_file_dest IS NOT NULL

THEN

dbms_backup_restore.restoreSetDataFile;

dbms_backup_restore.getOMFFileName('EXAMPLE',omfname); 

dbms_backup_restore.restoreDataFileTo(data_file_id, omfname, 0,'EXAMPLE');

ELSE

dbms_backup_restore.restoreSetDataFile;

dbms_backup_restore.restoreDataFileTo(data_file_id,'&data_file_name');

END IF;

dbms_output.put_line(' Restoring ... ');

dbms_backup_restore.restoreBackupPiece('&data_file_backup', done);

SELECT max(recid) INTO rec_id FROM v$datafile_copy;

-- Now get the real file name. It could be also OMF filename

SELECT name, stamp, resetlogs_change#, creation_change#, checkpoint_change#,block_size

INTO real_file_name, stamp,resetlogs_change, creation_change, checkpoint_change, blksize

FROM V$DATAFILE_COPY

WHERE recid = rec_id and file# = data_file_id;

-- Uncatalog the file from V$DATAFILE_COPY. This important.

dbms_backup_restore.deleteDataFileCopy(recid => rec_id,

stamp => stamp,

fname => real_file_name,

dfnumber => data_file_id,

resetlogs_change => resetlogs_change,

creation_change => creation_change,

checkpoint_change => checkpoint_change,

blksize => blksize,

no_delete => 1,

force => 1);

-- Set the bindvariable to the real filename

:new_datafile := real_file_name;

if done then

dbms_output.put_line(' Restore done.');

else

dbms_output.put_line(' ORA-XXXX: Restore failed ');

end if;

end;

/

这个恢复完成之后,接下来最重要的部分就是通过传输表空间技术将 example 表空间导入到当前的数据库。

考虑一下这种情况,当进行跨数据库迁移时,需要将一个用户表空间中的数据迁移到另外一个数据库,应该使用什么样的方法呢?

最常规的做法可能是通过 EXP 工具将数据全部导出,然后在目标数据库上 IMP 导入,可是这种方法可能会比较缓慢。EXP工具同时还提供另外一种技术——可传输表空间技术,可以用于加快这个过程。

在exp-help的帮助中,可以看到这样一个参数:

TRANSPORT_TABLESPACE 导出可传输的表空间元数据 (N)

通过这个选项,我们可以对一组自包含、只读的表空间只导出元数据,然后在操作系统层将这些表空间的数据文件拷贝至目标平台,并将元数据导入数据字典(这个过程称为插入,plugging),即完成迁移。但是注意,传输表空间技术不能应用于SYSTEM表空间或SYS用户拥有的对象。

对于可传输表空间有一个重要概念:自包含(Self-Contained)。

在表空间传输中,要求表空间集为自包含的,自包含表示用于传输的内部表空间集没有引用指向外部表空间集。自包含分为两种:一般自包含表空间集和完全(严格)自包含表空间集。

常见的以下情况是违反自包含原则的。

索引在内部表空间集,而表在外部表空间集(相反地,如果表在内部表空间集,而索引在外部表空间集,则不违反自包含原则)。

分区表一部分区在内部表空间集,一部分在外部表空间集(对于分区表,要么全部包含在内部表空间集中,要么全不包含)。

如果在传输表空间时同时传输约束,则对于引用完整性约束,约束指向的表在外部表空间集,则违反自包含约束;如果不传输约束,则与约束指向无关。

表在内部表空间集,而lob列在外部表空间集,则违反自包含约束。

通常可以通过系统包 DBMS_TTS 来检查表空间是否自包含,验证可以以两种方式执行:非严格方式和严格方式。

以下是一个简单的验证过程,假定在eygle表空间存在一个表eygle,其上存在索引存储在USERS表空间:

SQL> create table eygle as select rownum id ,username from dba_users;

SQL> create index ind_id on eygle(id) tablespace users;

以SYS用户执行非严格自包含检查(full_check=false):

SQL> connect / as sysdba

SQL> exec dbms_tts.transport_set_check('EYGLE', TRUE);

PL/SQL procedure successfully completed.

SQL> SELECT * FROM TRANSPORT_SET_VIOLATIONS;

no rows selected 

执行严格自包含检查(full_check=true):

SQL> exec dbms_tts.transport_set_check('EYGLE', TRUE, True);

PL/SQL procedure successfully completed.

SQL> SELECT * FROM TRANSPORT_SET_VIOLATIONS;

VIOLATIONS

--------------------------------------------------------------------------------------

Index EYGLE.IND_ID in tablespace USERS points to table EYGLE.EYGLE in tablespace EYGLE

反过来对于USERS表空间来说,非严格检查也是无法通过的:

SQL> exec dbms_tts.transport_set_check('USERS', TRUE);

PL/SQL procedure successfully completed.

SQL> SELECT * FROM TRANSPORT_SET_VIOLATIONS;

VIOLATIONS

----------------------------------------------------------------------------------------

Index EYGLE.IND_ID in tablespace USERS points to table EYGLE.EYGLE in tablespace EYGLE

但是,可以对多个表空间同时传输,则一些自包含问题就可以得到解决:

SQL> exec dbms_tts.transport_set_check('USERS,EYGLE', TRUE, True);

PL/SQL procedure successfully completed.

SQL> SELECT * FROM TRANSPORT_SET_VIOLATIONS;

no rows selected

表空间自包含确认之后,进行表空间传输就很方便了,一般包含如下几个步骤。

(1)将表空间设置为只读。

alter tablespace users read only;

(2)导出表空间。在操作系统提示符下执行:

exp username/passwd tablespaces=users transport_tablespace=y file=exp_users.dmp

此处的导出文件只包含元数据,所以导出文件很小,导出速度也会很快。

(3)转移。将导出的元数据文件(此处是exp_users.dmp)和传输表空间的数据文件(此处是users表空间的数据文件user01.dbf)转移至目标主机(转移过程如果使用FTP方式,应该注意使用二进制方式)。

(4)传输。在目标数据库将表空间插入到数据库中,完成表空间传输。在操作系统命令提示符下执行以下语句:

imp  username/passwd   tablespaces=users   transport_tablespace=y   file=exp_users.dmp datafiles='users01.dbf'

了解了Oracle的可传输表空间技术后,来看一下example表空间的插入,以下脚本仍然来自mkplug.sql脚本:

--

-- Importing the metadata and plugging in the tablespace at the same

-- time, using the restored database file

--

DEFINE imp_logfile = &log_path.tts_example_imp.log

-- When importing use filename got after restore is finished

host imp "'sys/&&password_sys AS SYSDBA'" transport_tablespace=y file=&imp_file log=&imp_logfile datafiles='&datafile' tablespaces=EXAMPLE tts_owners=hr,oe,pm,ix,sh

完成plugging之后,这个表空间就被包含在了新建的数据库之中。

 

1.4.6 跨平台表空间传输

需要注意的是,在Oracle 10g 之前,数据文件是不能够跨平台传输使用的,从Oracle 10g开始,Oracle支持跨平台的表空间传输,这极大地增强了数据迁移的便利性。

1.字节顺序和平台

数据文件所以不能跨平台,主要是由于不同平台的字节顺序不同,这是计算机领域由来已久的问题之一,在各种计算机体系结构中,由于对于字、字节等的存储机制有所不同,通信双方交流的信息单元(比特、字节、字、双字等)应该以什么样的顺序进行传送就成了一个问题,如果不达成一致的规则,通信双方将无法进行正确的编/译码从而导致通信失败。

目前在各种体系的计算机中通常采用的字节存储机制主要有两种:Big-Endian和Little-Endian。

一些操作系统(包括Windows)在低位内存地址中存放二进制数据的最低有效字节,因此这种系统被称为Little Endian;一些操作系统(包括Solaris)将最高有效字节存储在低位内存地址中,因此这种系统被称为Big Endian。

举一个简单点的例子,假如1122这样一个数据要存入不同系统,对于Little Endian的系统,存储的顺序就是2211,小头在前;而对于Big Endian的系统来说,存储顺序就是1122,大头在前,显然BigEndian更符合我们通常的语言习惯。

那么跨平台的问题就出现了,当一个Little Endian的系统试图从一个Big Endian的系统中读取数据时,就需要通过转换,否则不同的字节顺序将导致数据不能被正确读取。

说明:据考证,Endian这个词来源于Jonathan Swift在1726年写的讽刺小说《Gulliver's Travels》(《格利佛游记》)。该小说在描述 Gulliver 畅游小人国时碰到了如下的一个场景。在小人国里的小人因为非常小(身高 6 英寸)所以总是碰到一些意想不到的问题。有一次因为对水煮蛋该从大的一端(Big-End)剥开还是小的一端(Little-End)剥开的争论而引发了一场战争,并形成了两支截然对立的队伍:支持从 Big-End 剥开的人 Swift 就称作Big-Endians,而支持从Little-End剥开的人就称作Little-Endians(后缀ian表明的就是支持某种观点的人)。Endian这个词由此而来。

清楚了这个问题,接下来就可以来看看Oracle是如何处理这种情况的。

2.源平台和目标平台

首先在迁移之前,需要确认一下源平台和目标平台的平台信息,这些信息可以通过视图v$transportable_platform和v$database视图联合查询得到。

以下是源平台的信息:

SQL> col PLATFORM_NAME for a30

SQL> SELECT d.platform_name, endian_format

2 FROM v$transportable_platform tp, v$database d

3 WHERE tp.platform_name = d.platform_name;

PLATFORM_NAME ENDIAN_FORMAT

------------------------------ --------------

Solaris[tm] OE (64-bit) Big

查询目标数据库平台信息:

SQL> col platform_name for a40

SQL> SELECT d.platform_name, endian_format

2 FROM v$transportable_platform tp, v$database d

3 WHERE tp.platform_name = d.platform_name;

PLATFORM_NAME ENDIAN_FORMAT

---------------------------------------- --------------

Microsoft Windows IA (32-bit) Little

看到Windows平台和Solaris平台的字节顺序是不同的,Windows平台是Little-Endian,而Solaris平台是Big-Endian的。

可以通过数据库查询Oracle10g支持的平台转换:

SQL> col PLATFORM_NAME for a40

SQL> select * from v$transportable_platform;

PLATFORM_ID PLATFORM_NAME ENDIAN_FORMAT

----------- ---------------------------------------- --------------

1 Solaris[tm] OE (32-bit) Big

2 Solaris[tm] OE (64-bit) Big

7 Microsoft Windows IA (32-bit) Little

10 Linux IA (32-bit) Little

6 AIX-Based Systems (64-bit) Big

3 HP-UX (64-bit) Big

5 HP Tru64 UNIX Little

4 HP-UX IA (64-bit) Big

11 Linux IA (64-bit) Little

15 HP Open VMS Little

8 Microsoft Windows IA (64-bit) Little

9 IBM zSeries Based Linux Big

13 Linux 64-bit for AMD Little

16 Apple Mac OS Big

12 Microsoft Windows 64-bit for AMD Little

17 Solaris Operating System (x86) Little

18 IBM Power Based Linux Big

17 rows selected.

3.源平台的导出及转换

接下来开始我们的测试,创建一个独立的自包含表空间,并创建一个测试表:

SQL> create tablespace trans

2 datafile '/data2/ora10g/oradata/mars/trans.dbf' size 10M;

SQL> create user trans identified by trans default tablespace trans;

SQL> grant connect,resource to trans;

SQL> connect trans/trans

SQL> create table test as select * from dict;

SQL> select count(*) from test;

COUNT(*)

----------

617

将表空间设置为只读:

SQL> connect / as sysdba

Connected.

SQL> alter tablespace trans read only;

Tablespace altered.

导出要传输的表空间:

$ exp \'/ as sysdba\' tablespaces=trans transport_tablespace=y file=exp_trans.dmp

Export: Release 10.2.0.1.0 - Production on Thu Mar 22 16:31:15 2007

Copyright (c) 1982, 2005, Oracle. All rights reserved.

Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit Production

With the Partitioning, OLAP and Data Mining options

Export done in ZHS16GBK character set and AL16UTF16 NCHAR character set

Note: tabledata (rows)willnotbe exported 

About to export transportable tablespace metadata...

For tablespace TRANS ...

. exporting cluster definitions

. exporting table definitions

. . exporting table TEST

. exporting referential integrity constraints

. exporting triggers

. end transportable tablespace metadata export

Export terminated successfully without warnings.

使用RMAN的convert命令转换文件格式:

$ rman target /

Recovery Manager: Release 10.2.0.1.0 - Production on Thu Mar 22 16:34:30 2007

Copyright (c) 1982, 2005, Oracle. All rights reserved.

connected to target database: MARS (DBID=1034439893)

RMAN> convert tablespace trans

2> toplatform 'MicrosoftWindows IA (32-bit)'

3> format '/tmp/%N_%f';

Starting backup at 22-MAR-07

using target database control file instead of recovery catalog

allocated channel: ORA_DISK_1

channel ORA_DISK_1: sid=140 devtype=DISK

channel ORA_DISK_1: starting datafile conversion

input datafile fno=00005 name=/data2/ora10g/oradata/mars/trans.dbf

converted datafile=/tmp/TRANS_5

channel ORA_DISK_1: datafile conversion complete, elapsed time: 00:00:01

Finished backup at 22-MAR-07

确认导出文件已生成:

$ ls -l /tmp/TRANS*

-rw-r----- 1 oracle dba 10493952 Mar 22 16:37 /tmp/TRANS_5

4.文件传输

通过FTP获得两个文件,注意应该使用二进制方式传输(bin模式):

D:\oradata\EYGLE\DATAFILE>ftp 172.16.33.50

Connected to 172.16.33.50.

220 testdbserver.hurray.com.cn FTP server (SunOS 5.8) ready.

User (172.16.33.50:(none)): gqgai

331 Password required for gqgai.

Password:

230 User gqgai logged in.

ftp> bin

200 Type set to I.

ftp> mget /export/home/oracle/exp_trans.dmp 

200 Type set to I.

mget /export/home/oracle/exp_trans.dmp? y

200 PORT command successful.

150 Binary data connection for /export/home/oracle/exp_trans.dmp (172.16.34.89,5006) (3072 bytes).

226 Binary Transfer complete.

ftp: 收到 3072 字节,用时 0.00Seconds 3072000.00Kbytes/sec.

ftp> mget /tmp/TRANS_5

200 Type set to I.

mget /tmp/TRANS_5? y

200 PORT command successful.

150 Binary data connection for /tmp/TRANS_5 (172.16.34.89,5008) (10493952 bytes).

226 Binary Transfer complete.

ftp: 收到 10493952 字节,用时 1.13Seconds 9270.28Kbytes/sec.

5.目标数据库的导入

在目标数据库中,也可以使用RMAN对备份文件进行转换,以使数据文件具有更规范的名称:

D:\oradata\EYGLE\DATAFILE>rman target /

恢复管理器: Release 10.2.0.1.0 - Production on 星期四 3月 22 17:18:50 2007

Copyright (c) 1982, 2005, Oracle. All rights reserved.

连接到目标数据库: EYGLE (DBID=1417824532)

RMAN> convert datafile 'D:\oradata\EYGLE\DATAFILE\TRANS_5'

2> db_file_name_convert

3> 'D:\oradata\EYGLE\DATAFILE\TRANS_5','D:\oradata\EYGLE\DATAFILE\TRANS01.DBF';

启动 backup 于 22-3月 -07

使用目标数据库控制文件替代恢复目录

分配的通道: ORA_DISK_1

通道 ORA_DISK_1: sid=144 devtype=DISK

通道 ORA_DISK_1: 启动数据文件转换

输出文件名=D:\ORADATA\EYGLE\DATAFILE\TRANS_5

已转换的数据文件 = D:\ORADATA\EYGLE\DATAFILE\TRANS01.DBF

通道 ORA_DISK_1: 数据文件转换完毕, 经过时间: 00:00:08

完成 backup 于 22-3月 -07

然后,需要在目标数据库创建相应的用户:

SQL> create user trans identified by trans;

用户已创建。

SQL> grant connect,resource to trans;

授权成功。

接下来可以执行导入:

D:\oradata\EYGLE\DATAFILE>imp  '/ as sysdba' tablespaces=trans transport_tablespace=yfile=exp_trans.dmpdatafiles=D:\oradata\EYGLE\DATAFILE\TRANS01.DBF

Import: Release 10.2.0.1.0 - Production on 星期四 3月 22 17:34:27 2007

Copyright (c) 1982, 2005, Oracle. All rights reserved.

连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production

With the Partitioning, OLAP and Data Mining options

经由常规路径由 EXPORT:V10.02.01 创建的导出文件

即将导入可传输的表空间元数据...

已经完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的导入

. 正在将 SYS 的对象导入到 SYS

. 正在将 SYS 的对象导入到 SYS

. 正在将 TRANS 的对象导入到 TRANS

. . 正在导入表 "TEST"

. 正在将 SYS 的对象导入到 SYS

成功终止导入, 没有出现警告。

注意:此处也可以在IMP时通过fromuser/touser参数将数据导入其他用户下。

现在这个表空间已经被插入到新的数据库中,并且数据全部传输过来:

SQL> select name from v$datafile where name like ‘%TRANS%’;

NAME

------------------------------------------------------------

D:\ORADATA\EYGLE\DATAFILE\TRANS01.DBF

SQL> select count(*) from trans.test;

COUNT(*)

----------

617

导入后的表空间还处于read only状态,确认后可以更改为读写模式:

SQL> select tablespace_name,status from dba_tablespaces;

TABLESPACE_NAME STATUS

------------------------------ ---------

SYSTEM ONLINE

UNDOTBS1 ONLINE

SYSAUX ONLINE

TEMP ONLINE

USERS ONLINE

EYGLE ONLINE

TRANS READ ONLY

已选择7行。

SQL> alter tablespace trans read write;

表空间已更改。

同样,传输表空间也可以通过数据泵来完成,以下是Oracle10gR1中插入表空间的简单示例:

E:\Oracle\oradata\eygle\dpdata>impdp  eygle/eygle       directory=dpdata transport_datafiles= 'E:\Oracle\oradata\eygle\EYGLE\DATAFILE\TRANS01.DBF' dumpfile=trans.dmp

Import: Release 10.1.0.2.0 - Production on 星期二, 27 4月, 2004 15:03

Copyright (c) 2003, Oracle. All rights reserved.

连接到: Oracle Database 10g Enterprise Edition Release 10.1.0.2.0 - Production

With the Partitioning, OLAP and Data Mining options

已成功加载/卸载了主表 "EYGLE"."SYS_IMPORT_TRANSPORTABLE_01"

启动 "EYGLE"."SYS_IMPORT_TRANSPORTABLE_01": eygle/******** dumpfile=trans.dmp directory=dpdata transport_ datafiles='E:\

Oracle\oradata\eygle\EYGLE\DATAFILE\TRANS01.DBF'

处理对象类型 TRANSPORTABLE_EXPORT/PLUGTS_BLK

处理对象类型 TRANSPORTABLE_EXPORT/TABLE

处理对象类型 TRANSPORTABLE_EXPORT/TTE_POSTINST/PLUGTS_BLK

作业 "EYGLE"."SYS_IMPORT_TRANSPORTABLE_01" 已于 15:03 成功完成

6.同字节序文件的跨平台

前面说过,当一个Little Endian的系统试图从一个Big Endian的系统中读取数据时,就需要通过转换,否则不同的字节顺序将导致数据不能被正确读取。那么另外一个问题出现了,如果字节序相同的平台进行文件交互,数据能否被正确读取呢?

理论上的确是可以的,但是由于在不同的平台上操作系统会在数据文件头写上系统信息,这部分信息无法跨越平台,所以仍然会导致跨平台的文件无法被数据库正确识别(Oracle10g中同字节序平台数据文件头不再存在跨平台的迁移问题)。

接下来让我们通过Windows和Linux平台来进行一个跨平台测试,相信通过这个测试可以对以上提出的问题作出一个很好的回答。

实验环境一:Windows XP+Oracle10g 10.2.0.1。

SQL> select * from v$version where rownum <2;

BANNER

----------------------------------------------------------------

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

实验环境二:Red Hat Enterprise Linux AS release3 +Oracle 9iR29.2.0.4。

SQL> select * from v$version where rownum <2;

BANNER

----------------------------------------------------------------

Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production

看一下Linux平台,文件头被操作系统保留了8192字节:

SQL> select file_name,bytes from dba_data_files

2 where tablespace_name='USERS';

FILE_NAME BYTES

----------------------------------- ----------

/opt/oracle/oradata/eygle/users.dbf 10485760

SQL> !

[oracle@jumper eygle]$ ll users.dbf

-rw-r----- 1 oracle dba 10493952 Mar 23 10:14 users.dbf

[oracle@jumper eygle]$ exit

exit

SQL> select 10493952 -10485760 diff from dual;

DIFF

----------

8192

Windows平台上数据文件头同样保留了8192字节:

SQL> select file_name,bytes from dba_data_files

2 where tablespace_name='USERS';

FILE_NAME BYTES

--------------------------------------------------- ----------

D:\ORADATA\EYGLE\DATAFILE\O1_MF_USERS_2G8OJYYS_.DBF 5242880

SQL> host dir D:\ORADATA\EYGLE\DATAFILE\O1_MF_USERS_2G8OJYYS_.DBF

2007-03-22 17:41 5,251,072 O1_MF_USERS_2G8OJYYS_.DBF

SQL> select 5251072 -5242880 diff from dual;

DIFF

----------

8192

可以通过Linux和Windows平台来进行一个小测试实验,这两个平台都是Little Endian的系统:

SQL> select * from v$transportable_platform;

PLATFORM_ID PLATFORM_NAME ENDIAN_FORMAT

----------- ---------------------------------------- --------------

1 Solaris[tm] OE (32-bit) Big

2 Solaris[tm] OE (64-bit) Big

7MicrosoftWindows IA (32-bit)   Little 

0 Linux IA (32-bit)     Little 

首先在Linux下Oracle 9204中创建一个测试表空间:

[oracle@jumper oracle]$ cd oradata/eygle

[oracle@jumper eygle]$ sqlplus "/ as sysdba"

Connected to:

Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production

With the Partitioning option

JServer Release 9.2.0.4.0 - Production

SQL> create tablespace eyglee datafile size 10M;

Tablespace created.

创建测试用户并创建一个测试表:

SQL> create user eyglee identified by eyglee default tablespace eyglee;

SQL> grant connect,resource to eyglee;

SQL> connect eyglee/eyglee

Connected.

SQL> create table eyglee as select * from dict;

SQL> select count(*) from eyglee;

COUNT(*)

----------

477

将表空间设置为只读:

SQL> connect / as sysdba

Connected.

SQL> alter tablespace eyglee read only;

Tablespace altered.

SQL> select file_name from dba_data_files where tablespace_name='EYGLEE';

FILE_NAME

------------------------------------------------------------

/opt/oracle/oradata/eygle/o1_mf_eyglee_309yc9gr_.dbf

压缩文件以方便传输:

[oracle@jumper eygle]$ tar -cvf eyglee.tar o1_mf_eyglee_309yc9gr_.dbf

o1_mf_eyglee_309yc9gr_.dbf

[oracle@jumper eygle]$ gzip eyglee.tar

导出表空间:

[oracle@jumper  eygle] $  exp  \'/  as  sysdba\'  tablespaces=eyglee  transport_tablespace=y file=trans_eyglee.dmp

Export: Release 9.2.0.4.0 - Production on Sat Mar 24 18:17:32 2007

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

Connected to: Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production

With the Partitioning option

JServer Release 9.2.0.4.0 - Production

Export done in ZHS16GBK character set and AL16UTF16 NCHAR character set

Note: tabledata (rows)willnotbe exported 

About to export transportable tablespace metadata...

For tablespace EYGLEE ...

. exporting cluster definitions

. exporting table definitions

. . exporting table EYGLEE

. exporting referential integrity constraints

. exporting triggers

. end transportable tablespace metadata export

Export terminated successfully without warnings.

[oracle@jumper eygle]$ ll *eyglee*

-rw-r--r-- 1 oracle dba 32985 Mar 24 18:14 eyglee.tar.gz

-rw-r----- 1 oracle dba 10493952 Mar 24 18:13 o1_mf_eyglee_309yc9gr_.dbf

-rw-r--r-- 1 oracle dba 16384 Mar 24 18:17 trans_eyglee.dmp

传输文件到Windows平台:

D:\oradata\EYGLE\DATAFILE>dir *eyglee*

2007-03-24 18:21 32,985 eyglee.tar.gz

2007-03-24 18:21 16,384 trans_eyglee.dmp

D:\oradata\EYGLE\DATAFILE>gzip -d eyglee.tar.gz

D:\oradata\EYGLE\DATAFILE>tar -xvf eyglee.tar

tar: blocksize = 20

x o1_mf_eyglee_309yc9gr_.dbf, 10493952 bytes, 20496 tape blocks

在Windows上创建新用户:

SQL> create user eyglee identified by eyglee;

用户已创建。

SQL> grant connect ,resource to eyglee;

授权成功。

如果此时导入会出现ORA-00600错误:

D:\oradata\EYGLE\DATAFILE>imp '/ as sysdba' tablespaces=eyglee transport_tablespace=y file=trans_eyglee.dmp datafiles=d:\oradata\EYGLE\DATAFILE\o1_mf_eyglee_309yc9gr_.dbf

Import: Release 10.2.0.1.0 - Production on 星期六 3月 24 18:59:23 2007

Copyright (c) 1982, 2005, Oracle. All rights reserved.

连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production

With the Partitioning, OLAP and Data Mining options

经由常规路径由 EXPORT:V09.02.00 创建的导出文件

即将导入可传输的表空间元数据...

已经完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的导入

. 正在将 SYS 的对象导入到 SYS

. 正在将 SYS 的对象导入到 SYS

IMP-00017: 由于 ORACLE 错误 600, 以下语句失败:

"BEGIN sys.dbms_plugts.beginImpTablespace('EYGLEE',9,'SYS',1,0,8192,1,1899"

"6106462,1,2147483645,8,128,8,0,1,0,8,1407686520,1,1,18996106397,NULL,0,0,NU"

"LL,NULL); END;"

IMP-00003: 遇到 ORACLE 错误 600

ORA-00600:内部错误代码,参数: [krhcvt_filhdr_v10_01], [], [], [], [], [], [], [] 

ORA-06512: 在 "SYS.DBMS_PLUGTS", line 1801

ORA-06512: 在 line 1

IMP-00000: 未成功终止导入

其中“参数:[krhcvt_filhdr_v10_01]”提示文件头无法正确识别。

可以通过对这个文件进行一个特殊操作,为文件更换一个Windows下数据文件的文件头,则数据文件就应该能够被数据库识别。以下是这个“小手术”操作的过程。

首先提取一个Windows数据文件头:

D:\oradata\EYGLE\DATAFILE>dd if=O1_MF_USERS_2G8OJYYS_.DBF of=header.dbf bs=8192 count=1

1+0 records in

1+0 records out

然后去除Linux下的数据文件头:

D:\oradata\EYGLE\DATAFILE>dd if=o1_mf_eyglee_309yc9gr_.dbf of=eyglee.dbf bs=8192 skip=1

1280+0 records in

1280+0 records out

最后将这两个文件合二为一:

D:\oradata\EYGLE\DATAFILE>copy /b header.dbf+eyglee.dbf eygleee.dbf

header.dbf

eyglee.dbf

已复制 1 个文件。

现在拥有的新文件eygleee.dbf就具有了一个Windows平台的文件头以及Linux下的“文件身”。至此这个文件就能够被Windows上的Oracle识别了,可以执行导入操作:

D:\oradata\EYGLE\DATAFILE>imp '/ as sysdba' tablespaces=eyglee transport_tablespace=y file=trans_eyglee.dmp datafiles=d:\oradata\EYGLE\DATAFILE\eygleee.dbf

Import: Release 10.2.0.1.0 - Production on 星期六 3月 24 19:22:13 2007

Copyright (c) 1982, 2005, Oracle. All rights reserved.

经由常规路径由 EXPORT:V09.02.00 创建的导出文件

即将导入可传输的表空间元数据...

已经完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的导入

. 正在将 SYS 的对象导入到 SYS

. 正在将 SYS 的对象导入到 SYS

. 正在将 EYGLEE 的对象导入到 EYGLEE

. . 正在导入表 "EYGLEE"

成功终止导入, 没有出现警告。

此时数据已经能够被正确识别:

SQL> connect eyglee/eyglee

已连接。

SQL> select count(*) from eyglee;

COUNT(*)

----------

477

最后将表空间更改为读写模式,可以进行正常的数据操作:

SQL> connect / as sysdba

已连接。

SQL> alter tablespace eyglee read write;

表空间已更改。

SQL> connect eyglee/eyglee

已连接。

SQL> insert into eyglee select * from eyglee;

已创建477行。

SQL> insert into eyglee select * from eyglee;

已创建954行。

SQL> insert into eyglee select * from eyglee;

已创建1908行。

SQL> commit;

提交完成。

SQL> select count(*) from eyglee;

COUNT(*)

----------

3816

通过这个实验,还可以得出另外一个结论,Oracle 9i的数据文件可以通过表空间传输迁移到Oracle 10g中使用。

7.Oracle10g同字节序跨平台迁移

在Oracle10g中,同字节序跨平台的文件头信息Oracle会自动改写,不再需要转换。我们看以下测试:

[oracle@danaly oradata]$ sqlplus "/ as sysdba"

SQL*Plus: Release 10.2.0.1.0 - Production on Thu Jul 12 15:14:21 2007

Copyright (c) 1982, 2005, Oracle. All rights reserved.

SQL> alter database mount;

Database altered.

SQL> alter database open;

Database altered.

SQL> select name from v$datafile;

NAME

--------------------------------------------------------------------------------

/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_system_37tc1xns_.dbf

/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_undotbs1_37tc29mb_.dbf

/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_sysaux_37tc2gqc_.dbf

/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_users_37tc2tth_.dbf

SQL> show parameter comp

NAME TYPE VALUE

------------------------------------ ----------- ------------------------------

compatible string 10.2.0.1.0

nls_comp string

plsql_compiler_flags string INTERPRETED, NON_DEBUG

plsql_v2_compatibility boolean FALSE

SQL> create tablespace trans

2 datafile '/opt/oracle/oradata/eygle/EYGLE/datafile/trans.dbf' size 10M;

Tablespace created.

SQL> create user trans identified by trans default tablespace trans;

SQL> grant connect,resource to trans;

SQL> connect trans/trans

Connected.

SQL> create table test as select * from dict;

Table created.

SQL> select count(*) from test;

COUNT(*)

----------

615

SQL> connect / as sysdba

Connected.

SQL> alter tablespace trans read only;

Tablespace altered.

导出元数据,准备表空间迁移:

[oracle@]$ exp \'/ as sysdba\' tablespaces=trans transport_tablespace=y file=exp_trans.dmp

Export: Release 10.2.0.1.0 - Production on Thu Jul 12 15:28:24 2007

Copyright (c) 1982, 2005, Oracle. All rights reserved.

Note: tabledata (rows)willnotbe exported 

About to export transportable tablespace metadata...

For tablespaceTRANS ... 

. exporting cluster definitions

. exporting table definitions

. . exporting table TEST

. exporting referential integrity constraints

. exporting triggers

. end transportable tablespace metadata export

Export terminated successfully without warnings.

[oracle@danaly oradata]$ ls -l exp_trans.dmp 

-rw-r--r-- 1 oracle dba 16384 Jul 12 15:28 exp_trans.dmp

然后我们可以直接将这两个文件传输到Windows平台上,在数据库中执行必要的准备步骤:

SQL> create user trans identified by trans;

用户已创建。

SQL> grant connect,resource to trans;

授权成功。

接下来执行导入:

C:\oracle\oradata\EYGLE\DATAFILE>imp  '/  as  sysdba'  tablespaces=trans  transport_tablespace=y file=exp_trans.dmp datafiles=C:\oracle\oradata\EYGLE\DATAFILE\trans.dbf

Import: Release 10.2.0.3.0 - Production on 星期四 7月 12 15:55:30 2007

Copyright (c) 1982, 2005, Oracle. All rights reserved.

经由常规路径由 EXPORT:V10.02.01 创建的导出文件

即将导入可传输的表空间元数据... 

已经完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的导入

. 正在将 SYS 的对象导入到 SYS

. 正在将 SYS 的对象导入到 SYS

. 正在将 TRANS 的对象导入到 TRANS

. . 正在导入表 "TEST"

. 正在将 SYS 的对象导入到 SYS

成功终止导入, 没有出现警告。

我们看到这个文件可以直接被Windows上的系统识别。

SQL> select count(*) from trans.test;

COUNT(*)

----------

615

SQL> select tablespace_name,status from dba_tablespaces;

TABLESPACE_NAME STATUS

------------------------------ ---------

SYSTEM ONLINE

UNDOTBS1 ONLINE

SYSAUX ONLINE

TEMP ONLINE

USERS ONLINE

TRANS     READONLY 

8.Oracle10g同字节序跨平台迁移的增强

基于上一节的测试我们知道,在 Oracle10gR2 中,Oracle 开始支持同字节序数据库的跨平台迁移。这一技术实现有以下几点注意事项。

源平台和目的平台需要具有相同的字节序。

重做日志文件和控制文件不会传输,迁移之后需要重建控制文件使用RESETLOGS方式打开数据库;临时文件不会被传输。

BFILES、外部表和Directories、口令文件等不会被传输。

我们通过Linux平台到Windows平台的迁移来看一下这一技术的实现。

(1)确认平台及版本。

首先要确定源平台和目标平台具有相同的字节序:

SQL> select PLATFORM_NAME, ENDIAN_FORMAT from V$TRANSPORTABLE_PLATFORM

2 where platform_name in ('Linux IA (32-bit)','Microsoft Windows IA (32-bit)');

PLATFORM_NAME ENDIAN_FORMAT

---------------------------------------- --------------

Microsoft Windows IA (32-bit) Little

Linux IA (32-bit) Little

然后需要确定源平台及目标平台的数据库版本,通常需要这两者具有相同的数据库版本,本例的情况有所不同,Linux平台的数据库版本为10.2.0.1,Windows平台的数据库版本为10.2.0.3,数据库版本不同将使情况稍微复杂一点,而且需要注意的是,通常高版本的数据库不能向低版本迁移。

(2)确认迁移是否支持。

跨平台迁移需要数据库处于READ ONLY模式打开,使用DBMS_TDB.CHECK_DB进行检查:

SQL> set serveroutput on

SQL> declare

2 db_ready boolean;

3 begin

4 db_ready := dbms_tdb.check_db('Microsoft Windows IA (32-bit)');

5 end;

6 /

PL/SQL procedure successfully completed.

如果以上过程成功执行,并没有其他相关警告输出,则说明数据库可以支持跨平台转移。

(3)检查外部对象。

使用DBMS_TDB.CHECK_EXTERNAL来识别外部表、Directories或BFILES等,这些对象所指向的外部数据不能被RMAN自动转移。

SQL> set serveroutput on

SQL> declare

2 external boolean;

3 begin

4 external := dbms_tdb.check_external;

5 end;

6 /

The following directories exist in the database:

SYS.DATA_PUMP_DIR

PL/SQL procedure successfully completed.

如果数据库中存在外部表、DIRECTORIES等,则以上过程执行后的输出与以上类似。

(4)使用RMAN进行跨平台文件迁移。

执行跨平台迁移首先要通过RMAN对数据文件进行转换,RMAN执行过程如下:

[oracle@danaly eygle]$ rman target /

Recovery Manager: Release 10.2.0.1.0 - Production on Sat Jun 23 23:06:52 2007

Copyright (c) 1982, 2005, Oracle. All rights reserved.

connected to target database: EYGLE (DBID=1445136501)

RMAN> CONVERTDATABASE NEW DATABASE 'JULIA'

2> TRANSPORT SCRIPT '/opt/oracle/oradata/transport/transport.sql'

3> TO PLATFORM 'Microsoft Windows IA (32-bit)'

4> DB_FILE_NAME_CONVERT '/opt/oracle/oradata/eygle/EYGLE/datafile' \

'/opt/oracle/oradata/transport';

Starting convert at 23-JUN-07

using target database control file instead of recovery catalog

allocated channel: ORA_DISK_1

channel ORA_DISK_1: sid=159 devtype=DISK

Directory SYS.DATA_PUMP_DIR found in the database

UserSYSwithSYSDBA andSYSOPERprivilege found inpassword file 

channel ORA_DISK_1: starting datafile conversion

input datafile

fno=00001 name=/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_system_37tc1xns_.dbf

converted datafile=/opt/oracle/oradata/transport/o1_mf_system_37tc1xns_.dbf

channel ORA_DISK_1: datafile conversion complete, elapsed time: 00:00:15

channel ORA_DISK_1: starting datafile conversion

input datafile

fno=00002 name=/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_undotbs1_37tc29mb_.dbf

converted datafile=/opt/oracle/oradata/transport/o1_mf_undotbs1_37tc29mb_.dbf

channel ORA_DISK_1: datafile conversion complete, elapsed time: 00:00:07

channel ORA_DISK_1: starting datafile conversion

input datafile

fno=00003 name=/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_sysaux_37tc2gqc_.dbf

converted datafile=/opt/oracle/oradata/transport/o1_mf_sysaux_37tc2gqc_.dbf

channel ORA_DISK_1: datafile conversion complete, elapsed time: 00:00:07

channel ORA_DISK_1: starting datafile conversion

input datafile

fno=00004 name=/opt/oracle/oradata/eygle/EYGLE/datafile/o1_mf_users_37tc2tth_.dbf

converted datafile=/opt/oracle/oradata/transport/o1_mf_users_37tc2tth_.dbf

channel ORA_DISK_1: datafile conversion complete, elapsed time: 00:00:01

Run SQL script /opt/oracle/oradata/transport/transport.sql on the target platform to create database

Edit init.ora file /opt/oracle/product/10.2.0/dbs/init_00il1i4r_1_0.ora. This PFILE will be used to create the database on the target platform

To recompile all PL/SQL modules, run utlirp.sql and utlrp.sql on the target platform

To change the internal database identifier, use DBNEWID Utility

Finished backup at 23-JUN-07

RMAN 的转换语句中指定生成一个转换脚本 transport.sql 用于参考,转换的目标平台是Microsoft WindowsIA(32-bit),所有的数据文件转换后存放在一个新的目录下。

最后RMAN还自动生成一个参数文件,这个文件是init_00il1i4r_1_0.ora,这个参数文件里包含了一些重要的初始化参数,可以根据需要进行相应的更改,由于平台以及路径的不同,很多涉及路径的参数都需要进行变更,这个参数文件的内容大致分为3个部分。

第一部分列出需要修改的参数:

# Please change the values of the following parameters:

control_files = "/opt/oracle/product/10.2.0/dbs/cf_D-JULIA_id-1445136501_00il1i4r"

db_create_file_dest = "/opt/oracle/product/10.2.0/dbs/eygle"

db_recovery_file_dest = "/opt/oracle/product/10.2.0/dbs/flash_recovery_area"

db_recovery_file_dest_size= 2147483648

background_dump_dest = "/opt/oracle/product/10.2.0/dbs/bdump"

user_dump_dest = "/opt/oracle/product/10.2.0/dbs/udump"

core_dump_dest = "/opt/oracle/product/10.2.0/dbs/cdump"

audit_file_dest = "/opt/oracle/product/10.2.0/dbs/adump"

db_name = "JULIA"

第二部分列出了建议Review的参数:

# Please review the values of the following parameters:

remote_login_passwordfile= "EXCLUSIVE"

db_domain = ""

dispatchers = "(PROTOCOL=TCP) (SERVICE=eygleXDB)"

第三部分列出了来自于源数据库的一些特殊设置,这些参数可以酌情修改:

# The values of the following parameters are from source database:

processes = 150

sga_target = 943718400

db_block_size = 8192

compatible = "10.2.0.1.0"

db_file_multiblock_read_count= 16

undo_management = "AUTO"

undo_tablespace = "UNDOTBS1"

job_queue_processes = 10

open_cursors = 300

pga_aggregate_target = 314572800

参数文件的内容我们可以在新的平台上重新创建,这个参数文件可以作为参考。

(5)转移文件到目标平台。

源平台的工作完成之后,数据文件可以通过FTP等方式转移到目标平台,部署到相应目录,我的操作步骤如下:

C:\oracle\oradata>gzip -d trans.tar.gz

C:\oracle\oradata>tar -xvf trans.tar

tar: blocksize = 20

x transport/transport.sql, 2397 bytes, 5 tape blocks

x transport/o1_mf_sysaux_37tc2gqc_.dbf, 125837312 bytes, 245776 tape blocks

x transport/o1_mf_undotbs1_37tc29mb_.dbf, 209723392 bytes, 409616 tape blocks

x transport/o1_mf_system_37tc1xns_.dbf, 314580992 bytes, 614416 tape blocks

x transport/o1_mf_users_37tc2tth_.dbf, 5251072 bytes, 10256 tape blocks

C:\oracle\oradata>mkdir -p JULIA\DATAFILE

C:\oracle\oradata>mkdir JULIA\CONTROLFILE

C:\oracle\oradata>mkdir JULIA\ONLINELOG

C:\oracle\oradata>mv transport\* JULIA\DATAFILE

(6)创建基础环境。

首先创建相关目录:

C:\oracle\oradata>mkdir C:\oracle\admin\julia\adump

C:\oracle\oradata>mkdir C:\oracle\admin\julia\bdump

C:\oracle\oradata>mkdir C:\oracle\admin\julia\cdump

C:\oracle\oradata>mkdir C:\oracle\admin\julia\dpdump

C:\oracle\oradata>mkdir C:\oracle\admin\julia\pfile

C:\oracle\oradata>mkdir C:\oracle\admin\julia\udump

创建Windows数据库服务:

C:\oracle\oradata>oradim -new -sid julia

实例已创建。

修改参数文件,参数文件可以从前面自动生成的参数文件进行修改得到,其中目录结构需要依据新平台的具体设置进行修改,和存储主要相关的两个参数修改如下:

db_create_file_dest = "C:\oracle\oradata"

db_recovery_file_dest = "C:\oracle\flash_recovery_area"

修改后的参数文件在Windows上应该位于$ORACLE_HOME/database下。参数文件中的另外一个重要参数是控制文件路径:

control_files = "/opt/oracle/product/10.2.0/dbs/cf_D-JULIA_id-1445136501_00il1i4r"

如果我们计划使用 OMF 管理,可以暂时注释这一参数,在创建控制文件后再将控制文件的名称路径追加到参数文件中。

(7)迁移步骤。

准备工作完成之后,我们可以进行新平台的数据库加载等工作,这些工作还可以参考在源平台生成的transport.sql脚本。

这个脚本的第一部分给出了使用参数文件启动实例及重新创建控制文件的语法参考,当然我们还需要修改才能使用这段脚本:

STARTUP NOMOUNT PFILE='/opt/oracle/product/10.2.0/dbs/init_00il1i4r_1_0.ora'

CREATE CONTROLFILE REUSE SET DATABASE "LINDB10G" RESETLOGS NOARCHIVELOG

MAXLOGFILES 16 MAXLOGMEMBERS 3 MAXDATAFILES 100 MAXINSTANCES 8 MAXLOGHISTORY 292 LOGFILE

GROUP 1 SIZE 50M, GROUP 2 SIZE 50M, GROUP 3 SIZE 50M

DATAFILE

'/opt/oracle/oradata/transport/o1_mf_system_37tc1xns_.dbf',

'/opt/oracle/oradata/transport/o1_mf_undotbs1_37tc29mb_.dbf',

'/opt/oracle/oradata/transport/o1_mf_sysaux_37tc2gqc_.dbf',

'/opt/oracle/oradata/transport/o1_mf_users_37tc2tth_.dbf'

CHARACTER SET ZHS16GBK;

由于我们已经编辑好了新的参数文件,可以使用这个参数文件启动实例:

C:\oracle\oradata>set ORACLE_SID=julia

C:\oracle\oradata>sqlplus "/ as sysdba"

SQL*Plus: Release 10.2.0.3.0 - Production on 星期一 6月 25 09:45:59 2007

Copyright (c) 1982, 2006, Oracle. All Rights Reserved.

已连接到空闲例程。

SQL> startup nomount pfile=?\database\initjulia.ora

ORACLE 例程已经启动。

接下来创建控制文件:

SQL> CREATE CONTROLFILE REUSE SET DATABASE "JULIA" RESETLOGS NOARCHIVELOG

2 MAXLOGFILES 16

3 MAXLOGMEMBERS 3

4 MAXDATAFILES 100

5 MAXINSTANCES 8

6 MAXLOGHISTORY 292

7 LOGFILE

8 GROUP 1 SIZE 10M,

9 GROUP 2 SIZE 10M,

10 GROUP 3 SIZE 10M

11 DATAFILE

12 'C:\oracle\oradata\JULIA\DATAFILE\o1_mf_system_37tc1xns_.dbf',

13 'C:\oracle\oradata\JULIA\DATAFILE\o1_mf_undotbs1_37tc29mb_.dbf',

14 'C:\oracle\oradata\JULIA\DATAFILE\o1_mf_sysaux_37tc2gqc_.dbf',

15 'C:\oracle\oradata\JULIA\DATAFILE\o1_mf_users_37tc2tth_.dbf'

16 CHARACTER SET ZHS16GBK;

控制文件已创建。

然后将控制文件的名称等信息追加到参数文件中:

SQL> column ctl_files NEW_VALUE ctl_files;

SQL> SELECT CONCAT ('control_files=''',

2 CONCAT (REPLACE (VALUE, ', ', ''','''), '''')

3 ) ctl_files

4 FROM v$parameter WHERE NAME = 'control_files';

CTL_FILES

--------------------------------------------------------------------------------

control_files='C:\ORACLE\ORADATA\JULIA\CONTROLFILE\O1_MF_37Y7SZ9R_.CTL','C:\ORAC

LE\FLASH_RECOVERY_AREA\JULIA\CONTROLFILE\O1_MF_37Y7SZMK_.CTL'

SQL> host "echo &ctl_files >>C:\oracle\10.2.0\database\initjulia.ora";

注意:执行完以上命令后,需要检查参数文件的格式,如果控制文件名称未正确添加,可以手工调整一下。

完成了以上工作后,可以关闭数据库,再次启动数据库到Mount状态,这时候新的控制文件已经发挥作用:

SQL> shutdown immediate;

ORA-01109: 数据库未打开

已经卸载数据库。

ORACLE 例程已经关闭。

SQL> startup mount;

ORACLE 例程已经启动。

数据库装载完毕。

(8)完成数据库恢复。

接下来再参考一下transport.sql中的推荐步骤:

ALTER DATABASE OPEN RESETLOGS;

-- Commands to add tempfiles to temporary tablespaces.

-- Online tempfiles have complete space information.

-- Other tempfiles may require adjustment.

ALTER TABLESPACE TEMP ADD TEMPFILE

SIZE 20971520 AUTOEXTEND ON NEXT 655360 MAXSIZE 32767M;

-- End of tempfile additions.

现在我们需要通过RESETLOGS方式来重新生成日志文件,然后手工添加临时文件。

注意,在迁移过程中如果两个平台的数据库版本完全一致,则以上步骤可以顺利执行,参考transport.sql可以顺利完成迁移。而本例的测试平台由于Linux平台的数据库版本为10.2.0.1,Windows平台版本为10.2.0.3,所以实际操作中还会有所不同,在执行RESETLOGS过程中,数据库会发生中断:

SQL> alter database open resetlogs;

alter database open resetlogs

*

第 1 行出现错误:

ORA-01092: ORACLE 实例终止。强制断开连接

检查日志我们发现以下提示:

Mon Jun 25 10:03:19 2007

Errors in file c:\oracle\admin\julia\udump\julia_ora_3596.trc:

ORA-00704: 引导程序进程失败

ORA-39700: 必须用 UPGRADE 选项打开数据库

Oracle要求以UPGRADE选项打开数据库,对数据库执行跨版本迁移。

我们继续参考transport.sql的最后部分:

SHUTDOWN IMMEDIATE

STARTUP UPGRADE PFILE='/opt/oracle/product/10.2.0/dbs/init_00il1i4r_1_0.ora'

@@ ?/rdbms/admin/utlirp.sql

SHUTDOWN IMMEDIATE

STARTUP PFILE='/opt/oracle/product/10.2.0/dbs/init_00il1i4r_1_0.ora'

-- The following step will recompile all PL/SQL modules.

-- It may take serveral hours to complete.

@@ ?/rdbms/admin/utlrp.sql

set feedback 6;

再次启动数据库到UPGRADE模式,由于之前的数据库中断,现在这些需要进行一点恢复工作:

SQL> startup upgrade;

ORACLE 例程已经启动。

数据库装载完毕。

ORA-01113: 文件 1 需要介质恢复

ORA-01110: 数据文件 1:'C:\ORACLE\ORADATA\JULIA\DATAFILE\O1_MF_SYSTEM_37TC1XNS_.DBF'

SQL> recover database;

完成介质恢复。

恢复完成之后,启动数据库到UPGRADE模式:

SQL> shutdown immediate;

ORA-01109: 数据库未打开

已经卸载数据库。

ORACLE 例程已经关闭。

SQL> startup upgrade;

ORACLE 例程已经启动。

数据库装载完毕。

数据库已经打开。

执行脚本?/rdbms/admin/utlirp.sql,这个脚本执行完成之后会有如下提示:

DOC>#######################################################################

DOC> utlirp.sql completed successfully. All PL/SQL objects in the

DOC> database have been invalidated.

DOC>

DOC> Shut down and restart the database in normal mode and run utlrp.sql to

DOC> recompile invalid objects.

DOC>#######################################################################

也就是说,这个脚本的作用是使数据库中的PL/SQL对象INVALID,然后通过utlrp.sql的重新编译,消除跨平台的兼容性影响。

按照transport.sql脚本提示的步骤,我们可以重新启动数据库来执行utlrp.sql脚本(由于本例涉及版本迁移,需要再次启动数据库到 upgrade 模式,如果数据库版本相同,则可以直接启动数据库,执行utlrp.sql脚本完成最后的编译工作):

SQL> @@ ?/rdbms/admin/utlrp.sql

TIMESTAMP

-------------------------------------------------------------------------------

COMP_TIMESTAMP UTLRP_BGN 2007-06-25 10:27:57

……

PL/SQL 过程已成功完成。

TIMESTAMP

-------------------------------------------------------------------------------

COMP_TIMESTAMP UTLRP_END 2007-06-25 10:39:43

PL/SQL 过程已成功完成。

utlrp.sql执行完成之后,我们需要再执行和数据库升级相关的脚本,这个脚本是catupgrd.sql:

SQL> @?/rdbms/admin/catupgrd.sql

这个脚本调用catlog.sql和catproc.sql来重建字典对象等,在执行完这个脚本之后,我们可以关闭数据库后,正常打开数据库:

SQL> startup

ORACLE 例程已经启动。

数据库装载完毕。

数据库已经打开。

SQL> select count(*) from dba_objects where status='INVALID';

COUNT(*)

----------

86

已选择 1 行。

SQL> @?\rdbms\admin\utlrp.sql

catupgrd.sql脚本可能会使部分字典对象失效,我们可以再次运行utlrp.sql脚本来进行编译,编译完成后,不要忘记为数据库添加临时文件:

SQL> ALTER TABLESPACE TEMP ADD TEMPFILE

2 SIZE 20971520 AUTOEXTEND ON NEXT 655360 MAXSIZE 32767M;

表空间已更改。

至此,同字节序的跨平台迁移全部完成,当然由于版本的不同,整个过程稍微复杂了一些,不过,这个过程对于跨平台的迁移及版本升级是一个很好的参考。

9.实现数据迁移的高可用性

通过以上测试实际上可以确认,对于可传输表空间,可以很容易从Oracle 9i向Oracle 10g迁移。那么这种方法对于可用性要求极高的环境进行数据迁移或数据库迁移具有极大的便利。

如果进行数据库升级,通常的方法是通过DBUA(Database Upgrade Assistant,Oracle 10g引入的新工具)进行,但是DBUA存在的问题在于,操作过程过长,而且如果升级过程中出现问题,数据文件可能不能重新被使用,这就需要从备份中进行恢复,这使得业务连续性要求高的企业很难采用这种方法进行升级。

另外一种常见的迁移方法是通过逻辑导出导入(EXP/IMP),但是这种方法对于不断变化的数据无能为力,所以通常也不可行。那么现在,可传输表空间就成了一个可以考虑的快速迁移或升级方法。

Oracle 有一个小组,专注于设计高可用性架构的实现,以帮助用户最大限度的提高系统可用性,Oracle有一个专有名词用来命名这类技术——MAA(Maximum Availability Architecture , MAA)。OTN 上 MAA 部分有一个 Amadeus 公司的实践案例,通过可传输表空间从 Oracle 9i向Oracle 10g实现快速数据迁移。

当然,这种方法的使用要考虑的还有很多,通过各种技术和方法的结合使用才能最终地达到快速迁移的目标。

Amadeus公司的迁移是在同类型平台不同主机之间进行的,其实现步骤大致如下:

(1)在升级主机安装Oracle 9i版本,并创建生产库的DataGuard数据库,这个工作可以在线进行,不影响主节点的工作。

(2)在升级主机安装Oracle 10gR2数据库软件,创建数据库;此时升级主机上存在了2个数据库。

(3)整理不能通过transport tablespace处理的内容,如sequence、synonyms、grants等。

(4)在升级割接时间,将主库置为只读,将日志全部应用到备机,业务影响从此时开始。

(5)将备机的数据文件通过可传输表空间迁移至Oracle 10gR2数据库,并创建sequencee、synonyms、grants等对象,检查验证。

(6)如果没有问题,则即可将业务切换至新的Oracle 10gR2数据库运行,业务恢复正常运行。

在这个迁移过程中,如果迁移失败,那么直接读写打开主库即可恢复业务的正常运行,回退非常方便。

使用这种方法,业务影响仅发生在以上(4)~(6)步,在OTN的案例中,Amadeus公司在实际操作中,10分钟之内就将一个大型数据库迁移到Oracle 10gR2,这种方式是一种非常有新意的创新性应用。在熟悉了Oracle的各项技术之后,通过不断实践和探索,我们就能够不断发现充满价值的Oracle应用。

 

1.4.7 文件系统与ASM的切换

在进行表空间迁移时,如果是从文件系统到文件系统的迁移很容易实现,但是如果是从文件系统到ASM则需要多一点步骤。类似前面的测试,如果在ASM环境中执行同样的导入命令:

imp \'/ as sysdba\' tablespaces=trans transport_tablespace=y

file=exp_trans.dmp datafiles=/opt/oracle/trans.dbf

则简单的导入之后会出现如下的效果,新导入的文件位于文件系统之上,这显然是不希望看到的,我们需要将文件系统文件转移到ASM磁盘组上去:

SQL> select name from v$datafile;

NAME

--------------------------------------------------------------------------------

+DATADG/rac/datafile/system.259.722961061

+DATADG/rac/datafile/undotbs1.260.722961083

+DATADG/rac/datafile/sysaux.261.722961087

+DATADG/rac/datafile/undotbs2.263.722961097

+DATADG/rac/datafile/users.264.722961099

/opt/oracle/trans.dbf 

文件转移可以通过RMAN来进行,但是首次尝试遇到了RMAN-20201错误:

[oracle@rac1 oracle]$ rman target /

Recovery Manager: Release 10.2.0.4.0 - Production on Wed Sep 1 14:24:37 2010

Copyright (c) 1982, 2007, Oracle. All rights reserved.

connected to target database: RAC (DBID=2310943069)

RMAN> backup as copydatafile '/opt/oracle/trans.dbf' format '+DATADG';

Starting backup at 01-SEP-10

using target database control file instead of recovery catalog

allocated channel: ORA_DISK_1

channel ORA_DISK_1: sid=124 instance=rac1 devtype=DISK

RMAN-00571: ===========================================================

RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============

RMAN-00571: ===========================================================

RMAN-03002: failure of backup command at 09/01/2010 14:25:21

RMAN-20201: datafile not found in the recovery catalog

RMAN-06010: error while looking up datafile: /opt/oracle/trans.dbf

这个错误是由于TRANS表空间刚刚导入到数据库中,处于只读状态,并未被Catalog记录感知,通过对这个文件进行特定操作,如读写变更,则可以消除此错误:

SQL> select tablespace_name,status from dba_tablespaces where tablespace_name=’TRANS’;

TABLESPACE_NAME STATUS

------------------------------ ---------

TRANS READ ONLY

RMAN中的Schema信息尚未记录该表空间:

RMAN> report schema;

Report of database schema

List of Permanent Datafiles

===========================

File Size(MB) Tablespace RB segs Datafile Name

---- -------- -------------------- ------- ------------------------

1 300 SYSTEM *** +DATADG/rac/datafile/system.259.722961061

2 200 UNDOTBS1 *** +DATADG/rac/datafile/undotbs1.260.722961083

3 280 SYSAUX *** +DATADG/rac/datafile/sysaux.261.722961087

4 200 UNDOTBS2 *** +DATADG/rac/datafile/undotbs2.263.722961097

5 5 USERS *** +DATADG/rac/datafile/users.264.722961099

6 512 STREAM_TBS *** +DATADG/rac/datafile/stream_tbs.268.725126097

7 1 TESTTBS1 *** +DATADG/rac/datafile/testtbs1.269.726592535

List of Temporary Files

=======================

File Size(MB) Tablespace Maxsize(MB) Tempfile Name

---- -------- -------------------- ----------- --------------------

1 20 TEMP 32767 +DATADG/rac/tempfile/temp.262.722961089

在数据库内部对该表空置读写访问:

SQL> alter tablespace trans read write;

Tablespace altered.

然后可以看到该表空间被Catalog所记录,当然这里的信息是来自控制文件的:

RMAN> report schema;

using target database control file instead of recovery catalog

Report of database schema

List of Permanent Datafiles

===========================

File Size(MB) Tablespace RB segs Datafile Name

---- -------- -------------------- ------- ------------------------

1 300 SYSTEM *** +DATADG/rac/datafile/system.259.722961061

2 200 UNDOTBS1 *** +DATADG/rac/datafile/undotbs1.260.722961083

3 280 SYSAUX *** +DATADG/rac/datafile/sysaux.261.722961087

4 200 UNDOTBS2 *** +DATADG/rac/datafile/undotbs2.263.722961097

5 5 USERS *** +DATADG/rac/datafile/users.264.722961099

6 512 STREAM_TBS *** +DATADG/rac/datafile/stream_tbs.268.725126097

7 1 TESTTBS1 *** +DATADG/rac/datafile/testtbs1.269.726592535

8 10  TRANS    *** /opt/oracle/trans.dbf 

List of Temporary Files

=======================

File Size(MB) Tablespace Maxsize(MB) Tempfile Name

---- -------- -------------------- ----------- --------------------

1 20 TEMP 32767 +DATADG/rac/tempfile/temp.262.722961089

接下来将表空间状态再改为只读:

SQL> alter tablespace trans read only;

Tablespace altered.

通过RMAN进行镜像拷贝:

RMAN> backup as copy datafile '/opt/oracle/trans.dbf' format '+DATADG';

Starting backup at 01-SEP-10

using target database control file instead of recovery catalog

allocated channel: ORA_DISK_1

channel ORA_DISK_1: sid=130 instance=rac1 devtype=DISK

channel ORA_DISK_1: starting datafile copy

input datafile fno=00008 name=/opt/oracle/trans.dbf

output filename=+DATADG/rac/datafile/trans.270.728577593 tag=TAG20100901T143951 recid=2 stamp=728577592

channel ORA_DISK_1: datafile copy complete, elapsed time: 00:00:01

Finished backup at 01-SEP-10

切换之前需要将表空间离线,否则会出现错误:

RMAN> switch datafile '/opt/oracle/trans.dbf' to copy;

RMAN-00571: ===========================================================

RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============

RMAN-00571: ===========================================================

RMAN-03002: failure of switch to copy command at 09/01/2010 14:40:58

RMAN-06572:database is open and datafile 8 is not offline

将表空间离线:

SQL> alter tablespace trans offline;

Tablespace altered.

执行切换:

RMAN> switch datafile '/opt/oracle/trans.dbf' to copy;

datafile 8 switched to datafile copy "+DATADG/rac/datafile/trans.270.728577593"

现在转换后的表空间已经被转移到了 ASM 磁盘组中,此时可以将表空间 Online,如果操作期间有过事务变更,还可能需要恢复:

SQL> alter tablespace trans online;

Tablespace altered.

SQL> select name from v$datafile;

NAME

--------------------------------------------------------------------------------

+DATADG/rac/datafile/system.259.722961061

+DATADG/rac/datafile/undotbs1.260.722961083

+DATADG/rac/datafile/sysaux.261.722961087

+DATADG/rac/datafile/undotbs2.263.722961097

+DATADG/rac/datafile/users.264.722961099

+DATADG/rac/datafile/trans.270.728577593 

 

1.4.8 DBMS_FILE_TRANSFER的可选性

从Oracle 10g开始,Oracle提供了DBMS_FILE_TRANSFER程序包,可以很方便地在本地数据库和远程数据库,ASM和文件系统间传输数据库文件。

有了DBMS_FILE_TRANSFER,数据库文件的传输就方便了许多,尤其是在传输基于ASM存储的数据文件时,不再局限于利用RMAN来进行传输,为我们提供了更多的选择。

注意,DBMS_FILE_TRANSFER具备一定的限制,单个数据库文件必须是512字节的整数倍,并且文件大小必须小于或者等于2TB,但是这基本上算不上什么弱点,我们的绝大多数需求都可以被满足。

DBMS_FILE_TRANSFER 包一共包含了 3 个存储过程,分别提供本机之间拷贝(COPY_FILE)、本机从远程主机获取(GET_FILE)以及本机上传至远程主机(PUT_FILE)3种传输数据库文件的功能。

SQL> desc dbms_file_transfer

PROCEDURE COPY_FILE

Argument Name Type In/Out Default?

------------------------------ ----------------------- ------ --------

SOURCE_DIRECTORY_OBJECT VARCHAR2 IN

SOURCE_FILE_NAME VARCHAR2 IN

DESTINATION_DIRECTORY_OBJECT VARCHAR2 IN

DESTINATION_FILE_NAME VARCHAR2 IN

PROCEDURE GET_FILE 

Argument Name Type In/Out Default?

------------------------------ ----------------------- ------ --------

SOURCE_DIRECTORY_OBJECT VARCHAR2 IN

SOURCE_FILE_NAME VARCHAR2 IN

SOURCE_DATABASE VARCHAR2 IN

DESTINATION_DIRECTORY_OBJECT VARCHAR2 IN

DESTINATION_FILE_NAME VARCHAR2 IN

PROCEDUREPUT_FILE 

Argument Name Type In/Out Default?

------------------------------ ----------------------- ------ --------

SOURCE_DIRECTORY_OBJECT VARCHAR2 IN

SOURCE_FILE_NAME VARCHAR2 IN

DESTINATION_DIRECTORY_OBJECT VARCHAR2 IN

DESTINATION_FILE_NAME VARCHAR2 IN

DESTINATION_DATABASE VARCHAR2 IN

以上过程的参数中,除了文件名称外,最关键的是DIRECTORY目录参数,这个目录需要预先设定,并且要求传输用户对相应的目录具有读或者写的权限。

看以下测试,首先通过asmcmd在DATADG下创建一个asmbk目录:

$ export ORACLE_SID=+ASM1

$ asmcmd

ASMCMD> ls

DATADG/

FSHDG/

ASMCMD> cd DATADG

ASMCMD> mkdir asmbk

然后在数据库内部创建两个DIRECTORY:

SQL> create directory ASMBK as '+DATADG/asmbk';

Directory created.

SQL> create directory OBASE as '/opt/oracle';

Directory created.

SQL> select * from dba_directories;

OWNER DIRECTORY_NAME DIRECTORY_PATH

---------- ------------------------------ --------------------------------------------------

SYS ASMBK +DATADG/asmbk

SYS OBASE /opt/oracle

现在DBMS_FILE_TRANSFER就可以大显身手,快速地帮助我们解决文件传输的问题:

SQL> exec dbms_file_transfer.copy_file('OBASE','trans.dbf','ASMBK','trans.dbf');

PL/SQL procedure successfully completed.

看一下ASM磁盘组上的内容,实际上文件的位置是在DATAFILE下,asmbk下存放的是一个别名:

ASMCMD> ls

DATADG/

FSHDG/

ASMCMD> cd DATADG

ASMCMD> cd asmbk

ASMCMD> ls

trans.dbf

ASMCMD> ls -l

Type Redund Striped Time Sys Name

N trans.dbf =>

+DATADG/RAC/DATAFILE/COPY_FILE.271.728582605 

DBMS_FILE_TRANSFER包更强大的功能是基于网络的远程PUT_FILE和COPY_FILE功能,这两个功能通过dblink实现。以下是一个简单测试。

首先在远程数据库创建测试用户及目录,并进行授权:

SQL> create user eygle identified by eygle;

SQL> grant connect,resource to eygle;

SQL> create or replace directory OBASE as '/opt/oracle';

SQL> grant read,write on directory OBASE to eygle;

SQL> grant execute on dbms_file_transfer to eygle;

接下来在本地数据库配置tnsnames.ora文件,并创建db link:

SMSDBN =

(DESCRIPTION =

(ADDRESS = (PROTOCOL = TCP)(HOST = 172.16.9.108)(PORT = 1521))

(CONNECT_DATA =

(SERVER = DEDICATED)

(SERVICE_NAME = smsdbn)

)

)

SQL> create database link smsdbn connect to eygle identified by eygle using 'smsdbn';

Database link created.

SQL> select * from dual@smsdbn;

D

-

X

接下来就可以通过DB Link进行远程的文件操作了,PUT_FILE可以将文件传输至远程主机:

SQL> exec dbms_file_transfer.put_file( 'ASMBK','trans.dbf','OBASE','remote_trans.dbf','SMSDBN');

PL/SQL procedure successfully completed.

在远程节点可以立刻检查到这个文件的存在:

SQL> ! ls -al remote_trans.dbf

-rw-r----- 1 oracle dba 10493952 Sep 1 17:16 remote_trans.dbf

进一步的,可以将远程文件读取到本地:

SQL> exec dbms_file_transfer.get_file(

'OBASE','remote_trans.dbf','SMSDBN','ASMBK','local_trans.dbf');

PL/SQL procedure successfully completed.

本地ASM存储中,马上获得了这个文件:

$ export ORACLE_SID=+ASM1

$ asmcmd

ASMCMD> cd DATADG/ASMBK

ASMCMD> ls

local_trans.dbf

trans.dbf

ASMCMD> ls -l

Type Redund Striped Time Sys Name

N local_trans.dbf =>

+DATADG/RAC/DATAFILE/FILE_TRANSFER.272.728586765 

N trans.dbf =>

+DATADG/RAC/DATAFILE/COPY_FILE.271.728582605

而进一步的,将表空间置于热备模式下,可以通过DBMS_FILE_TRANSFER包将数据库热备到远程主机,甚至可以基于此来创建远程的 Dataguard 数据库,有时在数据库巨大,备份恢复空间不足时,通过这种方式进行数据传输与备库创建未尝不是一种妙解:

SQL> alter tablespace system begin backup;

Tablespace altered.

SQL> create or replace directory odata as '+DATADG/rac/datafile/';

Directory created.

SQL> exec dbms_file_transfer.put_file(

'ODATA','system.259.722961061','OBASE','system01.dbf','SMSDBN');

PL/SQL procedure successfully completed.

SQL> alter tablespace system endbackup;

Tablespace altered.

DBMS_FILE_TRANSFER为我们提供了多一个选择和灵活性,很多时候,Oracle一个小小的增强如果能够得到恰如其分的利用,就能够发挥巨大的优势。了解了Oracle的种种可能之后,我们才能够灵活运用,如臂使指。

 

1.4.9 用户的锁定

在Oracle Database 11g的创建脚本中,存在如下一个名为lockAccount.sql的脚本,该脚本在完成数据库创建之后,将部分用户账号锁定。一个简单的FOR循环完成了这个安全加固的工作:

SET VERIFY OFF

set echo on

spool D:\oracle\admin\eyglee\scripts\lockAccount.log append

BEGIN

FOR item IN ( SELECT USERNAME FROM DBA_USERS WHERE ACCOUNT_STATUS IN ('OPEN', 'LOCKED', 'EXPIRED') AND USERNAME NOT IN ( 'SYS','SYSTEM') )

LOOP

dbms_output.put_line('Locking and Expiring: ' || item.USERNAME);

execute immediate 'alter user ' ||

sys.dbms_assert.enquote_name(

sys.dbms_assert.schema_name(

 item.USERNAME),false) || ' password expire account lock' ;

END LOOP;

END;

/

spool off

 

1.4.10 最后的脚本

在完成了主要脚本的工作之后,剩下的是一些最后的维护工作。

这里还有两个脚本需要执行,首先执行的是postScripts.sql脚本,这个脚本主要对部分用户及部分数据库选件进行维护:

connect "SYS"/"&&sysPassword" as SYSDBA

set echo on

spool C:\oracle\admin\eygle\scripts\postScripts.log

@C:\oracle\10.2.0\rdbms\admin\dbmssml.sql;

execute dbms_datapump_utl.replace_default_dir;

commit;

connect "SYS"/"&&sysPassword" as SYSDBA

alter session set current_schema=ORDSYS;

@C:\oracle\10.2.0\ord\im\admin\ordlib.sql;

alter session set current_schema=SYS;

connect "SYS"/"&&sysPassword" as SYSDBA

connect "SYS"/"&&sysPassword" as SYSDBA

alter user CTXSYS account unlock identified by change_on_install;

connect "CTXSYS"/"change_on_install"

@C:\oracle\10.2.0\ctx\admin\defaults\dr0defdp.sql;

@C:\oracle\10.2.0\ctx\admin\defaults\dr0defin.sql "SIMPLIFIED CHINESE";

connect "SYS"/"&&sysPassword" as SYSDBA

execute dbms_swrf_internal.cleanup_database(cleanup_local => FALSE);

commit;

spool off

最后执行的脚本是 postDBCreation.sql,在这个脚本中将创建 spfile,解锁 SYSMAN、DBSNMP用户,编译失效对象并配置DB Control:

connect "SYS"/"&&sysPassword" as SYSDBA

set echo on

spool C:\oracle\admin\eygle\scripts\postDBCreation.log

connect "SYS"/"&&sysPassword" as SYSDBA

set echo on

create spfile='C:\oracle\10.2.0/dbs/spfileeygle.ora'

FROM pfile='C:\oracle\admin\eygle\scripts\init.ora';

shutdown immediate;

connect "SYS"/"&&sysPassword" as SYSDBA

startup ;

alter user SYSMAN identified by "&&sysmanPassword" account unlock;

alter user DBSNMP identified by "&&dbsnmpPassword" account unlock;

select 'utl_recomp_begin: ' || to_char(sysdate, 'HH:MI:SS') from dual;

execute utl_recomp.recomp_serial();

select 'utl_recomp_end: ' || to_char(sysdate, 'HH:MI:SS') from dual;

hostC:\oracle\10.2.0\bin\emca.bat -configdbcontroldb -silent -DB_UNIQUE_NAME eygle -PORT 1521-EM_HOME C:\oracle\10.2.0 -LISTENER LISTENER -SERVICE_NAME eygle -SYS_PWD &&sysPassword -SIDeygle -ORACLE_HOME C:\oracle\10.2.0 -DBSNMP_PWD &&dbsnmpPassword -HOST gqgai -LISTENER_OHC:\oracle\10.2.0  -LOG_FILE  C:\oracle\admin\eygle\scripts\emConfig.log  -SYSMAN_PWD&&sysmanPassword; 

spool C:\oracle\admin\eygle\scripts\postDBCreation.log

exit;

看到在最后部分,通过emca.bat批处理文件,配置了DB Control,这里通过一条完整的命令快速地完成了DB Control的创建等工作,也可以通过手工方式对DB Control进行维护,关于这部分的内容请参考“第2章从OEM到Grid Control”。

此外,需要注意的是以下几句命令:

select 'utl_recomp_begin: ' || to_char(sysdate, 'HH:MI:SS') from dual;

execute utl_recomp.recomp_serial();

select 'utl_recomp_end: ' || to_char(sysdate, 'HH:MI:SS') from dual;

在Oracle 9i的postDBCreation.sql的脚本中,这部分的内容如下:

@/opt/oracle/product/9.2.0/rdbms/admin/utlrp.sql;

其实两者是相同的,utlrp.sql中主体部分与Oracle 10g中是相同的:

@@utlrcmp.sql

execute utl_recomp.recomp_serial();

Rem

=====================================================================

Rem Run component validation procedure

Rem

=====================================================================

EXECUTE dbms_registry.validate_components;

Oracle 在 utlrp.sql 脚本的注释中说得很明确:这是一个通用脚本,可以在任意时候运行,以重新编译数据库失效对象。

通常我们会在Oracle的升级指导中看到这个脚本,Oracle强烈推荐在migration / upgrade /downgrade之后,通过运行此脚本编译失效对象。但是注意,此脚本需要用SQL*Plus以SYSDBA身份运行,并且当时数据库中最好不要有活动事物或DDL操作,否则极容易导致死锁的出现。

这样使用模板创建数据库就完成了。

 

1.4.11 使用模板建库注意事项

当使用模板创建数据库时,有一点需要特别注意,那就是种子数据库的版本。因为种子数据库通常来自软件的初始分布版本,如安装Oracle Database 9.2.0,则种子数据库就是随软件发布的初始版本。如果我们安装了9.2.0再安装Patch 9.2.0.8,那么此后若使用模板种子数据库创建数据库,则数据库可能并不会自动升级为9.2.0.8的版本。

如此创建的数据库其BANNER显示为Oracle 9i Enterprise Edition Release 9.2.0.8.0:

SQL> select * from v$version;

BANNER

--------------------------------------------------------------------------------

Oracle9i Enterprise Edition Release 9.2.0.8.0 - Production

PL/SQL Release 9.2.0.8.0 - Production

CORE 9.2.0.8.0 Production

TNS for 32-bit Windows: Version 9.2.0.8.0 - Production

NLSRTL Version 9.2.0.8.0 - Production

而如果查询注册的组件会发现,大部分组件仍然是9.2.0.1的版本:

SQL> column comp_name format a35

SQL> select comp_name, status, substr(version,1,10) as version from dba_registry;

COMP_NAME STATUS VERSION

----------------------------------- ---------------------- --------------------

Oracle9i Catalog Views VALID 9.2.0.1.0

Oracle9i Packages and Types VALID 9.2.0.1.0

Oracle Workspace Manager VALID 9.2.0.1.0

JServer JAVA Virtual Machine VALID 9.2.0.1.0

Oracle XDK for Java VALID 9.2.0.2.0

Oracle9i Java Packages VALID 9.2.0.1.0

Oracle interMedia LOADED 9.2.0.1.0

Spatial LOADED 9.2.0.1.0

Oracle text VALID 9.2.0.1.0

Oracle XML Database INVALID 9.2.0.1.0

Oracle Ultra Search VALID 9.2.0.1.0

Oracle Data Mining LOADED 9.2.0.1.0

OLAP Analytic Workspace LOADED 9.2.0.1.0

Oracle OLAP API LOADED 9.2.0.1.0

OLAP Catalog INVALID 9.2.0.1.0

已选择15行。

在这样的模式下运行,数据库的状况是不可靠的,在某些条件下,因为这些组件的不完备,可能会出现错误。在以上的数据库环境中,当drop用户时可能会遇到如下错误:

SQL> drop user eygle;

drop user eygle

*

ERROR at line 1:

ORA-01001: invalid cursor

ORA-00600: internal error code, arguments: [qmxiUnpPacked2], [121], [], [], [],[], [], []

解决该问题的方法就是运行一个升级重要脚本catpatch.sql,按照以下步骤操作:

shutdown immediate

startupmigrate

spool patch.log

@?/rdbms/admin/catpatch

spool off

之后可以查看patch.log日志文件来确认升级是否成功,如果成功完成,该日志末尾会显示相关组件版本:

DOC> END Component Patches */

COMP_NAME STATUS VERSION

----------------------------------- ----------- --------------------

Oracle9i Catalog Views VALID 9.2.0.8.0

Oracle9i Packages and Types VALID 9.2.0.8.0

Oracle Workspace Manager VALID 9.2.0.1.0

JServer JAVA Virtual Machine VALID 9.2.0.8.0

Oracle XDK for Java VALID 9.2.0.10.0

Oracle9i Java Packages VALID 9.2.0.8.0

Oracle interMedia VALID 9.2.0.8.0

Spatial VALID 9.2.0.8.0

Oracle text VALID 9.2.0.8.0

Oracle XML Database VALID 9.2.0.8.0

Oracle Ultra Search VALID 9.2.0.8.0

Oracle Data Mining VALID 9.2.0.8.0

OLAP Analytic Workspace UPGRADED 9.2.0.8.0

Oracle OLAP API UPGRADED 9.2.0.8.0

OLAP Catalog VALID 9.2.0.8.0

所以在使用模板创建数据库时,一定要注意升级问题。

 

1.5 案例与实践分析

在本节中,我将与本章有关的一些案例诊断、故障分析收录于此,供读者参考。

 

1.5.1 auto_space_advisor_job_proc案例一则

在数据库创建中所提到的“预防性指导报告”就包括空间指导报告,这一定时任务在很多客户系统中带来了极大的麻烦。

在以下客户的SAP系统中,某个高负载的时段,数据库就遇到了DBMS_SCHEDULER任务的一个Bug,其数据库版本为10.2.0.2。

在SQL Ordered By Elapsed Time的采样中,Top6都是DBMS_SCHEDULER调度的任务,而且耗时显著,如图1-28所示。

图1-28 SQL Ordered By Elapsed Time的采样

处在第一位的,是auto_space_advisor_job_proc过程调用,CPU Time消耗高达4226秒:

call dbms_space.auto_space_advisor_job_proc ( )

执行花费了大量的时间,3000多秒,进而执行的SQL:

insert  into wri$_adv_objspace_trend_data select  timepoint, space_usage, space_alloc, quality  from table(dbms_space.object_growth_trend(:1, :2, :3, :4, NULL, NULL, NULL, 'FALSE', :5, 'FALSE'))

也花费了2514秒的时间,这显然是不正常的。在正常情况下,单独跟踪一下SQL*Plus中手工执行这个过程,可以获得这个SQL的执行统计信息,跟踪过程可能如下:

SQL> alter session set events '10046 trace name context forever,level 12';

SQL> call dbms_space.auto_space_advisor_job_proc ( )

SQL> alter session set events '10046 trace name context off';

格式化跟踪文件,获得以下输出,如图1-29所示。

图1-29 输出信息

注意到,这个 Insert 仍然消耗了 389 秒的时间,逻辑读 429297,性能是存在问题的。在Metalink上存在如下一个Bug:

Bug 5376783:DBMS_SPACE.OBJECT_GROWTH_TRENDCALLTAKESALOTOFDISKREADS

这个 Bug 在 DBMS_SPACE.OBJECT_GROWTH_TREND 进行空间分析时被触发,根本原因在于内部算法在执行空间检查时,耗费了大量的评估IO成本,导致了大量的IO资源使用。

临时的处理办法是,暂时关闭这个自动任务:

executedbms_scheduler.disable('AUTO_SPACE_ADVISOR_JOB');

这个Bug在10.2.0.2之后的版本中被修正。

既然Oracle的缺省定时任务可能会带来如此多的问题,我们就很有必要去关注一下系统有哪些缺省的任务,执行情况如何。以下是一个10.2.0.5版本的数据库中一些自动任务的调度设置情况:

SQL> select job_name,state,enabled,last_start_date from dba_scheduler_jobs;

JOB_NAME STATE ENABL LAST_START_DATE

------------------------------ --------------- ----- -----------------------------------

AUTO_SPACE_ADVISOR_JOB SCHEDULED TRUE 07-AUG-10 06.00.03.792886 AM +08:00

GATHER_STATS_JOB SCHEDULED TRUE 07-AUG-10 06.00.03.783957 AM +08:00

FGR$AUTOPURGE_JOB DISABLED FALSE

PURGE_LOG SCHEDULED TRUE 07-AUG-10 03.00.00.353023 AM PRC

MGMT_STATS_CONFIG_JOB SCHEDULED TRUE 01-AUG-10 01.01.01.822354 AM +08:00

MGMT_CONFIG_JOB SCHEDULED TRUE 07-AUG-10 06.00.03.767320 AM +08:00

在以上的调度任务中,GATHER_STATS_JOB是Oracle Database 10g开始引入的自动统计信息收集的任务,该任务缺省的调度是,工作日每晚22:00至凌晨6:00进行分析,周末全天进行分析。在以下输出中,我们可以看到任务无法完成,STOP的情况:

SQL> SELECT log_id, job_name, status,

2 TO_CHAR(ACTUAL_START_DATE,'DD-MON-YYYY HH24:MI') start_date,TO_CHAR (log_date, 'DD-MON-YYYY HH24:MI') log_date

3 FROM dba_scheduler_job_run_details

4 WHERE job_name = 'GATHER_STATS_JOB' order by 4;

LOG_ID JOB_NAME STATUS START_DATE LOG_DATE

---------- -------------------- -------------------- -------------------- --------------------

1480 GATHER_STATS_JOB SUCCEEDED 02-AUG-2010 22:00 03-AUG-2010 00:58

1561GATHER_STATS_JOB STOPPED   03-AUG-201022:00 04-AUG-201006:00 

1640 GATHER_STATS_JOB SUCCEEDED 04-AUG-2010 22:00 05-AUG-2010 05:36

1680 GATHER_STATS_JOB SUCCEEDED 05-AUG-2010 22:00 05-AUG-2010 22:25

1741 GATHER_STATS_JOB SUCCEEDED 06-AUG-2010 22:00 06-AUG-2010 22:27

1800 GATHER_STATS_JOB SUCCEEDED 07-AUG-2010 06:00 07-AUG-2010 06:02

384GATHER_STATS_JOB STOPPED   07-JUL-201022:00 08-JUL-201006:00 

463 GATHER_STATS_JOB SUCCEEDED 08-JUL-2010 22:00 09-JUL-2010 05:06

503 GATHER_STATS_JOB SUCCEEDED 09-JUL-2010 22:00 09-JUL-2010 22:05

544 GATHER_STATS_JOB SUCCEEDED 10-JUL-2010 06:00 10-JUL-2010 06:02

589 GATHER_STATS_JOB SUCCEEDED 12-JUL-2010 22:00 12-JUL-2010 22:04

597 GATHER_STATS_JOB SUCCEEDED 13-JUL-2010 22:00 13-JUL-2010 22:03

在一些大型数据库中,这个任务不一定能够有效执行,以下是某用户的数据库环境,输出显示,多日数据库都因为ORA-04031错误未能完成统计信息收集采样:

SQL> SELECT LOG_DATE,RUN_DURATION,JOB_NAME,STATUS,ERROR#

2 FROM DBA_SCHEDULER_JOB_RUN_DETAILS

3 WHERE JOB_NAME='GATHER_STATS_JOB'

4 order by 1 desc;

LOG_DATE RUN_DURATION JOB_NAME STATUS ERROR#

----------------------------------- --------------- ------------------ ----------- ----------

26-MAY-10 10.00.09.290291 PM +08:00 +000 00:00:05 GATHER_STATS_JOB FAILED 22303

25-MAY-10 10.00.08.973684 PM +08:00 +000 00:00:06 GATHER_STATS_JOB FAILED 4031

24-MAY-10 10.00.22.977244 PM +08:00 +000 00:00:18 GATHER_STATS_JOB FAILED 4031

22-MAY-10 06.00.16.950362 AM +08:00 +000 00:00:13 GATHER_STATS_JOB FAILED 4031

21-MAY-10 10.00.49.653788 PM +08:00 +000 00:00:47 GATHER_STATS_JOB FAILED 4031

20-MAY-10 10.00.14.028432 PM +08:00 +000 00:00:11 GATHER_STATS_JOB FAILED 4031

19-MAY-10 10.00.20.828607 PM +08:00 +000 00:00:18 GATHER_STATS_JOB FAILED 4031

19-MAY-10 05.54.27.871444 AM +08:00 +000 07:54:25 GATHER_STATS_JOB SUCCEEDED 0

18-MAY-10 05.36.01.494920 AM +08:00 +000 07:35:59 GATHER_STATS_JOB SUCCEEDED 0

15-MAY-10 07.06.05.793257 AM +08:00 +000 01:06:01 GATHER_STATS_JOB SUCCEEDED 0

15-MAY-10 03.56.50.898303 AM +08:00 +000 05:56:48 GATHER_STATS_JOB SUCCEEDED 0

在GATHER_STATS_JOB任务不能够有效地执行时,我们必须及时地介入去手工处理,不及时地统计信息可能使数据库产生错误的执行计划。

正常的AUTO_SPACE_ADVISOR_JOB调度可能应该有着类似以下输出的执行结果:

SQL> SELECT log_id, job_name, status,TO_CHAR(ACTUAL_START_DATE,'DD-MON-YYYY HH24:MI') start_date,

2 TO_CHAR (log_date, 'DD-MON-YYYY HH24:MI') log_date

3 FROM dba_scheduler_job_run_details

4 WHERE job_name = 'AUTO_SPACE_ADVISOR_JOB' order by 4;

LOG_ID JOB_NAME STATUS START_DATE LOG_DATE

---------- ------------------------- --------------- -------------------- ----------------

1460 AUTO_SPACE_ADVISOR_JOB SUCCEEDED 02-AUG-2010 22:00 02-AUG-2010 22:16

1520 AUTO_SPACE_ADVISOR_JOB SUCCEEDED 03-AUG-2010 22:00 03-AUG-2010 23:18

1600 AUTO_SPACE_ADVISOR_JOB SUCCEEDED 04-AUG-2010 22:00 04-AUG-2010 22:19

1681 AUTO_SPACE_ADVISOR_JOB SUCCEEDED 05-AUG-2010 22:00 05-AUG-2010 22:28

1740 AUTO_SPACE_ADVISOR_JOB SUCCEEDED 06-AUG-2010 22:00 06-AUG-2010 22:17

 

1.5.2 systemstate转储案例分析一则

在Oracle数据库的运行过程中,可能会因为一些异常遇到数据库挂起失去响应的状况,在这种状况下,我们可以通过对系统状态进行转储,获得跟踪文件进行数据库问题分析;很多时候数据库也会自动转储出现问题的进程或系统信息;这些转储信息成为我们分析故障、排查问题的重要依据。

在一次客户现场培训中,客户提出一个系统正遇到问题,请求我协助诊断解决,理论联系实践,这是我在培训中极力主张的,我们的案例式培训业正好遇到了实践现场。

问题是这样的:此前一个 Job 任务可以在秒级完成,而现在运行了数小时也无法结束,一直挂起在数据库中,杀掉进程重新手工执行,尝试多次,同样无法完成。

客户的数据库环境为:

Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bit Production

With the Partitioning, OLAP and Data Mining options

Node name:  SF2900 Release: 5.9 Version:  Generic_118558-33 Machine: sun4u

介入问题诊断首先需要收集数据,我最关注两方面的信息:

告警日志文件,检查是否出现过异常;

生成AWR报告,检查数据库内部的运行状况。

通常有了这两部分信息,我们就可以做出初步判断了。

检查数据库的告警日志文件,我们发现其中出现过一个如下错误:

>>> WAITED TOO LONG FOR A ROW CACHE ENQUEUE LOCK! <<<

这个错误提示出现在7点左右,正是JOB的调度时间附近,显然这是一个高度相关的可能原因。这个异常生成了转储的DUMP文件,获得该文件进行进一步的详细分析。该文件的头部信息如下:

Redo thread mounted by this instance: 1

Oracleprocessnumber:29 

Unixprocesspid:8371, image: oracleEDW@SF2900

*** 2010-03-27 06:54:00.114

*** ACTION NAME:() 2010-03-27 06:54:00.106

***MODULENAME:(SQL*Plus)2010-03-2706:54:00.106 

*** SERVICE NAME:(EDW) 2010-03-27 06:54:00.106

*** SESSION ID:(120.46138) 2010-03-27 06:54:00.106

>>>WAITEDTOO LONG FORAROWCACHE ENQUEUE LOCK!<<< 

row cache enqueue: session: 6c10508e8,mode:N, request:S 

ROW CACHE队列锁无法获得,表明数据库在SQL解析时,遇到问题,DC层面出现竞争,导致超时。Row Cache位于Shared Pool中的Data Dictionary Cache,是用于存储表列定义、权限等相关信息的。

注意以上信息中的重要内容如下。

超时告警的时间是06:54:2010-03-2706:54:00.106。

出现等待超时的数据库进程号是29:Oracle process number:29。

等待超时的29号进程的OS进程号为8317:Unix process pid:8371。

进程时通过SQL*Plus调度执行的:MODULE NAME:(SQL*Plus)。

会话的ID、Serial#信息为120.46138:SESSION ID:(120.46138)。

进程的State Object为6c10508e8:row cache enqueue:session:6c10508e8。

队列锁的请求模式为共享(S):mode:N,request: S。

有了这些重要的信息,我们就可以开始一些基本的分析。

首先可以在跟踪文件中找到29号进程,查看其中的相关信息。经过检查可以发现这些内容与跟踪文件完全相符合:

PROCESS 29:

----------------------------------------

SO:6c1006740, type: 2, owner: 0, flag: INIT/-/-/0x00

(process) Oracle pid=29, calls cur/top:6c1097430/6c1096bf0, flag: (0) -

int error: 0, call error: 0, sess error: 0, txn error 0

(post info) last post received: 109 0 4

last post received-location: kslpsr

last process to post me: 6c1002800 1 6

last post sent: 0 0 24

last post sent-location: ksasnd

last process posted by me: 6c1002800 1 6

(latch info) wait_event=0 bits=0

Process Group: DEFAULT, pseudo proc: 4f818c298

O/S info: user: oracle, term: UNKNOWN, ospid:8371

OSD pid info: Unixprocesspid:8371, image: oracleEDW@SF2900

进一步向下检查可以找到SO对象6c10508e8,这里显示该进程确实由客户端的SQL*Plus发起,并且客户端的主机名称及进程的OSPID都记录在案:

SO:6c10508e8, type: 4, owner: 6c1006740, flag: INIT/-/-/0x00

(session) sid: 120 trans: 6c285ea98, creator: 6c1006740, flag: (100041) USR/- BSY/-/-/-/-/-

DID: 0001-001D-001BC795, short-term DID: 0000-0000-00000000

txn branch: 0

oct: 2, prv: 0, sql: 4f528d510, psql: 491cbe3e8, user: 56/CACI

O/S info:user:Administrator, term:HOST03,ospid:37692:38132,machine: 

program: sqlplus.exe 

applicationname:SQL*Plus,hash value=3669949024 

接下来的信息显示,进程一直在等待,等待事件为'ksdxexeotherwait':

last wait for 'ksdxexeotherwait' blocking sess=0x0 seq=36112 wait_time=5 seconds since wait started=3

=0, =0, =0

Dumping Session Wait History

for 'ksdxexeotherwait' count=1 wait_time=5

=0, =0, =0

for 'ksdxexeotherwait' count=1 wait_time=5

=0, =0, =0

for 'ksdxexeotherwait' count=1 wait_time=3

=0, =0, =0

for 'ksdxexeotherwait' count=1 wait_time=5

=0, =0, =0

for 'ksdxexeotherwait' count=1 wait_time=4

=0, =0, =0

for 'ksdxexeotherwait' count=1 wait_time=3

=0, =0, =0

for 'ksdxexeotherwait' count=1 wait_time=4

=0, =0, =0

for 'ksdxexeotherwait' count=1 wait_time=4

=0, =0, =0

for 'ksdxexeotherwait' count=1 wait_time=3

=0, =0, =0

for 'ksdxexeotherwait' count=1 wait_time=3

=0, =0, =0

temporary object counter: 0

在这个进程跟踪信息的最后部分,有如下一个SO对象继承关系列表,注意这里的OWNER具有级联关系,下一层隶属于上一层的 Owner,第一个 SO 对象的 Owner 6c1006740 就是PROCESS 29的SO号。

到了最后一个级别的SO 4e86f03e8上,请求出现阻塞。

Row cache enqueue有一个(count=1)共享模式(request=S)的请求被阻塞:

----------------------------------------

SO:6c1096bf0, type:3,owner:6c1006740, flag: INIT/-/-/0x00

(call) sess: cur 6c10508e8, rec 6c10508e8, usr 6c10508e8; depth: 0

----------------------------------------

SO:6c1096eb0, type:3,owner:6c1096bf0, flag: INIT/-/-/0x00

(call) sess: cur 6c10508e8, rec 6c10691f8, usr 6c10508e8; depth: 1

----------------------------------------

SO:6c1097430, type:3,owner:6c1096eb0, flag: INIT/-/-/0x00

(call) sess: cur 6c10691f8, rec 6c10691f8, usr 6c10508e8; depth: 2

----------------------------------------

SO:4e86f03e8, type:50,owner:6c1097430, flag: INIT/-/-/0x00

row cache enqueue: count=1 session=6c10508e8object=4f4e57138, request=S

savepoint=0xf67b

回过头去对比一下跟踪文件最初的信息,注意这里的session信息正是跟踪文件头上列出的session信息:

>>>WAITEDTOO LONG FORAROWCACHE ENQUEUE LOCK!<<< 

row cache enqueue: session: 6c10508e8,mode:N, request:S 

至此我们找到了出现问题的根源,这里也显示请求的对象是object=4f4e57138。

跟踪文件向下显示了更进一步的信息,地址为 4f4e57138 的 Row Cache Parent Object紧跟着之前的信息显示出来,跟踪信息同时显示是在 DC_OBJECTS 层面出现的问题。

跟踪信息显示对象的锁定模式为排他锁定(mode=X)。图1-30是跟踪文件的截取,我们可以看到Oracle的记录方式:

图1-30 跟踪文件的部分信息

进一步的,跟踪文件里也显示了 29 号进程执行的SQL为INSERT操作:

SO: 4f2e82c88, type: 53, owner: 6c10508e8, flag: INIT/-/-/0x00

LIBRARY OBJECT LOCK: lock=4f2e82c88 handle=4f528d510 mode=N

call pin=0 session pin=0 hpc=0000 hlc=0000

htl=4f2e82d08[4f2de4dd8,4f2e844c0] htb=4e84c5db0 ssga=4e84c57c8

user=6c10508e8 session=6c10508e8 count=1 flags=[0000] savepoint=0x4bad2ee7

LIBRARY OBJECT HANDLE: handle=4f528d510 mtx=4f528d640(1) cdp=1

name=INSERT /*+APPEND*/ INTO CACI_INV_BLB_DCNOLOGGING SELECT :B1 , T. *, SYSDATE FROMCACI_INV_BLBT 

hash=6734e347f90993bcd607836585310c4d timestamp=03-24-2010 06:01:54

namespace=CRSR flags=RON/KGHP/TIM/PN0/MED/KST/DBN/MTX/[500100d0]

kkkk-dddd-llll=0000-0001-0001 lock=N pin=0 latch#=12 hpc=ffec hlc=ffec

lwt=4f528d5b8[4f528d5b8,4f528d5b8] ltm=4f528d5c8[4f528d5c8,4f528d5c8]

pwt=4f528d580[4f528d580,4f528d580] ptm=4f528d590[4f528d590,4f528d590]

ref=4f528d5e8[4f528d5e8,4f528d5e8] lnd=4f528d600[4f581b4d8,4f5d190a8]

LIBRARY OBJECT: object=4a7227a50

type=CRSR flags=EXS[0001] pflags=[0000] status=VALD load=0

CHILDREN: size=16

child# table reference handle

------ -------- --------- --------

0 4a7227518 4a7227188 4ae9ed1f0

1 4a7227518 4a7227420 494cd5878

DATA BLOCKS:

data# heap pointer status pins change whr

----- -------- -------- --------- ---- ------ ---

0 4aebaa950 4a7227b68 I/P/A/-/- 0 NONE 00

好了,那么现在我们来看看是哪一个进程排他的锁定了之前的 4f4e57138 对象。在跟踪文件中搜索4f4e57138就可以很容易地找到这个持有排他锁定的SO对象。

以下显示了相关信息,Row Cache对象的信息在此同样有所显示:

SO: 4e86f0508, type: 50, owner: 8c183c258, flag: INIT/-/-/0x00

row cache enqueue: count=1 session=8c005d7c8object=4f4e57138,mode=X 

savepoint=0x2716

row cache parent object: address=4f4e57138 cid=8(dc_objects)

hash=b363a728 typ=11 transaction=8c183c258 flags=00000002

own=4f4e57208[4e86f0538,4e86f0538]wat=4f4e57218[4e86f0418,4e86f0418]mode=X 

status=VALID/-/-/-/-/-/-/-/-

set=0, complete=FALSE

data=

00000038 00134944 585f4341 43495f49 4e565f42 4c425f44 43000000 00000000

00000000 04000009 505f3230 31305f51 31000000 00000000 00000000 00000000

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

00000000 00000000 00000000 000209ca ffff0000 000209ca 14786e01 020e3239

786e0102 0e323978 6e01020e 32390100 00000000 00000000 00000000 00000000

00000000 00000006

再向上找到这个进程的信息,发现其进程号为16:

PROCESS 16:

----------------------------------------

SO: 8c00037d0, type: 2, owner: 0, flag: INIT/-/-/0x00

(process) Oracle pid=16, calls cur/top: 8c0095028/8c0094aa8, flag: (0) -

int error: 0, call error: 0, sess error: 0, txn error 0

(post info) last post received: 115 0 4

last post received-location: kslpsr

last process to post me: 6c1002800 1 6

last post sent: 0 0 24

last post sent-location: ksasnd

last process posted by me: 6c1002800 1 6

(latch info) wait_event=0 bits=0

Process Group: DEFAULT, pseudo proc: 4f818c298

O/S info: user: oracle, term: UNKNOWN, ospid: 8200

OSD pid info: Unix process pid: 8200, image: oracle@SF2900 (J000)

在这里可以看到16号进程是一个JOB进程,其进程为J000,那么这个JOB进程在执行什么操作呢?下面的信息可以看出一些端倪, JOB 由 DBMS_SCHEDULER 调度,执行AUTO_SPACE_ADVISOR_JOB任务,处于Wait for shrink lock等待:

Job Slave State Object

Slave ID: 0, Job ID: 8913

----------------------------------------

SO: 8c005d7c8, type: 4, owner: 8c00037d0, flag: INIT/-/-/0x00

(session) sid: 45 trans: 8c183c258, creator: 8c00037d0, flag: (48100041) USR/- BSY/-/-/-/-/-

DID: 0001-0010-0007BFA6, short-term DID: 0000-0000-00000000

txn branch: 0

oct: 0, prv: 0, sql: 0, psql: 0, user: 0/SYS

O/S info: user: oracle, term: UNKNOWN, ospid: 8200, machine: SF2900

program: oracle@SF2900 (J000)

applicationname:DBMS_SCHEDULER,hash value=2478762354 

actionname:AUTO_SPACE_ADVISOR_JOB,hash value=348111556 

waiting for 'Wait for shrink lock' blocking sess=0x0 seq=5909 wait_time=0 seconds since waitstarted=3101 

object_id=0, lock_mode=0, =0

Dumping Session Wait History

for 'Wait for shrink lock' count=1 wait_time=380596

object_id=0, lock_mode=0, =0

for 'Wait for shrink lock' count=1 wait_time=107262

object_id=0, lock_mode=0, =0

for 'Wait for shrink lock' count=1 wait_time=107263

object_id=0, lock_mode=0, =0

for 'Wait for shrink lock' count=1 wait_time=107246

object_id=0, lock_mode=0, =0

for 'Wait for shrink lock' count=1 wait_time=107139

object_id=0, lock_mode=0, =0

for 'Wait for shrink lock' count=1 wait_time=107248

object_id=0, lock_mode=0, =0

for 'Wait for shrink lock' count=1 wait_time=107003

object_id=0, lock_mode=0, =0

for 'Wait for shrink lock' count=1 wait_time=107169

object_id=0, lock_mode=0, =0

for 'Wait for shrink lock' count=1 wait_time=107233

object_id=0, lock_mode=0, =0

for 'Wait for shrink lock' count=1 wait_time=107069

object_id=0, lock_mode=0, =0

temporary object counter: 3

进一步向下查找,可以找到Shrink操作执行的SQL语句:

SO: 4e8a2c6c0, type: 53, owner: 8c005d7c8, flag: INIT/-/-/0x00

LIBRARY OBJECT LOCK: lock=4e8a2c6c0 handle=4c3c1ce60 mode=N

call pin=0 session pin=0 hpc=0000 hlc=0000

htl=4e8a2c740[4e81436e0,4e8c80c98] htb=4e8937910 ssga=4e8936e48

user=8c005d7c8 session=8c005d7c8 count=1 flags=[0000] savepoint=0x4bad2eec

LIBRARY OBJECT HANDLE: handle=4c3c1ce60 mtx=4c3c1cf90(1) cdp=1

name=alter index "CACI"."IDX_CACI_INV_BLB_DC"modifypartition "P_2010_Q1" shrink spaceCHECK

hash=0ed1a6f7b2cf775661d314b8d1b7659b timestamp=03-25-2010 22:05:09

namespace=CRSR flags=RON/KGHP/TIM/PN0/MED/KST/DBN/MTX/[500100d0]

kkkk-dddd-llll=0000-0001-0001 lock=N pin=0 latch#=15 hpc=0002 hlc=0002

lwt=4c3c1cf08[4c3c1cf08,4c3c1cf08] ltm=4c3c1cf18[4c3c1cf18,4c3c1cf18]

pwt=4c3c1ced0[4c3c1ced0,4c3c1ced0] ptm=4c3c1cee0[4c3c1cee0,4c3c1cee0]

ref=4c3c1cf38[4c3c1cf38,4c3c1cf38] lnd=4c3c1cf50[4c3c1cf50,4c3c1cf50]

LIBRARY OBJECT: object=4aa2bf668

type=CRSR flags=EXS[0001] pflags=[0000] status=VALD load=0

CHILDREN: size=16

child# table reference handle

------ -------- --------- --------

0 49efa3fe8 49efa3c58 4c3ad91a8

1 49efa3fe8 49efa3ed8 4c3941608

DATA BLOCKS:

data# heap pointer status pins change whr

----- -------- -------- --------- ---- ------ ---

0 4c3589b38 4aa2bf780 I/P/A/-/- 0 NONE 00

至此,真相大白于天下。

(1)系统通过DBMS_SCHEDULER调度执行AUTO_SPACE_ADVISOR_JOB任务发出了SQL语句:

alter index "CACI"."IDX_CACI_INV_BLB_DC" modify partition "P_2010_Q1" shrink space CHECK

(2)定时任务不能及时完成产生了排他锁定。

(3)客户端执行的INSERT操作挂起,INSERT语句为:

INSERT /*+ APPEND*/ INTO CACI_INV_BLB_DC NOLOGGING SELECT :B1 , T. *, SYSDATE FROM CACI_INV_BLB T   

Shrink Space的语句之所以不能成功完成,是因为该索引的相关数据表的数据量过为巨大。在Oracle 10g中,缺省的有一个任务定时进行分析,为用户提供空间管理建议,在进行空间建议前,Oracle会执行Shrink Space Check,这个检查工作和Shrink的具体内部工作完全相同,只是不执行具体的动作。

这个Shrink Space的检查对于客户环境显得多余。现场解决这个问题,只需要将16号进程Kill掉,即可释放了锁定,后面的操作可以顺利进行下去。

生成数据库出现问题时段的AWR报告,也可以辅助我们确定数据库的相关操作。如图1-31所示,Top 4 SQL都运行超过了3400秒而没有完成,第一个正是任务调度。

图1-31 SQL ordered by Elapsed Time采样

相关的SQL简要列举如下:

call dbms_space.auto_space_advisor_job_proc ( )

alter index "CACI"."IDX_CACI_INV_BLB_DC" modify partition "P_2010_Q1" shrink space CHECK

而如果你不关心空间建议,则可以取消这个定时任务,避免不必要的麻烦:

execute dbms_scheduler.disable('AUTO_SPACE_ADVISOR_JOB');

这个案例给我们的经验是:当你使用新的数据库版本时,一定要认真了解其新特性,确保不会因为新特性而带来麻烦。

后记

感谢大家一页一页地读到这里,陪我走完了这段 Oracle学习之旅。

有人说写作是一件苦差事,可我觉得,这是一段宝贵的学习历程,不管你是否相信,书中的很多关键内容都是我在写作过程中忽然领悟到的,在这段日子里,也许收获最多的是我自己。所以,总结、写作实在是自我检验的一个好机会。回忆一下,从中学到大学,似乎我们都有记笔记的习惯,而毕业之后呢?这个习惯是不是被抛弃了?特别是在这个计算机盛行的时代,是不是大家也很久没有做过笔记或总结了呢?

我的Blog已经坚持写作了三年多,在这三年多中,我已经在Blog上发表了1200篇左右的文章,这些日常的笔记与总结也为我的写作积累了大量的素材。《深入浅出 Oracle——DBA入门、进阶与诊断案例》出版之后,甚至有朋友说去我的Blog看看就行了,根本不需要买书。这个评价充分说明了网络的力量。在这个时代,网络实在是一个广阔的平台,如果每个人都能在这个平台上记录与分享自己的知识,那么学习是不是就会变成一件容易和充满乐趣的事情呢?

有一个好消息要告诉读过这本书的朋友,当然也许你已经知道了,Oracle 11g 已经发布(在这本书完稿之际,Oracle 11g 仅以Beta版在流传)。自2004 年Oracle 10g发布以来,整整三个年头过去了,这三年说短不短,说长不长。对于我的Blog写作,三年实在是一个漫长的旅程,而对于软件发展来说,也许你还完全没有尝试过Oracle 10g。

这是一个如此快速前进的时代,它从来不会因为任何原因而放慢自己向前的脚步。一位朋友曾经说过,以前是不学习就会落后的时代,而现在则是学习慢了就会落后的时代。诚如所言。

对于我个人,压力随时都在肩上,而勤奋是我们最锋利的武器。

2005 年,偶然读到王小慧的作品《我的视觉日记》,感觉极为震撼,那本书我认认真真地读过很多次,略过书的内容,至今记忆犹新的是书尾列出的作者作品年表,除了众多的摄影、电影拍摄与展览活动外,王小慧几乎保持了每年二三本的作品出版速度,这需要多么大的勤奋付出以及坚持不懈啊。有一位记者曾经这样写到:在她面前你会觉得惭愧,觉得自己至多是个中等水平的人,而且是个无可救药的懒人。2006年,博文视点的周筠老师又赠送了这本书的珍藏版给我。现在,这两本书现在都成为了我的珍藏。

更让人敬佩的是另外一位大师李敖,据说他曾经每月写作一本书,连续写了十年。这些天才横溢的大师尚且如此勤奋,而我们,唯有更加努力。

所以,虽然是在与文学完全不同的技术道路上,我还是要将两个字作为本书最后的分享:勤奋。

盖国强(Eygle)

2007年7月 于北京

新版后记

不知道这一本书还有没有下一次的修订机会,但是每一行字写下去,我都当是最后一次机会,也许这些字落到纸上,就再也没有修改的机缘,我对于人生的态度也是如此。

从2000年大学毕业到如今,接触Oracle也已经有10多年的历史,走上这条路,直到今天,我想最大的原因还是因为兴趣,我一直能够从学习中获得尊重与乐趣,并且能够从知识分享中获得快乐,最重要的,技术能够持续改变着我的生活,使得我对明天更有信心,我相信在任何一个行业里坚持不懈的走上十年,都能够有让自己满意的体验。

在2011年1月底,我和Kamus(张乐奕)一同前往旧金山参加了一次Oracle用户组的全球峰会,会议的内容不是最重要的,最重要的是我们在那里度过了一个愉快的假期,有一个下午我们骑着自行车沿着旧金山的海边,直上金门大桥,行到对岸远眺天空、海洋与城市,那个下午,我想我对生活有了新的认识:在那里到处都有跑步、骑车,带着家人与宠物悠闲漫步的人们,在大海边,无比蔚蓝的天空下,我想,我们的生活除了工作,还要有这样的悠闲与惬意。不论在任何一个地方,在任何环境下,我们都要有快乐生活的勇气与能力,虽然这个社会给予的压力使得人们越来越加浮躁。

愿我的读者们都能拥有快乐的生活,让我们一起为此而努力吧,而在这一路上,但愿有Oracle相伴!

盖国强(Eygle)

2011年5月 于北京

图书在版编目(CIP)数据

循序渐进Oracle:数据库管理、优化与备份恢复/盖国强著.--北京:人民邮电出版社,2011.8

ISBN 978-7-115-25317-0

Ⅰ.①循… Ⅱ.①盖… Ⅲ.①关系数据库—数据库管理系统,Oracle Ⅳ.①TP311.138

中国版本图书馆CIP数据核字(2011)第077228号

内容提要

本书从基础知识入手,详细讨论了Oracle数据库的创建、从OEM到Grid Control、Oracle的字符集、用户的创建与管理、表空间和数据文件、自动存储管理(ASM)、临时表空间和临时文件、备份与恢复、备份方案与特例恢复、Oracle的闪回特性、Oracle的数据加载与卸载、从Statspack到ADDM、故障诊断及分析方法等热点问题,并通过大量取自实际工作现场的实例,力图将Oracle知识全面、系统、深入地展现给读者。

本书在分析实例的过程中,兼顾深度与广度,不仅对实际问题的现象、产生原因和相关的原理进行了深入浅出的讲解,更主要的是,结合实际应用环境,提供了一系列解决问题的思路和方法,包括详细的操作步骤,具有很强的实战性和可操作性。

本书适用于数据库管理人员、数据库开发人员、系统维护人员、数据库初学者及其他数据库从业人员,也可以作为各大中专院校相关专业的参考用书和相关培训机构的培训教材。

循序渐进Oracle:数据库管理、优化与备份恢复

♦ 著 盖国强

责任编辑 杜洁

♦ 人民邮电出版社出版发行  北京市崇文区夕照寺街14号

邮编 100061  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

三河市海波印务有限公司印刷

♦ 开本:787×1092 1/16

印张:42.5

字数:1099千字  2011年8月第1版

印数:1–4000册  2011年8月河北第1次印刷

ISBN 978-7-115-25317-0

定价:89.00元

读者服务热线:(010)67132692 印装质量热线:(010)67129223

反盗版热线:(010)67171154

相关图书

Oracle从入门到精通
Oracle从入门到精通
Oracle 12c数据库应用与开发
Oracle 12c数据库应用与开发
Oracle PL/SQL程序设计(第6版)(上下册)
Oracle PL/SQL程序设计(第6版)(上下册)
Oracle PL/SQL必知必会
Oracle PL/SQL必知必会
Oracle性能优化与诊断案例精选
Oracle性能优化与诊断案例精选
Oracle数据库管理与维护实战
Oracle数据库管理与维护实战

相关文章

相关课程