csdn emag(oracle)第一期

131
http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期 1 131

Upload: yiditushe

Post on 31-May-2015

1.817 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

第 1 页 共 131 页

Page 2: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

CSDN Oracle 电子杂志创刊号

本期内容导读

篇首寄语

几句需要说在前面的话.

基础篇

书写历史的甲骨文-ORACLE 公司传奇 -- By Fenng Oracle 公司作为全球第二大软件公司无疑已经成为一个 IT 界的传奇,Fenng 这篇文章

为我们介绍了这个值得尊敬的公司的历史。

开发篇

判断某个字符串是否为数字的方法 -- By bzszp 开发中的一些常用技巧,这样的问题,几乎每个开发人员在走过的路上都曾经遇到...

使用 sql 语句直接生成带有'小计','合计'的数据集 -- By bzszp SQL 的常用小技巧

Oracle 中的进制转换 By eygle 在开发过程中,我们经常会遇到不同进制之间转换的问题,本文收集了集中常见的用

法供大家参考。

C#+Oracle 开发中执行存储过程问题 -- By dinya 当前开发过程中,微软的.NET+Oralce 是常见的架构,在开发过程中很多时候需要通

过前台程序调用数据库中的一些对象,本文以一个实例的形式,对 C#+Oracle 数据库的开

发中 C#执行 Oracle 存储过程问题做一简要阐述。

性能调整篇

Oracle 诊断案例-如何捕获问题 SQL 解决过度 CPU 消耗问题 -- By eygle

第 2 页 共 131 页

Page 3: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

在数据库管理中,经常会遇到 CPU 过度消耗的问题,这一类问题通常是因为不良 SQL

代码引起的,本文对于这一类问题的解决给出了通用的处理办法,通过实际案例的介绍,

希望能给大家提供一些解决类似问题的参考。

关于 Oracle 数据库中行迁移/行链接的问题性能影响及解决 -- By Coolyl 行迁移/行链接是经常会遇到,因此而带来的性能影响很多时候是不容忽略的,Coolyl

的文章详细分析了行迁移/行链接的产生原因,以及如何消除。

关于索引使用情况的研究 -- By bzszp 关于索引使用的一些探索和研究,在开发和系统设计中索引无疑都是非常重要的一个

环节,希望大家能从本文中对于索引的作用及常见问题有所了解.

Oracle SQL 优化手册 -- By snowywolf 这是雪狼翻译的作品,原书 Oracle SQL Tuning Pocket Reference 无疑是一部广为人知

的作品。

我们期待雪狼完成全部作品的翻译,提供给大家更精彩的内容。

Oracle 高可用性篇

Oracle9i 数据库 DataGuard 实施及维护手册 -- By kamus 从 standby 到 DataGuard,Oracle 在高可用性方面又作了一个巨大的提高,DataGuard

在可管理性、可靠性、性能等方面都得到了提高,Kamus 在这篇文章中对于 DataGuard 的

实施和维护作了详尽的描述。

Oracle 深入研究篇

32bit Oracle SGA 扩展原理 和 SGA 与 PGA 的制约关系 -- By biti_rainy 通常我们知道,32 位的 Oracle 在默认情况下 Oracle SGA 不能超过 1.7g。那么为什么

存在这样的限制?可以怎样突破这些限制? Biti_rainy从内部原理上探索了这些限制的原

因。

关于 shared pool 的深入探讨 -- By eygle Shared pool 是 SGA 设置中 为复杂和重要的,而 SGA 设置过大很多时候会给数据库

带来很大的负面影响。Eygle 在本文及系列文章中深入探讨了 Oracle Shared pool 的内部管

理机制,揭示了 Shared Pool 的分配、作用等内部原理。

第 3 页 共 131 页

Page 4: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

目 录

CSDN ORACLE电子杂志创刊号 .........................................................................................................2

本期内容导读 ..................................................................................................................................2 篇首寄语 ..........................................................................................................................................6 编者的话 ..........................................................................................................................................7 书写历史的甲骨文 ..........................................................................................................................8

ORACLE公司之起源.......................................................................................................8 发展与壮大.......................................................................................................................9 经受挫折.........................................................................................................................12 跨上巅峰.........................................................................................................................13 历史还在继续.................................................................................................................14

判断某个字符串是否为数字的方法.............................................................................................15 使用sql语句直接生成带有’小计’,’合计’的数据集.........................................................17 Oracle中的进制转换 ....................................................................................................................19

一 16 进制转换为 10 进制............................................................................................19 二 10 进制转换为 16 进制............................................................................................19 三 2 进制转换为 10 进制..............................................................................................20 四 通过自定义函数实现进制转换 ...............................................................................20

C#+Oracle开发中执行存储过程问题 ..........................................................................................23 1、在数据库中建一用户表及用户ID的序列:...........................................................23 2、在Oracle中建执行插入操作的存储过程: ............................................................24 3、在.NET项目建一个到数据库的联结: ..................................................................25 4、在类文件中添加如下内容,用来执行Oracle中的过程: ....................................25 5、在窗体界面中调用执行存储过程 ...........................................................................27 后记:.............................................................................................................................27

Oracle诊断案例--如何捕获问题SQL解决过度CPU消耗问题.....................................................29 1.登陆数据库主机..........................................................................................................29 2.使用Top命令 ...............................................................................................................30 3.检查进程数量..............................................................................................................30 4.检查数据库..................................................................................................................31 5.捕获相关SQL ..............................................................................................................35 6.决定创建新的索引以消除全表扫描 ..........................................................................38 7.观察系统状况..............................................................................................................39 8.性能何以提高? ............................................................................................................40 结语: ...............................................................................................................................42

关于Oracle数据库中行迁移/行链接的问题...............................................................................44 一、行迁移/行链接的介绍............................................................................................44 二、行迁移/行链接的检测............................................................................................50 三、行迁移和行链接的清除.........................................................................................53

方法一:传统的清除行迁移的方法 .....................................................................54 方法二:改进了的传统清除行迁移的方法 .........................................................56

第 4 页 共 131 页

Page 5: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

方法三:使用TOAD工具清除行迁移的方法 ......................................................58 方法四:使用EXP/IMP工具清除行迁移的方法 .................................................59 方法五:使用MOVE命令来清除行迁移的方法 .................................................61 方法六:对于一些行迁移数量巨大而且表记录数巨大的表的行迁移的清除方法

.................................................................................................................................62 关于索引使用情况的简单测试.....................................................................................................67 Oracle SQL优化手册 ....................................................................................................................76

前言.................................................................................................................................76 一.Oracle 9i的新特性 ..................................................................................................76 二.SQL优化器 .............................................................................................................78

2.1 理解RBO .........................................................................................................78 2.2 理解CBO .........................................................................................................83 2.3 对优化器的一些常见的误解 ..........................................................................89 2.4 选择合适的优化器..........................................................................................90

Oracle9i数据库Data Guard实施及维护手册 ............................................................................91 一.Data Guard介绍 ......................................................................................................91

RAC (Oracle Real Application Cluster)..................................................................91 高级复制(Advanced Replication )..........................................................................92 Data Guard ..............................................................................................................93

二.Data Guard类型的比较 ..........................................................................................93 物理备用库(Physical Standby): .......................................................................94 逻辑备用库(Logical Standby):.........................................................................94 大数据保护模式(MAXIMIZE PROTECTION)...........................................95 大可用性模式(MAXIMIZE AVAILABILITY) ............................................95 大性能模式(MAXIMIZE PERFORMANCE) ..............................................96

ARCH方式..............................................................................................................96 LGWR方式 .............................................................................................................96

三.硬件配置.................................................................................................................98 四.软件配置.................................................................................................................98 五.实施Data Guard前提条件和注意事项 ..................................................................98 六.实施步骤.................................................................................................................99

Physical Standby配置 .............................................................................................99 使用Data Guard Broker ........................................................................................105

七.在Cluster环境中的主备切换步骤 .......................................................................108 八.参考文档...............................................................................................................109

32bit oracle SGA 扩展原理 和 SGA与PGA的制约关系 ........................................................110 关于shared pool的深入探讨(之一) ....................................................................................121

(一)基础知识...........................................................................................................121 (二)Oracle8i中的管理方式 .....................................................................................122 (三)Oracle9i中的shared pool管理方式...................................................................123 (四)总结...................................................................................................................129

第 5 页 共 131 页

Page 6: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

篇首寄语

CSDN 网络总监 韩磊

3 年前,当我开始做一个 Delphi 技术资料网站时,曾经把“出一本杂志”作为奋斗目标

之一;来到 CSDN 的运营公司后,在参与杂志编辑的过程中,常常听到读者要求出版专业技

术期刊的呼声。读者需求不可谓不强烈,我们也曾尝试在《程序员》杂志之外,在更专业的

领域尝试出版期刊(例如《MSDN 开发精选》就是专注微软技术),现在看来并不是完全成功。

杂志要生存和获利,不外乎靠广告或发行量。以国内 IT 界目前环境来说,专注于某个

特定技术领域的纸质杂志,发行量基本不可能达到盈亏平衡点,且广告主对太专业杂志的投

入也相当有限。一方面是读者的强烈需求,另一方面却必须面对亏损的尴尬——中国专业技

术期刊何去何从?

我们曾对比网络媒体和纸质媒体的特性,并得出一些有趣的结论。例如,网站每天浏览

量可能过百万,但摊到每篇文章,也许就只有数千;而一本杂志发行量可能只有数万,但单

篇文章被阅读的机会却大了很多。

网络媒体的特点是:知识可以被方便地创造、传播和复制。我们考虑:能否把网络媒体

和传统纸质杂志相结合,走一条独特的知识传播路径呢?于是,CSDN 社区电子期刊计划应

运而生。在这面旗帜下,将出现多本电子杂志,涵盖Oracle、SQL Server、VC++、Web开发、.NET、

Java 等多个专业技术领域。

CSDN 社区电子杂志来自社区(编辑都是 CSDN 网友,许多内容资源也来自 CSDN 社区),

服务社区(免费下载阅读),体现了“知识共创共享”的理念。未来社区电子杂志也存在一

些商业模式,但这两条是必须坚持的。

Oracle 杂志作为这个项目的第一项成果,凝聚了网友编辑们的心血和汗水。在没有得到

应有回报的情况下,全力投入做出这样一本精品电子杂志,真令人钦佩和赞赏!我们承诺,

根据需要,投入更多人力物力,让社区电子期刊计划得以维持和发展。

在此,我代表 CSDN.NET 运营方,对 CSDN 社区电子期刊 Oracle 杂志的顺利创刊致以热

烈的祝贺,并对所有参与编辑这本杂志的网友致以谢意。愿 Oracle 杂志这只领头羊再接再

厉,愿其他电子杂志早日面世,愿更多的网友参与到社区电子期刊的编辑工作中来。社区是

网友的社区,电子期刊是网友的期刊,让我们都来为社区的繁荣做出贡献吧!

2004 年 11 月 9 日

第 6 页 共 131 页

Page 7: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

编者的话

本刊主编 Eygle

从 2004.10.11 开始筹划 CSDN 的 Oracle 电子杂志,到现在第一期杂志编辑完毕。将近

一个月的时间过去了。

一本杂志从策划、定位、筹稿、编辑到发布,我们花费了大量的时间和精力,那么当这

样一期杂志呈现在大家面前的时候,到底能获得怎样的评价和认同,我们的心底是满怀激动

却又惴惴不安的。在期待赞许的同时我们也同样期待大家的批评,而我们更希望的是越来越

多的朋友参与到 Oracle 杂志的中来, 终把杂志做成我们大家的朋友。

这一期杂志,是 CSDN Oracle 电子杂志的创刊号,准备时间及编辑都显仓促,不足在所

难免,我们期待大家的反馈。

任何批评、建议及投稿你都可以发送到:

[email protected]

在你读完这期杂志以后,如果能够觉得有所收获,我们将感到无比欣慰。

闲言少叙, 后让我们感谢为此杂志付出努力的朋友们,也就是 Oracle 杂志所有的编辑

们,没有他们这期杂志不可能如此快的同大家见面,他们是:

biti_rainy, bzszp, chanet, coolyl, dinya

eygle, Fenng, j2eexin, kamus, simore, snowywolf

关于编辑的具体情况你可以在杂志首页找到详细的介绍。

http://emag.csdn.net/Default.aspx?tabid=49

2004-11-07

第 7 页 共 131 页

Page 8: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

书写历史的甲骨文

―ORACLE 公司传奇

By Fenng

ORACLE 公司之起源

很难想象,ORACLE 公司的这一段传奇居然要从 IBM 开始。

1970年的6月,IBM公司的研究员埃德加·考特 (Edgar Frank Codd) 在Communications

of ACM 上发表了那篇著名的《大型共享数据库数据的关系模型》(A Relational Model of

Data for Large Shared Data Banks)的论文。这是数据库发展史上的一个转折。要知道,

当时还是层次模型和网状模型的数据库产品在市场上占主要位置。从这篇论文开始,拉开了

关系型数据库软件革命的序幕。

虽然早在 1970 年就诞生了关系模型理论,但是市场上迟迟不见关系型数据库管理软件

的推出。主要原因是很多反对者认为关系型数据库速度太慢,比不上当时的层次式数据库。

值得好笑的是,IBM 虽然 1973 年就启动了 System R 的项目来研究关系型数据库的实际可行

性,也没有及时推出这样的产品,因为当时 IBM 的的 IMS(著名的层次型数据库)市场不错,

如果推出关系型数据库,牵涉到 IBM 很多人的自身利益。再者,IBM 庞大复杂的官僚机构处

在决策上远不那么灵活。

1977 年 6 月,Larry Ellison 与 Bob Miner 和 Ed Oates 在硅谷共同创办了一家名为软

件开发实验室(Software Development Laboratories,SDL)的计算机公司(ORACLE 公司

的前身)。那个时候,32 岁的 Larry Ellison,这个读了三家大学都没能毕业的辍学生,还

只是一个普通的软件工程师。公司创立之初,Miner 是总裁,Oates 为副总裁,而 Ellison,

因为一个合同的事情,还在另一家公司上班。没多久,第一位员工 Bruce Scott(用过 ORACLE

数据库软件的人都知道有个 Scott 用户的吧?没错,就是这个 Scott,至于 Scott 用户的密

码 Tiger,那是 Scott 养的猫的名字)加盟进来,在 Miner 和 Oates 有些厌倦了那种合同式

的开发工作后,他们决定开发通用软件,不过们还不知道自己能开发出来什么样的产品。

Oates 先看到了埃德加·考特的那篇著名的论文连同其他几篇相关的文章并推荐 Ellison

和 Miner 也阅读一下。Ellison 和 Miner 预见到数据库软件的巨大潜力(跟着 IBM 走,没错),

于是,SDL 开始策划构建可商用的关系型数据库管理系统(RDBMS)。

很快他们就弄出来一个不太像样的产品,或者具体的说,更像一个 Demo。根据 Ellison

和 Miner 他们在前一家公司从事的一个由中央情报局投资的项目代码,他们把这个产品命名

为 ORACLE。因为他们相信,ORACLE(字典里的解释有“神谕, 预言”之意)是一切智慧的

源泉。1979 年,SDL 更名为关系软件有限公司(Relational Software,Inc.,RSI),毕竟

“软件开发实验室”不太像一个大公司的名字。1983 年,为了突出公司的核心产品,RSI

再次更名为 ORACLE。

第 8 页 共 131 页

Page 9: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

图1 美国 ORACLE 公司总部一瞥

发展与壮大

RSI 在 1979 年的夏季发布了可用于 DEC 公司的 PDP-11 计算机上的商用 ORACLE 产品,这

个数据库产品整合了比较完整的 SQL 实现,其中包括子查询、连接及其他特性。但不得不说,

软件不是很稳定,并缺少事务处理这样的重要功能。出于市场策略,公司宣称这是该产品的

第二版,但却是实际上的第一版。之所以被命名为第 2 版而不是第 1 版,是因为 Ellison

认为潜在的客户更愿意购买第 2 个版本,而不是初始版本。(虽然这样做有些不太诚实,还

是要承认这是个十分高明的技巧。到现在还有一些公司把自己卖给客户的版本叫做 1.0 ,

学学 1979 年的 ORACLE 吧!) 多年以后的今天,ORACLE 公司声称是他们第一个提供了第一

个 SQL 关系型数据库管理系统。

虽然软件不是很好,但是客户还是有的。美国中央情报局迫不及待的想买一套这样的软

件来满足他们的需求。但在咨询了 IBM 公司之后发现 IBM 没有可以商用的产品,他们联系了

RSI。于是 RSI 有了第一个客户。在当时,政府和军方的机构往往同时有几种计算机,而那

时还没有什么“软件可移植”这样的说法,当然,也几乎没有具有这样的能力的应用软件。

也就是说,给 PDP-11 开发的 ORACLE 数据库不能用在 IBM 主机和 DEC 的 VAX 上。很快用户就

表现出来这样的需求:ORACLE 能否同时在不同的操作系统上运行?这给 RSI 带来了新的挑

战(主要是 Miner 和 Scott)。70 年代末期和 80 年代早期的软件一般都设计成在单一操作系

统上运行,具有可移植能力的软件很少。

第 9 页 共 131 页

Page 10: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

1983 年 3 月,RSI 发布了 ORACLE 第三版。Miner 和 Scott 历尽艰辛用 C 语言重新写就这

一版本。要知道,C 语言当时推出不久,用它来写 ORACLE 软件也是具有一定的风险的,但

除此之外,别无他法。很快就证明了这样做是多么的正确,C 编译器便宜而又有效。从现在

起,ORACLE 产品有了一个关键的特性:可移植性。ORACLE 第 3 版还推出了 SQL 语句和事务

处理的“原子性”――SQL 语句要么全部成功,要么全部失败,事务处理要么全部提交,要

么全部回滚。ORACLE 第 3 版还引入了非阻塞查询,使用存储在"before image file"中的数

据来查询和回滚事务,从而避免了读锁定(read lock)的使用(虽然通过使用表级锁定限

制了它的吞吐量)。同样是 1983 年,IBM 发布了姗姗来迟的 Database 2(DB2),但只可在

MVS 上使用。不管怎么说,ORACLE 已经占取了先机。

在开发第三版还没有结束的时候,Scott 离开了 ORACLE。当时用 C 改写 ORACLE 的压力

很大,无休止的软件调试终于让 Scott 不堪重负,选择了一走了之。把剩下的重担交给了

Miner 一个人。在出售了自己的%4 的股票之后,Scott 后来创建了 Gupta 公司(现更名为

Centura Software)和 PointBase 公司(提供百分之百纯 Java 嵌入式数据库),都是开发和

数据库相关的产品。多年后有人问到他的%4 的 ORACLE 股票的时候,Scott,这个曾经给

ORACLE 写出第一行代码的技术高手,也只能报以一笑了。如果能坚持下来,那是一笔几亿

美金的财富。不过当时的 Scott 没有那么多的想法,他只是太累了。

图二 Bruce Scott 现在是 PointBase 公司的发起人之一

ORACLE 先将其软件移植到 DEC VAX 计算机上的 VMS 操作系统上。早在 1979 年公司就

已经雇了一位 DEC 公司的技术高手 Robot Brandt 进行 VAX 上 ORACLE 的开发。开始的时候资

金有限,只能到加州大学伯克利分校去蹭机器进行开发,后来好一些,但机器也是借来的。

尽管困难重重,Brandt 还是比较成功的完成了移植工作。随着 VAX 小型机的大量销售乃至

供不应求,ORACLE 软件也成为 VAX 上 受欢迎的程序。这一点要归功于 Larry 对市场的先

知先觉。如果说,是 IBM 引领着 ORACLE 公司走上数据库的大船,那么 DEC 公司的 VAX 就是

带着他们扬帆出海了。短短的几年之后,ORACLE 数据库被移植到各种主要平台之上。 ORACLE

产品也一直因为有可移植性这个关键特性而被那些潜在的客户关注。

Oates 这个时候因为婚姻趋于破裂而情绪沮丧,已经不能把精力全部放到公司上,不得

不离开公司。几年后,他又重返公司,重新为 ORACLE 带来巨大的贡献,他许下诺言,在公

司员工超过 1 万人的时候会再度离开。1999 年,他完成了心愿。现在他正在纵情于音乐,

自得其乐。

很长一段时间里,公司研发由 Miner 独力承担。Miner 视金钱如无物,为人低调,和

Ellison 的锋芒必露形成鲜明的对比。在公司里,大家一致认为他是老好人,他也深受员工

爱戴。Ellison 是公司的大脑,Miner 则当之无愧的成为公司的心脏。他是个沉默的英雄,

正如 Steve Jobs 背后的 Steve Wozniak 一样。

1984 年 10 月,ORACLE 发布了第 4 版产品。产品的稳定性总算得到了得到了一定的增强,

第 10 页 共 131 页

Page 11: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

用 Miner 的话说,达到了“工业强度”。但是还不够令人满意,用户对产品的抱怨似乎永无

休止。这一版增加了读一致性(read consistency),这是数据库的一个关键特性,可以确

保用户在查询期间看到一致的数据。也就是说,当一个会话正在修改数据时,其他的会话将

看不到该会话未提交的修改。可以看到,在 ORACLE 第四版之前,产品始终是不稳定的,但

是 ORACLE 的这群销售人员,主要是 Ellison,他在宣传 ORACLE 的时候总是要夸大其词,但

他就是有能力把软件卖出去,而且,还卖得很好,不得不承认,这的确有些神奇。让我们看

看 1984 年软件市场的情形,在数据库市场上的霸主是 Asnton-Tale 公司,他们的拳头产品

是刚推出不久的 dBase III(确切的说 dBase 是 PC 上的数据库软件霸主),刚刚成为全球第

三大的独立软件公司(第一和第二分别是微软、Lotus,ORACLE 在当时还排不上号),这一

年,也是苹果公司 Macintosh 诞生的年度,Steven Jobs 用这个拳头产品挑战老大哥 IBM。

同样在这一年中,ORACLE 公司的开发人员刚刚把产品移植到 PC 上。这是 好的年代,也是

坏的年代。数以千计的小公司在软件领域里争斗不休,新公司如雨后春笋般成立,ORACLE

如何才能于不败之地?

在 1985 年,ORACLE 发布了 5.0 版。有用户说,这个版本算得上是 ORACLE 数据库的稳定

版本。这也是首批可以在 Client/Server 模式下运行的的 RDBMS 产品,在技术趋势上,ORACLE

数据库始终没有落后。这意味着运行在桌面 PC 机(客户机)上的商务应用程序能够通过网

络访问数据库服务器。1986 年发布的 5.1 版还支持分布式查询,允许通过一次性查询访问

存储在多个位置的数据。

那是在 1985 年,当时曾经的 大的独立软件公司 Cullinet(主要销售网状数据库)已经

如流星般陨落。ORACLE 的主要竞争对手是 Ingres 数据库。Ingres 在加州大学伯克利分校诞

生,主要的设计者是当时鼎鼎大名的 Michael Stonebraker 教授。 可以说 Ingres 数据库软

件是上个世纪 80 年代技术上 好的数据库,Ingres 市场分额的快速增长已经给 ORACLE 早

成了很大的压力。巧的是,这个时候,IBM 公司再一次伸出“上帝之手”。

Ingres 使用的是 Stonebraker 发明的 QUEL(Query Language))的查询技术,这和 IBM

的 SQL 大不相同。在某些地方 QUEL 甚至要优于 SQL。IBM 当时担心 Ingres 把 QUEL 变成标准

会对自己不利。经过一番衡量,决定把自己的 SQL 提交给数据库标准委员会。而 Stonebraker

教授可不打算把 QUEL 提交给数据库标准委员会,学院派的他认为这麽做实际上是扼杀了创

新精神。鹬蚌相争,渔翁得利。ORACLE 看到并抓住了这个绝佳的机会,大肆宣布 ORACLE 全

面与 SQL 兼容,加上 ORACLE 当时对 Ingres PC 上的版本的攻击(弱化对手优势,化解自己

弱势是他们 拿手的本领),再加上 ORACLE 公司销售上的强势,Ingres 不断丢城失地,等

到后来推出支持 SQL 的数据库的时候为时已晚。紧跟 IBM 让 ORACLE 得以成长、壮大,拥抱

标准,拥抱开放,拥抱变化,让 ORACLE 立于不败之地。

1986 年 3 月 12 日,ORACLE 公司以每股 15 美元公开上市,当日以 20.75 美元收盘,公

司市值 2.7 亿美元。3 月 13 日,微软以每股 21 美元的发行价上市,以 28 美元收市,公司

市值达到 7 亿美元。远远超过了 ORACLE。成功的光环下的微软和盖茨遮盖住了 ORACLE 和

Ellison 的光芒,可能这也是 Ellison 敌视微软的开始。

第 11 页 共 131 页

Page 12: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

图三 桀骜不驯的 Larry Ellison

经受挫折

ORACLE 第 6 版于 1988 年发布。由于过去的版本在性能上屡受诟病,Miner 带领着工程

师对数据库核心进行了重新的改写。引入了行级锁(row-level locking)这个重要的特性,

也就是说,执行写入的事务处理只锁定受影响的行,而不是整个表。这个版本引入了还算不

上完善的 PL/SQL(Procedural Language extension to SQL)语言。第 6 版还引入了联机

热备份功能,使数据库能够在使用过程中创建联机的备份,这极大地增强了可用性。同时在

这一年,ORACLE 开始研发 ERP 软件。

公司发展看上去比较顺利,不过,噩梦才刚刚开始。

由于过去对软件测试重视的程度不够――那个时候公司规模小,基本上都是客户帮助免

费测试的。在第六版刚发布之后,很多迫不及待开始使用的用户就怨声载道。这是个根本就

没有测试好就进行发布的产品(也怪 Ellison,大话总要说在前头,只好自尝苦果)。用户

开始对 ORACLE 大肆抨击,ORACLE 的一些对手,也开始落井下石,针对 ORACLE 产品的一些

弱点进行攻击。开发人员一面应付愤怒的用户,一面加班加点地对程序进行接连不断的修正,

后,总算得到了一个比较稳定的版本,暂时平息了用户的愤怒。

但是,实际的问题并不在这里,几年来高速增长的同时也给公司带来了巨大的隐患,1990

财年第三季度报表的公布引爆了一切。财务人员发现了 1500 万美元的坏帐,并且公司利润

第 12 页 共 131 页

Page 13: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

距离预期相差甚远。接下来的时间里,大公司病的诸般症状接踵而来,面对股东的指控,股

票一落千丈,公司前景暗淡,甚至面临破产。一度靠贷款来维持自己的奢华生活也不变卖股

票的 Ellison 也快撑不住了。公司下大力气整顿财务(财务主管杰夫·沃克从某种程度上解

救了公司)。公司宣布削减开支,裁退大量销售人员,同时聘用了专门的管理人才。

噩梦延续到 ORACLE 第七版的推出而结束。这个公司已经空谈了好几年的新版本(一度

被讥讽为不过是 Ellison 的故计重施而已),直到 1992 年 6 月才终于闪亮登场,这一次公司

吸取了第六版匆忙上市的教训,听取了用户的多方面的建议,并集中力量对新版本进行了大

量而细致的测试。该版本增加了许多新的性能特性:分布式事务处理功能、增强的管理功能、

用于应用程序开发的新工具以及安全性方法。ORACLE7 还包含了一些新功能,如存储过程、

触发过程和说明性引用完整性等,并使得数据库真正的具有可编程能力。

ORACLE 第七版是 ORACLE 真正出色的产品,取得了巨大的成功。这个版本的出现真是好

时机,当时 Sybase 公司的数据库已经占据了不少份额,ORACLE 借助这一版本的成功,一具

击退了咄咄逼人的 Sybase。公司的销售人员这次算到了给用户兑现空头许诺的时候。公司

经过两三年的治理,终于摆脱了种种麻烦,重新开始健康发展,销售额也从 92 年的 15 亿美

元变为四年后的 42 亿美元。

跨上巅峰

“搅浑水”是 Ellison 的一项绝技。在 1995 年巴黎举行的欧洲信息技术论坛会议上,

Ellison 在即兴演讲中介绍了网络计算机(Network Computer,NC)的概念,所谓 NC 指的是

配置简单却能充分利用网络资源的低价电脑, 为重要的是,它不需要操作系统,或者更准

确的说,不需要微软的操作系统。Ellison 希望借此来抵制微软的强势。很快,ORACLE 联合

IBM、Sun、Apple 和 Netscape 在 1996 年制定了网络计算机的标准,但事实上人们从头到尾

没有看到一台真正的 NC 生产出来。这次的演讲在业界引起了轩然大波,通过这个事件,

ORACLE 公司吸引了足够多的注意力,同时也让人们看到 ORACLE 公司对于网络的巨大信心。

1997 年 6 月,ORACLE 第八版发布。ORACLE8 支持面向对象的开发及新的多媒体应用,这

个版本也为支持 Internet、网络计算等奠定了基础。同时这一版本开始具有同时处理大量

用户和海量数据的特性。这个版本也算是可圈可点了。

1998 年 9 月,ORACLE 公司正式发布 ORACLE 8i。“i”代表 Internet,这一版本中添加

了大量为支持 Internet 而设计的特性。这一版本为数据库用户提供了全方位的 Java 支持。

ORACLE 8i成为第一个完全整合了本地Java运行时环境的数据库,用Java就可以编写ORACLE

的存储过程。对,Java,只要是能够打击微软的武器,ORACLE 都要派上用场。ORACLE8i 添

加了 SQLJ(一种开放式标准,用于将 SQL 数据库语句嵌入客户机或服务器 Java 代码)和

ORACLE interMedia(用于管理多媒体内容)以及 XML 等特性。同时,ORACLE 8i 极大程度

上提高了伸缩性、扩展性和可用性以满足网络应用需要。接下来的几年中,ORACLE 陆续发

布了 8i 的几个版本,并逐渐添加了一些面向网络应用的新特性。面对开源运动的蓬勃发展,

ORACLE 自然不甘落后,1998 年十月 ORACLE 发布了可用于 Linux 平台的 ORACLE 8 以及

ORACLE Application Server 4.0,随后不久,ORACLE 又发布了 ORACLE 8i for Linux。在 .com

第 13 页 共 131 页

Page 14: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

大潮中,ORACLE 是站在风口浪尖的弄潮儿。

在 2001 年 6 月的 ORACLE OpenWorld 大会中,ORACLE 发布了 ORACLE 9i。在 ORACLE 9i

的诸多新特性中, 重要的就是 Real Application Clusters(RAC)了。说起 ORACLE 集群

服务器,早在第五版的时候,ORACLE 就开始开发 ORACLE 并行服务器(ORACLE Parallel

Server ,OPS),并在以后的版本中逐渐的完善了其功能,不过,严格来说,尽管 OPS 算得

上是个集群环境,但是并没有体现出集群技术应有的优点。在完全吸收了 Rdb(ORACLE 在

1994 年收购了 Compaq 的 Rdb 数据库,此前 Rdb 属于 DEC 公司,DEC 公司在 VAX 上实现了第

一个可以商用的 Rdb 集群数据库)的一些技术优势之后,ORACLE 终于推出了真正的应用集

群软件。RAC 使得多个集群计算机能够共享对某个单一数据库的访问,以获得更高的可伸缩

性、可用性和经济性。ORACLE 9i 的 RAC 在 TPC-C 的基准测试中打破了数项记录,一时间业

内瞩目。这个新的数据库还包含集成的商务智能(BI)功能。ORACLE 9i 第 2 版还做出了很

多重要的改进,使 ORACLE 数据库成为一个本地的 XML 数据库;此外还包括自动管理、Data

Guard 等高可用方面的特性。

历史还在继续

2003 年 9 月 8 日,旧金山举办的 ORACLE World 大会上,Ellison 宣布下一代数据库产

品为“ORACLE 10g”。 ORACLE 应用服务器 10g(ORACLE Application Server 10g)也将作

为甲骨文公司下一代应用基础架构软件集成套件。“g”代表“grid ,网格”。这一版的 大

的特性就是加入了网格计算的功能。何谓网格计算?网格计算可以把分布在世界各地的计算

机连接在一起,并且将各地的计算机资源通过高速的互联网组成充分共享的资源集成。通过

合理调度,不同的计算环境被综合利用并共享。ORACLE 宣称 10g 可以作为网格计算的基础,

矛头直指 大的敌人 IBM 的“随需应变”!看来,ORACLE 公司已经把这一次的“赌注”押

在了网格计算的大市场上。但前景如何?让我们拭目以待。

如果说,IBM 是 IT 产业中的一头巨鲸,那么 ORACLE 一定就是一条大鲨鱼:咄咄逼人,

善于进攻。就在 2003 年 6 月初,ORACLE 突然宣布 51 亿美金收购仁科(PeopleSoft),业内

再次震动。次举又一次露出 ORACLE 一贯善于进攻的本性。要知道,ORACLE 在发展过程中很

少对企业进行收购的,那么收购仁科目的何在?首先,ORACLE 觊觎企业应用软件市场已久,

但苦于不能进一步扩大市场分额,尤为重要的是,一旦成功,可以直接对 大的敌人 IBM

进行打击,还可以阻击 SAP 等巨头的强势,这一点尤为重要。时至今日,ORACLE 依然以不

达目的不罢休的态势和仁科缠斗,结果如何,让我们拭目以待。

“人生 大的快乐是击败敌人”, Ellison 一定很喜欢这句活。

[作者简介]

Fenng,现任某美资公司 DBA。

目前关注如何利用 ORACLE 数据库有效的构建企业应用。

对 ORACLE database tuning, trouble shooting 有一点研究。

个人技术站点:http://www.dbanotes.net, 可以通过电子邮件 [email protected] 联系到他。

End

第 14 页 共 131 页

Page 15: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

判断某个字符串是否为数字的方法

By:bzszp

测试数据库版本:8.1.6

测试操作系统:windows2000 server

--第一种方法 通过 to_number 转换是否发生异常来判断

SQL> create or replace function f_str_or_num(str varchar2) return varchar2 is 2 v_num number; 3 v_return varchar2(60); 4 begin 5 v_num:=to_number(str); 6 v_return:=str||' is a number string!'; 7 return v_return; 8 exception when others then 9 v_return:=str||' is not a number string!'; 10 return v_return; 11 end f_str_or_num; 12 / Function created. SQL> select f_str_or_num('123.56') from dual; F_STR_OR_NUM('123.56') -------------------------------------------------------------------------------- 123.56 is a number string! SQL> select f_str_or_num('12aa.56') from dual; F_STR_OR_NUM('12AA.56') -------------------------------------------------------------------------------- 12aa.56 is not a number string! SQL>

--第二种通过 translate 函数来以及其他相关函数来实现

SQL> select decode(replace(translate('12a3.456','0123456789.',' '),' ',''),null, 2 'is number','is not a number') from dual; DECODE(REPLACE( --------------- is not a number SQL> select decode(replace(translate('123.456','0123456789.',' '),' ',''),null, 2 'is number','is not a number') from dual; DECODE(RE

第 15 页 共 131 页

Page 16: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

--------- is number SQL> [作者简介]

宋志平,常用网名 bzszp,现任 CSDN ORACLE 版大版主。

目前就职于山东青岛某软件公司,一直从事 ORACLE 开发以及相关工作。

在 oracle sql 语句以及 pl/sql 开发方面经验丰富,对 oracl 优化方面有所了解。

联系方式:[email protected]

End

第 16 页 共 131 页

Page 17: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

使用 sql 语句直接生成带有’小计’,’合计’的数

据集

By:bzszp

测试数据库版本:8.1.6

测试造作系统:windows2000 server

测试用户:scott

测试用表:dept,emp

在软件开发过程中经常要做一些报表,而且大部分报表都需要用到根据某一列进行统

计,计算出’小计’以及’合计’项目。一般来说大家都是在前台程序中进行处理,其实,

用 sql 语句就可以很轻松的完成这个功能。

下面的语句检索出需要进行统计的数据集(包含部门名称 dname、职位 job、工资 sal):

SQL> select dept.dname,emp.job,sal from emp,dept 2 where emp.deptno=dept.deptno; DNAME JOB SAL -------------- --------- ---------- RESEARCH CLERK 800 SALES SALESMAN 1600 SALES SALESMAN 1250 RESEARCH MANAGER 2975 SALES SALESMAN 1250 SALES MANAGER 2850 ACCOUNTING MANAGER 2450 ACCOUNTING PRESIDENT 5000 SALES SALESMAN 1500 SALES CLERK 950 RESEARCH ANALYST 3000 ACCOUNTING CLERK 1300 已选择 12 行。

下面,我们就根据部门名称以及职位进行汇总,并为每个部门生成’小计’, 后生成’

合计’。

第 17 页 共 131 页

Page 18: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

SQL> select decode(grouping(dept.dname),1,'合计:',dept.dname) dname, 2 decode(grouping(emp.job)+grouping(dept.dname),1,'小计:',emp.job) job,sum(sal) sum_sal from emp,dept 3 where emp.deptno=dept.deptno group by rollup(dept.dname,emp.job); DNAME JOB SUM_SAL -------------- --------- ---------- ACCOUNTING CLERK 1300 ACCOUNTING MANAGER 2450 ACCOUNTING PRESIDENT 5000 ACCOUNTING 小计: 8750 RESEARCH ANALYST 3000 RESEARCH CLERK 800 RESEARCH MANAGER 2975 RESEARCH 小计: 6775 SALES CLERK 950 SALES MANAGER 2850 SALES SALESMAN 5600 SALES 小计: 9400 合计: 24925 已选择 13 行。 SQL> [作者简介]

宋志平,常用网名 bzszp,现任 CSDN ORACLE 版大版主。

目前就职于山东青岛某软件公司,一直从事 ORACLE 开发以及相关工作。

在 oracle sql 语句以及 pl/sql 开发方面经验丰富,对 oracl 优化方面有所了解。

联系方式:[email protected]

End

第 18 页 共 131 页

Page 19: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

Oracle 中的进制转换

By Eygle

进制转换是开发中经常需要用到的,本文简单介绍几种常用的进制转化方法.

一 16 进制转换为 10 进制

可以通过 to_number 函数实现

SQL> select to_number('19f','xxx') from dual; TO_NUMBER('19F','XXX') ---------------------- 415 SQL> select to_number('f','xx') from dual; TO_NUMBER('F','XX') ------------------- 15

二 10 进制转换为 16 进制

可以通过 to_char 函数转换

SQL> select to_char(123,'xxx') from dual; TO_C ---- 7b SQL> select to_char(4567,'xxxx') from dual; TO_CH ----- 11d7

第 19 页 共 131 页

Page 20: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

三 2 进制转换为 10 进制

从 Oracle9i 开始,提供函数 bin_to_num 进行 2 进制到 10 进制的转换

SQL> select bin_to_num(1,1,0,1) a,bin_to_num(1,0) b from dual; A B ----- ---------- 13 2 SQL> select bin_to_num(1,1,1,0,1) from dual; BIN_TO_NUM(1,1,1,0,1) --------------------- 29

四 通过自定义函数实现进制转换

以下函数来自 AskTom 网站,是 Tom 给出的例子,供参考:

create or replace function to_base( p_dec in number, p_base in number ) return varchar2 is l_str varchar2(255) default NULL; l_num number default p_dec; l_hex varchar2(16) default '0123456789ABCDEF'; begin if ( trunc(p_dec) <> p_dec OR p_dec < 0 ) then raise PROGRAM_ERROR; end if; loop l_str := substr( l_hex, mod(l_num,p_base)+1, 1 ) || l_str; l_num := trunc( l_num/p_base ); exit when ( l_num = 0 ); end loop; return l_str; end to_base; / create or replace function to_dec

第 20 页 共 131 页

Page 21: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

( p_str in varchar2, p_from_base in number default 16 ) return number is l_num number default 0; l_hex varchar2(16) default '0123456789ABCDEF'; begin for i in 1 .. length(p_str) loop l_num := l_num * p_from_base + instr(l_hex,upper(substr(p_str,i,1)))-1; end loop; return l_num; end to_dec; / show errors create or replace function to_hex( p_dec in number ) return varchar2 is begin return to_base( p_dec, 16 ); end to_hex; / create or replace function to_bin( p_dec in number ) return varchar2 is begin return to_base( p_dec, 2 ); end to_bin; / create or replace function to_oct( p_dec in number ) return varchar2 is begin return to_base( p_dec, 8 ); end to_oct; /

[作者简介]

盖国强,网名 eygle

曾任 ITPUB MS 版版主,现任 itpub Oracle 管理版版主.

曾任职于某国家大型企业,服务于烟草行业,开发过基于 Oracle 数据库的大型 ERP 系统,属国家信息产业

部重点工程.同时负责 Oracle 数据库管理及优化,并为多家烟草企业提供 Oracle 数据库管理、优化及技术支

持.

目前任职于北京某电信增值业务系统提供商企业,首席 DBA,负责数据库业务.管理全国 30 多个数据库

系统。项目经验丰富,曾设计规划及支持中国联通增值业务等大型数据库系统.

实践经验丰富,长于数据库诊断、性能调整与 SQL 优化等.

第 21 页 共 131 页

Page 22: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

高级培训讲师,培训经验丰富,曾主讲 itpub dba 培训及 itpub 高级性能调整等主要课程.

《Oracle 数据库 DBA 专题技术精粹》一书的主编及主要作者.

你可以在http://www.eygle.com上找到关于作者的更多信息.

End

第 22 页 共 131 页

Page 23: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

C#+Oracle 开发中执行存储过程问题

By dinya

[关键字]

C#, Oracle, C/S

[内容摘要]

当前开发过程中,微软的.NET 以其易用和对网络的支持性好等而倍受开发人员的青睐,

不少项目使用 Oralce 数据库作为后台数据库,但是在开发过程中需要通过前台程序调用数

据库中的一些对象,本文将以一个实例的形式,对 C#+Oracle 数据库的开发中 C#执行 Oracle

存储过程问题做一简要阐述。

[本文适宜读者范围]

.NET+Oracel 开发人员,Oracle 初级

[系统环境]

OS:windows 2000 Professional (英文版)

Oracle:8.1.7.1.0

.NET:.Net 2003

[正文]

我们在使用 C#+Oracle 数据库开发 C/S 结构的程序时。有相当大一部分的事务会考虑放

在 Oracle 数据库中来处理,以减少网络数据流量、提高程序的性能。这样就要求我们将业

务逻辑化,抽象化,使用 Oracle 的存储过程是一个不错的选择。下面我将使用一个实例来

说明一下 C#使用 Oracle 存储过程来执行业务操作的过程:

需求描述:

在前端界面上输入用户名、密码、用户姓名、用户电话号码及用户类型等基础资料后。

调用 Oracle 数据库中的增加用户信息的存储过程来执行增加新用户信息的功能。要求用户

名、密码及用户类型不能为空,用户名不能有重复,本例中使用 OldDbConnection 来连接

Oracle 数据库。

1、在数据库中建一用户表及用户 ID 的序列:

create sequence seq_user_information

increment by 1

start with 1

nomaxvalue

nocycle

第 23 页 共 131 页

Page 24: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

cache 10

create table user_information

(

user_id number primary key, --用户序号

user_login_name varchar2(30) not null, --登陆名

user_password varchar2(50) not null, --用户密码

user_name varchar2(20), --用户姓名

user_telephone varchar2(20), --用户电话

user_type number(5) , --用户类型

creation_date date not null, --创建日期

last_update_date date not null -- 后修改日期

)

2、在 Oracle 中建执行插入操作的存储过程:

create or replace procedure insert_user_information

(

p_user_login_name in varchar2,

p_user_password in varchar2,

p_user_name in varchar2,

p_user_telephone in varchar2,

p_user_type in number,

p_out out number

) as

v_count number;

begin

if p_user_login_name is null or p_user_password is null then

p_out:=-1; --用户名和密码不能为空,

return ;

end if;

if p_user_type is null then

p_out:=-2; --用户类型不能为空

return ;

end if;

select count(*) into v_count from user_information a where

.user_login_name=upper(p_user_login_name);

if v_count>0 then

p_out:=-3; --该用户名已经存在

return ;

end if;

insert into user_information

values(seq_user_information.nextval,upper(p_user_login_name),

p_user_password,p_user_name,p_user_telephone,

第 24 页 共 131 页

Page 25: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

p_user_type, sysdate,sysdate);

commit;

p_out:=0; --操作成功

return ;

exception

when others then

p_out:=-4; --插入过程中出现异常

return ;

end ;

3、在.NET 项目建一个到数据库的联结:

在项目中新增加一个类文件。名称:clsPublic,

//添加引用:

using System;

using System.Data;

using System.Data.OleDb;

//连接字符串

private string connectora="Provider=MSDAORA.1;Password=fran;User

ID=fran;Data Source=demo;Persist Security Info=True";

//连接 Oracle 数据库

public OleDbConnection ConnectDB()

{

try

{

OleDbConnection conn=new OleDbConnection();

conn.ConnectionString=connectora;

conn.Open();

return conn;

}

catch

{

return null;

}

}

4、在类文件中添加如下内容,用来执行 Oracle 中的过程:

public int Insert_User_Information(string v_user_login_name,string

v_user_password,string v_user_name,string v_user_telephone,int

v_user_type,string proc_name)

{

第 25 页 共 131 页

Page 26: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

int i;

cmdOra.Parameters.Clear();

cmdOra.CommandText=proc_name;

cmdOra.CommandType=CommandType.StoredProcedure;

cmdOra.Connection=new clsPublic().ConnectDB();

cmdOra.Parameters.Add("p_user_login_name",OleDbType.VarChar);

cmdOra.Parameters.Add("p_user_password",OleDbType.VarChar);

cmdOra.Parameters.Add("p_user_name",OleDbType.VarChar);

cmdOra.Parameters.Add("p_user_telephone",OleDbType.VarChar);

cmdOra.Parameters.Add("p_user_type",OleDbType.Integer);

cmdOra.Parameters.Add("p_out",OleDbType.Integer);

cmdOra.Parameters["p_user_login_name"].Value=v_user_login_name;

cmdOra.Parameters["p_user_password"].Value=v_user_password;

cmdOra.Parameters["p_user_name"].Value=v_user_name;

cmdOra.Parameters["p_user_telephone"].Value=v_user_telephone;

cmdOra.Parameters["p_user_type"].Value=v_user_type;

cmdOra.Parameters["p_user_login_name"].Direction=ParameterDirection

.Input;

cmdOra.Parameters["p_user_password"].Direction=ParameterDirection.I

nput;

cmdOra.Parameters["p_user_name"].Direction=ParameterDirection.Input

;

cmdOra.Parameters["p_user_telephone"].Direction=ParameterDirection.I

nput;

cmdOra.Parameters["p_user_type"].Direction=ParameterDirection.Input;

cmdOra.Parameters["p_out"].Direction=ParameterDirection.ReturnValue;

try

{

cmdOra.ExecuteNonQuery();

i=(int)cmdOra.Parameters["p_out"].Value;

}

catch

{

i=-88;

}

finally

{

if(cmdOra.Connection.State==ConnectionState.Open)

{

cmdOra.Connection.Close();

第 26 页 共 131 页

Page 27: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

cmdOra.Connection.Dispose();

cmdOra.Parameters.Clear();

cmdOra.Dispose();

}

}

return i;

}

5、在窗体界面中调用执行存储过程

private void button3_Click_1(object sender, System.EventArgs e)

{

int i=new clsPublic().Insert_User_Information

("dinya","111","DINYA","13877778888",0,

"cux_franchiser.insert_user_information");

MessageBox.Show(i.ToString());

}

在本例第二步中,定义一个输出参数用来存储执行的结果,Oracle 存储过程允许给输出

参数直接赋值,在。NET 中设置该参数类型:

cmdOra.Parameters["p_out"].Direction=ParameterDirection.ReturnValue;

将其设置为返回值,这样在调用 Insert_User_Information 执行存储过程后,该参数将

执行结果返回给用户。

在 第 五 步 窗 体 界 面 中 调 用 存 储 过 程 的 时 候 , 后 一 个 参 数 为

"cux_franchiser.insert_user_information",该值中 cux_franchiser 为自己定义的一个

包,insert_user_information 为包中的过程。(具体对包的使用请参考 Oracle 相关书籍中

有关包的使用一节)。

其中需要指出的是,用来连接 Oracle 数据库的联结串会因为 OleDB 的厂家不同而不同,

本例中使用微软的,您在开发过程也可以使用 Oracle 公司的,可以到 Oralce 网站下载,地

址:

http://www.oracle.com/technology/software/tech/windows/ole_db/index.html。

后记:

在.NET + Oracle的开发过程,当然还有很多其他的操作技巧,希望本文能够起到抛砖

引玉的作用,刚接触开发的读者或Oracle初学者,可以参考本文,举一反三。此文您也可以

在作者的Blog中找到:http://blog.csdn.net/dinya2003/

第 27 页 共 131 页

Page 28: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

[作者简介]

曾就职于机械相关行业,后做 Windows 程序开发。现就职于一家制造企业,做 Oracle ERP 开发工作,

现任 CSDN 论坛 Oracle 开发版版主。

作者Mail: [email protected]

End

第 28 页 共 131 页

Page 29: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

Oracle诊断案例--如何捕获问题SQL解决过度CPU消

耗问题

By Eygle

本文通过实际业务系统中调整的一个案例,试图给出一个常见 CPU 消耗问题的一个诊断

方法.大多数情况下,系统的性能问题都是由不良 SQL 代码引起的,那么作为 DBA,怎样发

现和解决这些 SQL 问题就显得尤为重要.

本案例平台为 UNIX,所以不可避免的应用了一些 Unix 下常用的工具.如 vmstat,top 等.

本文适宜读者范围:中高级.

系统环境:

OS: Solaris8

Oracle: 8.1.7.4

问题描述:

开发人员报告系统运行缓慢,已经影响业务系统正常使用.请求协助诊断.

1.登陆数据库主机

使用 vmstat 检查,发现 CPU 资源已经耗尽,大量任务位于运行队列:

bash-2.03$ vmstat 3 procs memory page disk faults cpu r b w swap free re mf pi po fr de sr s6 s9 s1 sd in sy cs us sy id 0 0 0 5504232 1464112 0 0 0 0 0 0 0 0 1 1 0 4294967196 0 0 -84 -5 -145 131 0 0 5368072 1518360 56 691 0 2 2 0 0 0 1 0 0 3011 7918 2795 97 3 0 131 0 0 5377328 1522464 81 719 0 2 2 0 0 0 1 0 0 2766 8019 2577 96 4 0 130 0 0 5382400 1524776 67 682 0 0 0 0 0 0 0 0 0 3570 8534 3316 97 3 0 134 0 0 5373616 1520512 127 1078 0 2 2 0 0 0 1 0 0 3838 9584 3623 96 4 0 136 0 0 5369392 1518496 107 924 0 5 5 0 0 0 0 0 0 2920 8573 2639 97 3 0 132 0 0 5364912 1516224 63 578 0 0 0 0 0 0 0 0 0 3358 7944 3119 97 3 0 129 0 0 5358648 1511712 189 1236 0 0 0 0 0 0 0 0 0 3366 10365 3135 95 5 0 129 0 0 5354528 1511304 120 1194 0 0 0 0 0 0 0 4 0 3235 8864 2911 96 4 0 128 0 0 5346848 1507704 99 823 0 0 0 0 0 0 0 3 0 3189 9048 3074 96 4 0 125 0 0 5341248 1504704 80 843 0 2 2 0 0 0 6 1 0 3563 9514 3314 95 5 0 133 0 0 5332744 1501112 79 798 0 0 0 0 0 0 0 1 0 3218 8805 2902 97 3 0 129 0 0 5325384 1497368 107 643 0 2 2 0 0 0 1 4 0 3184 8297 2879 96 4 0 126 0 0 5363144 1514320 81 753 0 0 0 0 0 0 0 0 0 2533 7409 2164 97 3 0 136 0 0 5355624 1510512 169 566 786 0 0 0 0 0 0 1 0 3002 8600 2810 96 4 0

第 29 页 共 131 页

Page 30: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

130 1 0 5351448 1502936 267 580 1821 0 0 0 0 0 0 0 0 3126 7812 2900 96 4 0 129 0 0 5347256 1499568 155 913 2 2 2 0 0 0 0 1 0 2225 8076 1941 98 2 0 116 0 0 5338192 1495400 177 1162 0 0 0 0 0 0 0 1 0 1947 7781 1639 97 3 0

2.使用 Top 命令

观察进程 CPU 耗用,发现没有明显过高 CPU 使用的进程

$ top last pid: 28313; load averages: 99.90, 117.54, 125.71 23:28:38 296 processes: 186 sleeping, 99 running, 2 zombie, 9 on cpu CPU states: 0.0% idle, 96.5% user, 3.5% kernel, 0.0% iowait, 0.0% swap Memory: 4096M real, 1404M free, 2185M swap in use, 5114M swap free PID USERNAME THR PRI NICE SIZE RES STATE TIME CPU COMMAND 27082 oracle8i 1 33 0 1328M 1309M run 0:17 1.29% oracle 26719 oracle8i 1 55 0 1327M 1306M sleep 0:29 1.11% oracle 28103 oracle8i 1 35 0 1327M 1304M run 0:06 1.10% oracle 28161 oracle8i 1 25 0 1327M 1305M run 0:04 1.10% oracle 26199 oracle8i 1 45 0 1328M 1309M run 0:42 1.10% oracle 26892 oracle8i 1 33 0 1328M 1310M run 0:24 1.09% oracle 27805 oracle8i 1 45 0 1327M 1306M cpu/1 0:10 1.04% oracle 23800 oracle8i 1 23 0 1327M 1306M run 1:28 1.03% oracle 25197 oracle8i 1 34 0 1328M 1309M run 0:57 1.03% oracle 21593 oracle8i 1 33 0 1327M 1306M run 2:12 1.01% oracle 27616 oracle8i 1 45 0 1329M 1311M run 0:14 1.01% oracle 27821 oracle8i 1 43 0 1327M 1306M run 0:10 1.00% oracle 26517 oracle8i 1 33 0 1328M 1309M run 0:33 0.97% oracle 25785 oracle8i 1 44 0 1328M 1309M run 0:46 0.96% oracle 26241 oracle8i 1 45 0 1327M 1306M run 0:42 0.96% oracle

3.检查进程数量

bash-2.03$ ps -ef|grep ora|wc -l 258 bash-2.03$ ps -ef|grep ora|wc -l 275 bash-2.03$ ps -ef|grep ora|wc -l 274 bash-2.03$ ps -ef|grep ora|wc -l 278

第 30 页 共 131 页

Page 31: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

bash-2.03$ ps -ef|grep ora|wc -l 277 bash-2.03$ ps -ef|grep ora|wc -l 366

发现系统存在大量 Oracle 进程,大约在 300 左右,大量进程消耗了几乎所有 CPU 资源,

而正常情况下 Oracle 连接数应该在 100 左右.

4.检查数据库

查询 v$session_wait 获取各进程等待事件

SQL> select sid,event,p1,p1text from v$session_wait; SID EVENT P1 P1TEXT ---------- ------------------------------ ---------- ---------------------------------------------------------------- 124 latch free 1.6144E+10 address 1 pmon timer 300 duration 2 rdbms ipc message 300 timeout 3 rdbms ipc message 300 timeout 11 rdbms ipc message 30000 timeout 6 rdbms ipc message 180000 timeout 4 rdbms ipc message 300 timeout 134 rdbms ipc message 6000 timeout 147 rdbms ipc message 6000 timeout 275 rdbms ipc message 17995 timeout 274 rdbms ipc message 6000 timeout SID EVENT P1 P1TEXT ---------- ------------------------------ ---------- ---------------------------------------------------------------- 118 rdbms ipc message 6000 timeout 7 buffer busy waits 17 file# 56 buffer busy waits 17 file# 161 buffer busy waits 17 file# 195 buffer busy waits 17 file# 311 buffer busy waits 17 file# 314 buffer busy waits 17 file# 205 buffer busy waits 17 file# 269 buffer busy waits 17 file# 200 buffer busy waits 17 file# 164 buffer busy waits 17 file# SID EVENT P1 P1TEXT ---------- ------------------------------ ---------- ----------------------------------------------------------------

第 31 页 共 131 页

Page 32: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

140 buffer busy waits 17 file# 66 buffer busy waits 17 file# 10 db file sequential read 17 file# 18 db file sequential read 17 file# 54 db file sequential read 17 file# 49 db file sequential read 17 file# 48 db file sequential read 17 file# 46 db file sequential read 17 file# 45 db file sequential read 17 file# 35 db file sequential read 17 file# 30 db file sequential read 17 file# SID EVENT P1 P1TEXT ---------- ------------------------------ ---------- ---------------------------------------------------------------- 29 db file sequential read 17 file# 22 db file sequential read 17 file# 178 db file sequential read 17 file# 175 db file sequential read 17 file# 171 db file sequential read 17 file# 123 db file sequential read 17 file# 121 db file sequential read 17 file# 120 db file sequential read 17 file# 117 db file sequential read 17 file# 114 db file sequential read 17 file# 113 db file sequential read 17 file# SID EVENT P1 P1TEXT ---------- ------------------------------ ---------- ---------------------------------------------------------------- 111 db file sequential read 17 file# 107 db file sequential read 17 file# 80 db file sequential read 17 file# 222 db file sequential read 17 file# 218 db file sequential read 17 file# 216 db file sequential read 17 file# 213 db file sequential read 17 file# 199 db file sequential read 17 file# 198 db file sequential read 17 file# 194 db file sequential read 17 file# 192 db file sequential read 17 file# SID EVENT P1 P1TEXT ---------- ------------------------------ ---------- ---------------------------------------------------------------- 188 db file sequential read 17 file# 249 db file sequential read 17 file#

第 32 页 共 131 页

Page 33: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

242 db file sequential read 17 file# 239 db file sequential read 17 file# 236 db file sequential read 17 file# 235 db file sequential read 17 file# 234 db file sequential read 17 file# 233 db file sequential read 17 file# 230 db file sequential read 17 file# 227 db file sequential read 17 file# 336 db file sequential read 17 file# SID EVENT P1 P1TEXT ---------- ------------------------------ ---------- ---------------------------------------------------------------- 333 db file sequential read 17 file# 331 db file sequential read 17 file# 329 db file sequential read 17 file# 327 db file sequential read 17 file# 325 db file sequential read 17 file# 324 db file sequential read 17 file# 320 db file sequential read 17 file# 318 db file sequential read 17 file# 317 db file sequential read 17 file# 316 db file sequential read 17 file# 313 db file sequential read 17 file# SID EVENT P1 P1TEXT ---------- ------------------------------ ---------- ---------------------------------------------------------------- 305 db file sequential read 17 file# 303 db file sequential read 17 file# 301 db file sequential read 17 file# 293 db file sequential read 17 file# 290 db file sequential read 17 file# 288 db file sequential read 17 file# 287 db file sequential read 17 file# 273 db file sequential read 17 file# 271 db file sequential read 17 file# 257 db file sequential read 17 file# 256 db file sequential read 17 file# SID EVENT P1 P1TEXT ---------- ------------------------------ ---------- ---------------------------------------------------------------- 254 db file sequential read 17 file# 252 db file sequential read 17 file# 159 db file sequential read 17 file# 153 db file sequential read 17 file#

第 33 页 共 131 页

Page 34: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

146 db file sequential read 17 file# 142 db file sequential read 17 file# 135 db file sequential read 17 file# 133 db file sequential read 17 file# 132 db file sequential read 17 file# 126 db file sequential read 17 file# 79 db file sequential read 17 file# SID EVENT P1 P1TEXT ---------- ------------------------------ ---------- ---------------------------------------------------------------- 77 db file sequential read 17 file# 72 db file sequential read 17 file# 70 db file sequential read 17 file# 69 db file sequential read 17 file# 67 db file sequential read 17 file# 63 db file sequential read 17 file# 55 db file sequential read 17 file# 102 db file sequential read 17 file# 96 db file sequential read 17 file# 95 db file sequential read 17 file# 91 db file sequential read 17 file# SID EVENT P1 P1TEXT ---------- ------------------------------ ---------- ---------------------------------------------------------------- 81 db file sequential read 17 file# 15 db file sequential read 17 file# 19 db file scattered read 17 file# 50 db file scattered read 17 file# 285 db file scattered read 17 file# 279 db file scattered read 17 file# 255 db file scattered read 17 file# 243 db file scattered read 17 file# 196 db file scattered read 17 file# 187 db file scattered read 17 file# 170 db file scattered read 17 file# SID EVENT P1 P1TEXT ---------- ------------------------------ ---------- ---------------------------------------------------------------- 162 db file scattered read 17 file# 138 db file scattered read 17 file# 110 db file scattered read 17 file# 108 db file scattered read 17 file# 92 db file scattered read 17 file# 330 db file scattered read 17 file#

第 34 页 共 131 页

Page 35: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

310 db file scattered read 17 file# 302 db file scattered read 17 file# 299 db file scattered read 17 file# 89 db file scattered read 17 file# 5 smon timer 300 sleep time SID EVENT P1 P1TEXT ---------- ------------------------------ ---------- ---------------------------------------------------------------- 20 SQL*Net message to client 1952673792 driver id 103 SQL*Net message to client 1650815232 driver id .... 148 SQL*Net more data from client 1952673792 driver id 291 SQL*Net more data from client 1952673792 driver id 244 rows selected.

发现存在大量 db file scattered read 及 db file sequential read 等待.显然全表扫描

等操作成为系统 严重的性能影响因素.

关于常见的等待事件,你可以在以下网址找到更为详细的说明.

http://www.eygle.com/statspack/statspack12.htm

5.捕获相关 SQL

这里用到了我的以下脚本 getsqlbysid:

SELECT sql_text FROM v$sqltext a WHERE a.hash_value = (SELECT sql_hash_value FROM v$session b WHERE b.SID = '&sid') ORDER BY piece ASC /

该脚本根据用户 sid,结合 v$session 和 v$sqltext 视图,获得用户 sql 语句的完整文

本.

使用该脚本,通过从 v$session_wait 中获得的等待全表或索引扫描的进程 SID,捕获

问题 sql:

SQL> @getsql Enter value for sid: 18 old 5: where b.sid='&sid' new 5: where b.sid='18'

第 35 页 共 131 页

Page 36: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

SQL_TEXT ---------------------------------------------------------------- select i.vc2title,i.numinfoguid from hs_info i where i.intenab ledflag = 1 and i.intpublishstate = 1 and i.datpublishdate <= sysdate and i.numcatalogguid = 2047 order by i.datpublishdate d esc, i.numorder desc SQL> / Enter value for sid: 54 old 5: where b.sid='&sid' new 5: where b.sid='54' SQL_TEXT ---------------------------------------------------------------- select i.vc2title,i.numinfoguid from hs_info i where i.intenab ledflag = 1 and i.intpublishstate = 1 and i.datpublishdate <= sysdate and i.numcatalogguid = 33 order by i.datpublishdate des c, i.numorder desc SQL> / Enter value for sid: 49 old 5: where b.sid='&sid' new 5: where b.sid='49' SQL_TEXT ---------------------------------------------------------------- select i.vc2title,i.numinfoguid from hs_info i where i.intenab ledflag = 1 and i.intpublishstate = 1 and i.datpublishdate <= sysdate and i.numcatalogguid = 26 order by i.datpublishdate des c, i.numorder desc

对几个进程进行跟踪,分别得到以上 SQL 语句,这些 SQL 可能就是问题产生的根源.

以上语句如果良好编码应该使用绑定变量.但是现在这个不是我们关心的.

使用该应用用户连接,检查以上 SQL 的执行计划:

SQL> set autotrace trace explain SQL> select i.vc2title,i.numinfoguid 2 from hs_info i where i.intenabledflag = 1 3 and i.intpublishstate = 1 and i.datpublishdate <=sysdate 4 and i.numcatalogguid = 3475 5 order by i.datpublishdate desc, i.numorder desc ; Execution Plan

第 36 页 共 131 页

Page 37: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=228 Card=1 Bytes=106) 1 0 SORT (ORDER BY) (Cost=228 Card=1 Bytes=106) 2 1 TABLE ACCESS (FULL) OF 'HS_INFO' (Cost=218 Card=1 Bytes=106) SQL> select count(*) from hs_info; COUNT(*) ---------- 227404

以上查询使用了全表扫描,该表这里有 22 万记录,全表扫描已经不再适合.

检查该表,存在以下索引:

SQL> select index_name,index_type from user_indexes where table_name='HS_INFO'; INDEX_NAME INDEX_TYPE ------------------------------ --------------------------- HSIDX_INFO1 FUNCTION-BASED NORMAL HSIDX_INFO_SEARCHKEY DOMAIN PK_HS_INFO NORMAL

检查索引键值:

SQL> select index_name,column_name 2 from user_ind_columns where table_name ='HS_INFO'; INDEX_NAME COLUMN_NAME ------------------------------ -------------------- HSIDX_INFO1 NUMORDER HSIDX_INFO1 SYS_NC00024$ HSIDX_INFO_SEARCHKEY VC2INDEXWORDS PK_HS_INFO NUMINFOGUID SQL> desc hs_info Name Null? Type --------------------------------- -------- -------------------------------------------- NUMINFOGUID NOT NULL NUMBER(15) NUMCATALOGGUID NOT NULL NUMBER(15) INTTEXTTYPE NOT NULL NUMBER(38) VC2TITLE NOT NULL VARCHAR2(60) VC2AUTHOR VARCHAR2(100)

第 37 页 共 131 页

Page 38: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

NUMPREVINFOGUID NUMBER(15) NUMNEXTINFOGUID NUMBER(15) NUMORDER NOT NULL NUMBER(15) DATPUBLISHDATE NOT NULL DATE INTPUBLISHSTATE NOT NULL NUMBER(38) VC2PUBLISHERID VARCHAR2(30) VC2INDEXWORDS VARCHAR2(200) VC2WAPPREVPATH VARCHAR2(200) VC2WEBPREVPATH VARCHAR2(200) VC2WAP2PREVPATH VARCHAR2(200) NUMVISITED NOT NULL NUMBER(15) INTENABLEDFLAG NOT NULL NUMBER(38) DATCREATETIME NOT NULL DATE DATMODIFYTIME NOT NULL DATE VC2NOTES VARCHAR2(1000) INTINFOTYPE NOT NULL NUMBER(38) VC2PRIZEFLAG VARCHAR2(1) VC2DESC VARCHAR2(1000)

6.决定创建新的索引以消除全表扫描

检查发现在 numcatalogguid 字段上并没有索引,该字段具有很好的区分度,考虑在该

字段创建索引以消除全表扫描.

SQL> create index hs_info_NUMCATALOGGUID on hs_info(NUMCATALOGGUID); Index created. SQL> set autotrace trace explain SQL> select i.vc2title,i.numinfoguid 2 from hs_info i where i.intenabledflag = 1 3 and i.intpublishstate = 1 and i.datpublishdate <=sysdate 4 and i.numcatalogguid = 3475 5 order by i.datpublishdate desc, i.numorder desc ; Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=12 Card=1 Bytes=106) 1 0 SORT (ORDER BY) (Cost=12 Card=1 Bytes=106) 2 1 TABLE ACCESS (BY INDEX ROWID) OF 'HS_INFO' (Cost=2 Card=1 Bytes=106) 3 2 INDEX (RANGE SCAN) OF 'HS_INFO_NUMCATALOGGUID' (NON-UNIQUE) (Cost=1 Card=1)

第 38 页 共 131 页

Page 39: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

7.观察系统状况

原大量等待消失

SQL> select sid,event,p1,p1text from v$session_wait where event not like 'SQL%'; SID EVENT P1 P1TEXT ---------- ------------------------------ ---------- ---------------------------------------------------------------- 1 pmon timer 300 duration 2 rdbms ipc message 300 timeout 3 rdbms ipc message 300 timeout 6 rdbms ipc message 180000 timeout 59 rdbms ipc message 6000 timeout 118 rdbms ipc message 6000 timeout 275 rdbms ipc message 30000 timeout 147 rdbms ipc message 6000 timeout 62 rdbms ipc message 6000 timeout 11 rdbms ipc message 30000 timeout 4 rdbms ipc message 300 timeout SID EVENT P1 P1TEXT ---------- ------------------------------ ---------- ---------------------------------------------------------------- 305 db file sequential read 17 file# 356 db file sequential read 17 file# 19 db file scattered read 17 file# 5 smon timer 300 sleep time 15 rows selected.

持续观察的 CPU 使用情况

bash-2.03$ vmstat 3 procs memory page disk faults cpu r b w swap free re mf pi po fr de sr s6 s9 s1 sd in sy cs us sy id 20 0 0 5421792 1503488 38 434 136 0 0 0 0 0 0 2 0 2931 7795 2622 91 9 0 23 1 0 5416080 1500632 95 734 56 0 0 0 0 0 0 0 0 2949 8057 2598 89 11 0 26 0 0 5412016 1498480 210 1170 21 5 5 0 0 0 2 1 0 3301 9647 3116 90 10 0 25 0 0 5394912 1490160 242 1606 56 0 0 0 0 0 0 1 0 3133 9318 2850 89 11 0 40 0 0 5390200 1488112 162 1393 66 0 0 0 0 0 0 0 0 2848 9080 2502 90 10 0 40 0 0 5377120 1481792 136 1180 120 2 2 0 0 0 1 1 0 2846 9099 2593 92 8 0 36 0 0 5363216 1475168 134 1169 53 0 0 0 0 0 3 2 0 2871 7989 2621 88 12 0 39 0 0 5348936 1469160 157 1448 210 0 0 0 0 0 0 0 0 3660 10062 3480 88 12 0 35 0 0 5344552 1466472 7 15 56 0 0 0 0 0 0 0 0 2885 7663 2635 92 8 0

第 39 页 共 131 页

Page 40: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

34 0 0 5343016 1465416 44 386 77 0 0 0 0 0 0 0 0 3197 8486 2902 92 8 0 31 0 0 5331568 1459696 178 1491 122 0 0 0 0 0 0 3 0 3237 9461 3005 89 11 0 31 0 0 5317792 1453008 76 719 80 0 0 0 0 0 0 0 0 3292 8736 3025 93 7 0 31 2 0 5311144 1449552 235 1263 69 2 2 0 0 0 1 0 0 3473 9535 3357 88 12 0 25 0 0 5300240 1443920 108 757 18 2 2 0 0 0 1 1 0 2377 7876 2274 95 5 0 19 0 0 5295904 1441840 50 377 0 0 0 0 0 0 0 1 0 1915 6598 1599 98 1 0 ----以上为创建索引之前部分 ----以下为创建索引之后部分,CPU 使用率恢复正常 procs memory page disk faults cpu r b w swap free re mf pi po fr de sr s6 s9 s1 sd in sy cs us sy id 40 1 0 5290040 1439208 315 3894 8 2 2 0 0 0 1 6 0 3631 13414 5206 61 9 30 0 1 0 5237192 1414744 731 6749 45 0 0 0 0 0 2 7 0 3264 13558 4941 52 14 34 0 0 0 5163632 1380608 747 6585 10 0 0 0 0 0 0 1 0 2617 12291 3901 46 12 41 1 0 0 5090224 1348152 712 6079 29 0 0 0 0 0 0 6 0 2825 12416 4178 50 12 39 1 0 0 5023672 1317296 714 6183 24 0 0 0 0 0 0 5 0 3166 12424 4745 47 13 40 0 0 0 4955872 1287136 737 6258 16 0 0 0 0 0 0 3 0 2890 11777 4432 44 12 44 1 0 0 4887888 1256464 809 6234 8 2 2 0 0 0 0 2 0 2809 12066 4247 45 12 43 0 0 0 4828912 1228200 312 2364 13 5 5 0 0 0 2 1 0 2410 6816 3492 38 6 57 0 0 0 4856816 1240168 8 138 0 0 0 0 0 0 1 0 0 2314 4026 3232 34 4 62 0 0 0 4874176 1247712 0 86 0 0 0 0 0 0 0 0 0 2298 3930 3324 35 2 63 2 0 0 4926088 1270824 34 560 0 0 0 0 0 0 0 0 0 2192 4694 2612 29 16 55 0 0 0 5427320 1512952 53 694 0 0 0 0 0 0 3 2 0 2443 5085 3340 33 12 55 0 0 0 5509120 1553136 0 37 0 0 0 0 0 0 0 0 0 2309 3908 3321 35 1 64 0 0 0 5562048 1577000 16 234 0 0 0 0 0 0 0 0 0 2507 5187 3433 35 8 57 0 0 0 5665672 1623848 252 1896 8 2 2 0 0 0 1 0 0 2091 6548 2939 34 5 61 0 0 0 5654752 1618208 5 173 16 0 0 0 0 0 0 0 0 2226 4218 3051 35 4 60 0 0 0 5727024 1651120 28 254 0 0 0 0 0 0 0 0 0 2126 4224 2982 38 2 60 0 0 0 5723184 1648880 93 562 8 2 2 0 0 0 1 1 0 2371 5140 3432 38 3 59 0 0 0 5730744 1652512 7 177 26 2 2 0 0 0 1 0 0 2465 4442 3575 36 3 61

至此,此问题得以解决.

8.性能何以提高?

回答这个问题似乎是多余的,我只想重申一点:

有效的降低 SQL 的逻辑读是 SQL 优化的基本原则之一.

我们来比较一下前后两种执行方式的读取及性能差异.

全表扫描的性能

SQL> select i.vc2title,i.numinfoguid 2 from hs_info i where i.intenabledflag = 1

第 40 页 共 131 页

Page 41: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

3 and i.intpublishstate = 1 and i.datpublishdate <=sysdate 4 and i.numcatalogguid = 3475 5 order by i.datpublishdate desc, i.numorder desc ; 352 rows selected. Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=541 Card=1 Bytes=106) 1 0 SORT (ORDER BY) (Cost=541 Card=1 Bytes=106) 2 1 TABLE ACCESS (FULL) OF 'HS_INFO' (Cost=531 Card=1 Bytes=106) Statistics ---------------------------------------------------------- 0 recursive calls 25 db block gets 3499 consistent gets 258 physical reads 0 redo size 14279 bytes sent via SQL*Net to client 2222 bytes received via SQL*Net from client 25 SQL*Net roundtrips to/from client 2 sorts (memory) 0 sorts (disk) 352 rows processed

使用索引的性能

SQL> select i.vc2title,i.numinfoguid 2 from hs_info i where i.intenabledflag = 1 3 and i.intpublishstate = 1 and i.datpublishdate <=sysdate 4 and i.numcatalogguid = 3475 5 order by i.datpublishdate desc, i.numorder desc; 352 rows selected. Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=12 Card=1 Bytes=106) 1 0 SORT (ORDER BY) (Cost=12 Card=1 Bytes=106) 2 1 TABLE ACCESS (BY INDEX ROWID) OF 'HS_INFO' (Cost=2 Card=1 Bytes=106) 3 2 INDEX (RANGE SCAN) OF 'HS_INFO_NUMCATALOGGUID' (NON-UNIQUE) (Cost=1 Card=1)

第 41 页 共 131 页

Page 42: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 89 consistent gets 0 physical reads 0 redo size 14279 bytes sent via SQL*Net to client 2222 bytes received via SQL*Net from client 25 SQL*Net roundtrips to/from client 1 sorts (memory) 0 sorts (disk) 352 rows processed

consistent gets 从 3499 到 89,我们看到性能得到了巨大的提高.

结语:

通常,开发人员很少注意 SQL 代码的效率,他们更着眼于功能的实现.

至于性能问题通常被认为是次要的,而且在应用系统开发初期,由于数据库数据量较少,

对于查询 SQL 语句等,不容易体会出各种 SQL 句法的性能差异.

但是一旦这些应用作为生产系统上线运行,随着数据库中数据量的增加,大量并发访问,

系统的响应速度可能就会成为系统需要解决的 主要的问题之一.

在少量用户下性能可以接受的 SQL,可能在大量用户并发的条件下就会成为性能瓶颈.

在我这个案例中,开发人员很难相信仅只一条 SQL 语句就导致了整个数据库的性能下

降.

然而事实就是如此,一条低效的 SQL 语句就可能毁掉你的数据库,所以在系统设计及开

发过程中,你必须考虑到诸多细节,严格的测试也是提早发现问题的有效方法.

如果不幸以上环节都被忽略,那么,DBA(也许就是你)就是 后的一环,你必须能够快速

的诊断并解决各种复杂问题.

那么,朋友们,祝你好运!

[作者简介]

盖国强,网名 eygle

曾任 ITPUB MS 版版主,现任 itpub Oracle 管理版版主.

曾任职于某国家大型企业,服务于烟草行业,开发过基于 Oracle 数据库的大型 ERP 系统,属国家信息产业

部重点工程.同时负责 Oracle 数据库管理及优化,并为多家烟草企业提供 Oracle 数据库管理、优化及技术支

第 42 页 共 131 页

Page 43: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

持.

目前任职于北京某电信增值业务系统提供商企业,首席 DBA,负责数据库业务.管理全国 30 多个数据库

系统。项目经验丰富,曾设计规划及支持中国联通增值业务等大型数据库系统.

实践经验丰富,长于数据库诊断、性能调整与 SQL 优化等.

高级培训讲师,培训经验丰富,曾主讲 itpub dba 培训及 itpub 高级性能调整等主要课程.

《Oracle 数据库 DBA 专题技术精粹》一书的主编及主要作者.

你可以在http://www.eygle.com上找到关于作者的更多信息.

End

第 43 页 共 131 页

Page 44: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

关于 Oracle 数据库中行迁移/行链接的问题

By Coolyl

一、行迁移/行链接的介绍

在实际的工作中我们经常会碰到一些 Oracle 数据库性能较低的问题,当然,引起 Oracle

数据库性能较低的原因是多方面的,我们能够通过一些正确的设计和诊断来尽量的避免一些

Oracle 数据库性能不好,Row Migration (行迁移) & Row Chaining (行链接)就是其中我

们可以尽量避免的引起 Oracle 数据库性能低下的潜在问题。通过合理的诊断行迁移/行链

接,我们可以较大幅度上提高 Oracle 数据库的性能。

那究竟什么是行迁移/行链接呢,先让我们从 Oracle 的 block 开始谈起。

操作系统的 小读写操作单元是操作系统的 block,所以当创建一个 Oracle 数据库的时

候我们应该讲数据库的block size设置成为操作系统的block size的整数倍,Oracle block

是 Oracle 数据库中读写操作的 小单元,Oracle9i 之前的 Oracle 数据库版本中 Oracle

block 一旦在创建数据库的时候被设定后就没法再更改。为了在创建数据库之前确定一个合

理的 Oracle block 的大小,我们需要考虑一些因素,例如数据库本身的大小以及并发事务

的数量等。使用一个合适的 Oracle block 大小对于数据库的调优是非常重要的。Oracle

block 的结构如下图所示:

第 44 页 共 131 页

Page 45: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

图一:Oracle Block 结构图

由上图我们可以看出,一个 Oracle block 由三个部分组成,分别是数据块头、自由空

间、实际数据三部份组成。

数据块头:主要包含有数据块地址的一些基本信息和段的类型,以及表和包含有数据的

实际行的地址。

自由空间:是指可以为以后的更新和插入操作分配的空间,大小由 PCTFREE 和 PCTUSED

两个参数影响。

实际数据:是指在行内存储的实际数据。

当创建或者更改任何表和索引的时候,Oracle 在空间控制方面使用两个存储参数:

PCTFREE:为将来更新已经存在的数据预留空间的百分比。

PCTUSED:用于为插入一新行数据的 小空间的百分比。这个值决定了块的可用状态。

可用的块时可以执行插入的块,不可用状态的块只能执行删除和修改,可用状态的块被放在

freelist 中。

当表中一行的数据不能在一个数据block中放入的时候,这个时候就会发生两种情况,

一种是行链接,另外一种就是行迁移了。

第 45 页 共 131 页

Page 46: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

行链接产生在第一次插入数据的时候如果一个 block 不能存放一行记录的情况下。这

种情况下,Oracle 将使用链接一个或者多个在这个段中保留的 block 存储这一行记录,行

链接比较容易发生在比较大的行上,例如行上有 LONG、LONG RAW、LOB 等数据类型的字段,

这种时候行链接是不可避免的会产生的。

当一行记录初始插入的时候事可以存储在一个 block 中的,由于更新操作导致行长增

加了,而 block 的自由空间已经完全满了,这个时候就产生了行迁移。在这种情况下,Oracle

将会迁移整行数据到一个新的 block 中(假设一个 block 中可以存储下整行数据),Oracle

会保留被迁移行的原始指针指向新的存放行数据的 block,这就意味着被迁移行的 ROW ID

是不会改变的。

当发生了行迁移或者行链接,对这行数据操作的性能就会降低,因为 Oracle 必须要

扫描更多的 block 来获得这行的信息。

下面举例来具体说明行迁移/行链接的产生过程。

先创建一个 pctfree 为 20 和 pctused 为 50 的测试表:

create table test(

col1 char(20),

col2 number)

storage (

pctfree 20

pctused 50);

当插入一条记录的时候,Oracle 会在 free list 中先去寻找一个自由的块,并且将数

据插入到这个自由块中。而在 free list 中存在的自由的块是由 pctfree 值决定的。初始的

空块都是在 free list 中的,直到块中的自由空间达到 pctfree 的值,此块就会从 free list

中移走,而当此块中的使用空间低于 pctused 的时候,此块又被重新放到 free list 中。

Oracle 使用 free list 机制可以大大的提高性能,对于每次的插入操作,Oracle 只

需要查找 free list 就可以了,而不是去查找所有的 block 来寻找自由空间。

假设第一次插入数据使用的一个空的 block,如下图所示:

图二:Oracle 空的 block 结构图

第 46 页 共 131 页

Page 47: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

假设插入第一条记录的时候占用一个 block 的 10%的空间(除去 block 头占去的大小),

剩余的自由空间90%大于pctfree20%,因此这个block还将继续为下次的插入操作提供空间。

图三:插入 10%后的 Oracle block 结构图

再连续插入七条记录,使 block 的剩余自由空间剩下 20%,此时,这个 block 将要从 free

list 中移走,如果再插入记录,Oracle 将再 free list 中寻找下一个空余的 block 去存放

后来插入的数据。

图四:插入 80%后的 Oracle block 结构图

此时如果去更新第一条插入的记录,使其行长增加 15%,Oracle 将会使用这个 block

中剩余的 20%的自由空间来存放此行数据,如果再更新第二条记录,同样的使其行长增加 15%,

而此block中只剩下5%的自由空间,不够存放更新的第二条记录,于是Oracle会在free list

中寻找一个有自由空间(10%+15%)的block来存放这行记录的block去存储,在原来的block

中保存了指向新的 block 的指针,原来这行记录的 ROW ID 保持不变,这个时候就产生了行

迁移。

而当我们插入一条新纪录的时候,如果一个 blcok 不足以存放下这条记录,Oracle

就会寻找一定数量的 block 一起来容纳这条新的记录,这个时候就产生了行链接,行链接主

要产生在 LOB、CLOB、BLOB 和大的 VA 行链接 HAR2 数据类型上。

具体我们通过下面的一个试验来查看行链接和行迁移是如何产生并在数据文件中体

现出来的。

第 47 页 共 131 页

Page 48: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

先查看 ALLAN 这个表空间的数据文件号,为了便于测试,我只建立了一个数据文件。

SQL> select file_id from dba_data_files where tablespace_name='ALLAN';

FILE_ID

----------

23

创建一个测试表 test:

SQL> create table test ( x int primary key, a char(2000), b char(2000), c char(2000),

d char(2000), e char(2000) ) tablespace allan;

Table created.

因为我的数据库的 db_block_size 是 8K,所以我创建的表有五个字段,每个占 2000 个字节,

这样一行记录大约 10K,就能超过一个 block 的大小了。

然后插入一行记录,只有一个字段的:

SQL> insert into test(x) values (1);

1 row created.

SQL> commit;

Commit complete.

查找这行记录所在的 block,并 dump 出来:

SQL> select dbms_rowid.rowid_block_number(rowid) from test;

DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)

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

34

SQL> alter system dump datafile 23 block 34;

System altered.

在 udump 目录下查看 trace 文件的内容如下:

Start dump data blocks tsn: 34 file#: 23 minblk 34 maxblk 34

buffer tsn: 34 rdba: 0x05c00022 (23/34)

scn: 0x0000.013943f3 seq: 0x01 flg: 0x02 tail: 0x43f30601

frmt: 0x02 chkval: 0x0000 type: 0x06=trans data

Block header dump: 0x05c00022

Object id on Block? Y

seg/obj: 0x3ccd csc: 0x00.13943ef itc: 2 flg: O typ: 1 - DATA

fsl: 0 fnx: 0x0 ver: 0x01

Itl Xid Uba Flag Lck Scn/Fsc

0x01 0x000a.02e.00000ad7 0x00800036.03de.18 --U- 1 fsc 0x0000.013943f3

0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000

data_block_dump,data header at 0xadb505c

===============

tsiz: 0x1fa0

hsiz: 0x14

pbl: 0x0adb505c

bdba: 0x05c00022

76543210

flag=--------

第 48 页 共 131 页

Page 49: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

ntab=1

nrow=1

frre=-1

fsbo=0x14

fseo=0x1f9a

avsp=0x1f83

tosp=0x1f83

0xe:pti[0] nrow=1 offs=0

0x12:pri[0] offs=0x1f9a

block_row_dump:

tab 0, row 0, @0x1f9a

tl: 6 fb: --H-FL-- lb: 0x1 cc: 1

col 0: [ 2] c1 02

end_of_block_dump

End dump data blocks tsn: 34 file#: 23 minblk 34 maxblk 34

对其中的一些信息做一些解释:

Fb:H 是指行记录的头,L是指行记录的 后一列,F 是指行记录的第一列。

Cc:列的数量

Nrid:对于行链接或者行迁移来说的下一个 row id 的值

由上面的 dump 信息我们可以看出来当前表 test 是没有行链接或者行迁移的。

然后更新 test 表,并重新 dump 出来:

SQL> update test set a='test',b='test',c='test',d='test',e='test' where x=1;

1 row updated.

SQL> commit;

Commit complete.

此时应该有行迁移/行链接产生了。

SQL> alter system dump datafile 23 block 34;

System altered.

在 udump 目录下查看 trace 文件的内容如下:

Start dump data blocks tsn: 34 file#: 23 minblk 34 maxblk 34

buffer tsn: 34 rdba: 0x05c00022 (23/34)

scn: 0x0000.0139442b seq: 0x01 flg: 0x02 tail: 0x442b0601

frmt: 0x02 chkval: 0x0000 type: 0x06=trans data

Block header dump: 0x05c00022

Object id on Block? Y

seg/obj: 0x3ccd csc: 0x00.1394429 itc: 2 flg: - typ: 1 - DATA

fsl: 0 fnx: 0x0 ver: 0x01

Itl Xid Uba Flag Lck Scn/Fsc

0x01 0x000a.02e.00000ad7 0x00800036.03de.18 C--- 0 scn 0x0000.013943f3

0x02 0x0004.002.00000ae0 0x0080003b.0441.11 --U- 1 fsc 0x0000.0139442b

data_block_dump,data header at 0xadb505c

===============

tsiz: 0x1fa0

hsiz: 0x14

第 49 页 共 131 页

Page 50: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

pbl: 0x0adb505c

bdba: 0x05c00022

76543210

flag=--------

ntab=1

nrow=1

frre=-1

fsbo=0x14

fseo=0x178a

avsp=0x177c

tosp=0x177c

0xe:pti[0] nrow=1 offs=0

0x12:pri[0] offs=0x178a

block_row_dump:

tab 0, row 0, @0x178a

tl: 2064 fb: --H-F--N lb: 0x2 cc: 3

nrid: 0x05c00023.0

col 0: [ 2] c1 02

col 1: [2000]

74 65 73 74 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20

20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20

…………

col 2: [48]

74 65 73 74 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20

20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20

end_of_block_dump

End dump data blocks tsn: 34 file#: 23 minblk 34 maxblk 34

我们不难看出,nrid 出现了值,指向了下一个 row id,证明刚刚的 update 操作使这行记录

产生了行链接或者行迁移了。

二、行迁移/行链接的检测

通过前面的介绍我们知道,行链接主要是由于数据库的 db_block_size 不够大,对于

一些大的字段没法在一个 block 中存储下,从而产生了行链接。对于行链接我们除了增大

db_block_size 之外没有别的任何办法去避免,但是因为数据库建立后 db_block_size 是不

可改变的(在 9i 之前),对于 Oracle9i 的数据库我们可以对不同的表空间指定不同的

db_block_size,因此行链接的产生几乎是不可避免的,也没有太多可以调整的地方。行迁移

则主要是由于更新表的时候,由于表的 pctfree 参数设置太小,导致 block 中没有足够的空

间去容纳更新后的记录,从而产生了行迁移。对于行迁移来说就非常有调整的必要了,因为

这个是可以调整和控制清除的。

如何检测数据库中存在有了行迁移和行链接呢?我们可以利用 Oracle 数据库自身提

供的脚本 utlchain.sql(在$ORACLE_HOME/rdbms/admin 目录下)生成 chained_rows 表,然

第 50 页 共 131 页

Page 51: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

后利用 ANALYZE TABLE table_name LIST CHAINED ROWS INTO chained_rows 命令逐个分析

表,将分析的结果存入 chained_rows 表中。从 utlchain.sql 脚本中我们看到 chained_rows

的建表脚本,对于分区表,cluster 表都是适用的。然后可以使用拼凑语句的办法生成分析

所需要的表的脚本,并执行脚本将具体的分析数据放入 Chained_rows 表中,例如下面是分

析一个用户下所有表的脚本:

SPOOL list_migation_rows.sql

SET ECHO OFF

SET HEADING OFF

SELECT 'ANALYZE TABLE ' || table_name || ' LIST CHAINED ROWS INTO chained_rows;'

FROM user_tables;

SPOOL OFF

然后查询 chained_rows 表,可以具体查看某张表上有多少的行链接和行迁移。

SELECT table_name, count(*) from chained_rows GROUP BY table_name;

当然,也可以查询 v$sysstat 视图中的’table fetch continued row’列得到当前的

行链接和行迁移数量。

SELECT name, value FROM v$sysstat WHERE name = 'table fetch continued row';

可以使用如下的脚本来直接查找存在有行链接和行迁移的表,自动完成所有的分析和统

计。

accept owner prompt " Enter the schema name to check for Row Chaining (RETURN for All):

"

prompt

prompt

accept table prompt " Enter the table name to check (RETURN for All tables owned by

&owner): "

prompt

prompt

set head off serverout on term on feed off veri off echo off

!clear

prompt

declare

v_owner varchar2(30);

v_table varchar2(30);

v_chains number;

v_rows number;

v_count number := 0;

sql_stmt varchar2(100);

dynamicCursor INTEGER;

dummy INTEGER;

cursor chains is

select count(*) from chained_rows;

第 51 页 共 131 页

Page 52: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

cursor analyze is

select owner, table_name

from sys.dba_tables

where owner like upper('%&owner%')

and table_name like upper('%&table%')

order by table_name;

begin

dbms_output.enable(64000);

open analyze;

fetch analyze into v_owner, v_table;

while analyze%FOUND loop

dynamicCursor := dbms_sql.open_cursor;

sql_stmt := 'analyze table '||v_owner||'.'||v_table||' list chained rows into

chained_rows';

dbms_sql.parse(dynamicCursor, sql_stmt, dbms_sql.native);

dummy := dbms_sql.execute(dynamicCursor);

dbms_sql.close_cursor(dynamicCursor);

open chains;

fetch chains into v_chains;

if (v_chains != 0) then

if (v_count = 0) then

dbms_output.put_line(CHR(9)||CHR(9)||CHR(9)||'<<<<< Chained Rows Found >>>>>');

v_count := 1;

end if;

dynamicCursor := dbms_sql.open_cursor;

sql_stmt := 'Select count(*) v_rows'||' From '||v_owner||'.'||v_table;

dbms_sql.parse(dynamicCursor, sql_stmt, dbms_sql.native);

dbms_sql.DEFINE_COLUMN(dynamicCursor, 1, v_rows);

dummy := dbms_sql.execute(dynamicCursor);

dummy := dbms_sql.fetch_rows(dynamicCursor);

dbms_sql.COLUMN_VALUE(dynamicCursor, 1, v_rows);

dbms_sql.close_cursor(dynamicCursor);

dbms_output.put_line(v_owner||'.'||v_table);

dbms_output.put_line(CHR(9)||'---> Has '||v_chains||' Chained Rows and '||v_rows||'

Num_Rows in it!');

dynamicCursor := dbms_sql.open_cursor;

sql_stmt := 'truncate table chained_rows';

dbms_sql.parse(dynamicCursor, sql_stmt, dbms_sql.native);

dummy := dbms_sql.execute(dynamicCursor);

dbms_sql.close_cursor(dynamicCursor);

v_chains := 0;

end if;

close chains;

fetch analyze into v_owner, v_table;

第 52 页 共 131 页

Page 53: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

end loop;

if (v_count = 0) then

dbms_output.put_line('No Chained Rows found in the '||v_owner||' owned Tables!');

end if;

close analyze;

end;

/

set feed on head on

prompt

三、行迁移和行链接的清除

由于对于行链接来说只能增大 db_block_size 来清除,而 db_block_size 在创建了数据

库后又是不能改变了的,所以这里对行链接的清除不做过多的叙述了,主要是针对行迁移来

谈谈在实际的生产系统中如何去清除。

对于行迁移的清除,一般来说分为两个步骤:第一步,控制住行迁移的增长,使其不在

增多;第二步,清除掉以前存在的行迁移。

众所周知,行迁移产生的主要原因是因为表上的 pctfree 参数设置过小导致的,而要实

现第一步控制住行迁移的增长,就必须设置好一个正确合适的 pctfree 参数,否则即使清除

了当前的行迁移后马上又会产生很多新的行迁移。当然,这个参数也不是越大越好的,如果

pctfree 设置的过大,会导致数据块的利用率低,造成空间的大量浪费,因此必须设置一个

合理的 pctfree 参数。如何去确定一个表上合理的 pctfree 参数呢,一般来说有两种方法。

第一种是定量的的设定方法,就是利用公式来设定 pctfree 的大小。先使用 ANALYZE

TABLE table_name ESTIMATE STATISTICS 命令来分析要修改 pctfree 的表,然后查看

user_tables 中的 AVG_ROW_LEN 列值,得到一个平均行长 AVG_ROW_LEN1,然后大量的对表操

作之后,再次使用上述命令分析表,得到第二个平均行长 AVG_ROW_LEN2,然后运用公式 100

* (AVG_ROW_LEN2-AVG_ROW_LEN1)/(AVG_ROW_LEN2-AVG_ROW_LEN1 + 原始的 AVG_ROW_LEN)

得出的结果就是定量计算出来的一个合适的 pctfree 的值。这种方法因为是定量计算出来

的,可能不一定会很准确,而且因为要分析表,所以对于使用 RBO 执行计划的系统不是很适

用。例如:avg_row_len_1 = 60,avg_row_len_2 = 70,则平均修改量为 10,PCTFREE 应

调整为 100 * 10 /(10 + 60)= 16.7% 。

第二种是差分微调的方法,先查询到当前表的 pctfree 的值,然后监控和调整 pctfree

参数,每次增加一点 pctfree 的大小,每次增加的比例不要超过 5 个百分点,然后使用

ANALYZE TABLE TABLE_NAME LIST CHAINED ROWS INTO chained_rows 命令分析每次所有的

行迁移和行链接的增长情况,对于不同的表采取不同的增长比例,对于行迁移增长的比较快

的表 pctfree 值就增加的多点,对于增长慢的表就增加的少点,直到表的行迁移基本保持不

增长了为止。但是注意不要把 pctfree 调的过大,一般在 40%以下就可以了,否则会造成空

间的很大浪费和增加数据库访问的 IO。

使用上述的方法控制住了当前表的行迁移的增长之后,就可以开始清除之前表上存在的

第 53 页 共 131 页

Page 54: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

行迁移了。是否清除掉行迁移,关系到系统的性能是否能够有很大的提高。因此,对于以前

存在的行迁移是一定而且必须要清除掉的。清除掉已经存在的行迁移有很多方法,但是并不

是所有的方法都能适用所有的情况,例如表中的记录数多少,表上的关联多少、表上行迁移

的数量多少等等这些因素都会是成为制约你使用什么方法清除的条件,因此,根据表的特点

和具体情况的不同我们应该采用不同的方法去清除行迁移。下面我将逐一介绍各种清除行迁

移的方法以及它们各自适用的不同情况。

方法一:传统的清除行迁移的方法

具体步骤如下:

1. 执行$ORACLE_HOME/rdbms/admin 目录下的 utlchain.sql 脚本创建 chained_rows

表。

@$ORACLE_HOME/rdbms/admin/utlchain.sql

2. 将存在有行迁移的表(用 table_name 代替)中的产生行迁移的行的 rowid 放入到

chained_rows 表中。

ANALYZE TABLE table_name LIST CHAINED ROWS INTO chained_rows;

3. 将表中的行迁移的 row id 放入临时表中保存。

CREATE TABLE table_name_temp AS

SELECT * FROM table_name

WHERE rowid IN

(SELECT head_rowid FROM chained_rows

WHERE table_name = 'table_name');

4. 删除原来表中存在的行迁移的记录行。

DELETE table_name

WHERE rowid IN

(SELECT head_rowid

FROM chained_rows

WHERE table_name = 'table_name');

5. 从临时表中取出并重新插入那些被删除了的数据到原来的表中,并删除临时表。

INSERT INTO table_name SELECT * FROM table_name_temp;

DROP TABLE table_name_temp;

对于这种传统的清除 RM 的方法,优点是执行起来过程比较简单,容易实现。但是这种

算法的缺陷是没有考虑到表关联的情况,在大多数数据库中很多表都是和别的表之间有表关

联的,有外键的限制,这样就造成在步骤 3 中根本无法 delete 掉存在有行迁移的记录行,

所以这种方法能够适用的表的范围是有限的,只能适用于表上无任何外键关联的表。由于这

种方法在插入和删除数据的时候都没有 disable 掉索引,这样导致主要消耗时间是在删除和

第 54 页 共 131 页

Page 55: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

插入时维持索引树的均衡上了,这个对于如果记录数不多的情况时间上还比较短,但是如果

对于记录数很多的表这个所消耗的时间就不是能够接受的了。显然,这种方法在处理大数据

量的表的时候显然是不可取的。

以下是一个具体在生产数据库上清除行迁移的例子,在这之前已经调整过表的 pctfree

参数至一个合适的值了:

SQL>@$ORACLE_HOME/rdbms/admin/utlchain.sql

Table created.

SQL> ANALYZE TABLE CUSTOMER LIST CHAINED ROWS INTO chained_rows;

Table analyzed.

SQL>SELECT count(*) from chained_rows;

TABLE_NAME COUNT(*)

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

CUSTOMER 21306

1 rows selected.

查看在 CUSTOMER 表上存在的限制:

SQL>select CONSTRAINT_NAME,CONSTRAINT_TYPE,TABLE_NAME from USER_CONSTRAINTS where

TABLE_NAME='CUSTOMER';

CONSTRAINT_NAME C TABLE_NAME

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

PK_CUSTOMER1 P CUSTOMER

SQL>select CONSTRAINT_NAME,CONSTRAINT_TYPE,TABLE_NAME from USER_CONSTRAINTS where

R_CONSTRAINT_NAME='PK_CUSTOMER1';

no rows selected

SQL> CREATE TABLE CUSTOMER_temp AS

SELECT * FROM CUSTOMER WHERE rowid IN

(SELECT head_rowid FROM chained_rows

WHERE table_name = 'CUSTOMER');

Table created.

SQL>select count(*) from CUSTOMER;

COUNT(*)

----------

338299

SQL> DELETE CUSTOMER WHERE rowid IN

(SELECT head_rowid

FROM chained_rows

WHERE table_name = 'CUSTOMER');

21306 rows deleted.

SQL> INSERT INTO CUSTOMER SELECT * FROM CUSTOMER_temp;

21306 rows created.

SQL> DROP TABLE CUSTOMER_temp;

Table dropped.

SQL> commit;

Commit complete.

第 55 页 共 131 页

Page 56: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

SQL> select count(*) from CUSTOMER;

COUNT(*)

----------

338299

SQL> truncate table chained_rows;

Table truncated.

SQL> ANALYZE TABLE CUSTOMER LIST CHAINED ROWS INTO chained_rows;

Table analyzed.

SQL> select count(*) from chained_rows;

COUNT(*)

----------

0

以上整个清除两万多行的行迁移过程在三分钟左右,而且全部都在联机的状态下完成,

基本上不会对业务有什么影响,唯一就是在要清除行迁移的表上不能有对外键的限制,否则

就不能采用这个方法去清除了。

方法二:改进了的传统清除行迁移的方法

1. 执行$ORACLE_HOME/rdbms/admin 目录下的 utlchain.sql 脚本创建 chained_rows

表。

2. 禁用所有其它表上关联到此表上的所有限制。

3. 将表中的行迁移的 row id 放入临时表中保存。

4. 删除原来表中存在的行迁移的记录行。

5. 从临时表中取出并重新插入那些被删除了的数据到原来的表中,并删除临时表。

6. 启用所有其它表上关联到此表上的所有限制。

这种算法是对传统算法的一种改进,对于使用这种算法来清除行迁移,考虑到了表之间

的关联,还可以灵活的利用的 TOAD 工具生成的表关联信息,是一种比较适合于清除行迁移

的一种方法。但是因为使用这种方法后来需要重建索引,如果记录数很大,比如说上千万条

以上的记录的表,就不是很合适了,因为这个重建索引的时间会很长,是线性时间复杂度的,

而重建索引是会导致索引所在的表被锁定的,从而导致插入不了新的记录,重建索引的时间

太长导致记录长时间插入不了是会严重影响应用的,甚至导致数据的丢失,因此这个是使用

这个方法前必须要考虑到的一个重要因素;对于 8i 以上的版本可以使用 online 的方法来重

建索引,这样不会导致锁表,但是会有额外更多的开销,时间会很长。再者,因为这种方法

在插入记录和删除记录都是带着索引的,如果表上的行迁移比较多,这样耗时间会比较长,

而且占用资源也会比较大,因此只适用于表上行迁移存在的比较少的表。总的来说,这种方

法对于表记录太多或者是表上的行迁移太多的情况都不是很适用,比较适合表记录少和表上

行迁移都不太多的情况。

第 56 页 共 131 页

Page 57: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

以下是一个具体在生产数据库上清除行迁移的例子,在这之前已经调整过表的 pctfree

参数至一个合适的值了:

SQL>select index_name,index_type,table_name from user_indexes where

table_name='TERMINAL';

INDEX_NAME INDEX_TYPE TABLE_NAME

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

INDEX_TERMINAL_TERMINALCODE NORMAL TERMINAL

I_TERMINAL_ID_TYPE NORMAL TERMINAL

I_TERMINAL_OT_OID NORMAL TERMINAL

PK_TERMINAL_ID NORMAL TERMINAL

UI_TERMINAL_GOODIS_SSN NORMAL TERMINAL

SQL>select CONSTRAINT_NAME,CONSTRAINT_TYPE,TABLE_NAME from USER_CONSTRAINTS

where R_CONSTRAINT_NAME='PK_TERMINAL_ID';

CONSTRAINT_NAME C TABLE_NAME

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

SYS_C003200 R CONN

SQL>alter table CONN disable constraint SYS_C003200;

Table altered.

SQL>CREATE TABLE TERMINAL_temp AS

SELECT * FROM TERMINAL

WHERE rowid IN

(SELECT head_rowid FROM chained_rows

WHERE table_name = 'TERMINAL');

Table created.

SQL>select count(*) from TERMINAL_temp;

COUNT(*)

----------

8302

SQL>DELETE TERMINAL

WHERE rowid IN

(SELECT head_rowid

FROM chained_rows

WHERE table_name = 'TERMINAL');

8302 rows deleted.

SQL>INSERT INTO TERMINAL SELECT * FROM TERMINAL_temp;

8302 rows created.

SQL>alter table CONN disable constraint SYS_C003200;

Table altered.

SQL>select count(*) from terminal;

COUNT(*)

----------

647799

SQL>truncate table chained_rows;

第 57 页 共 131 页

Page 58: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

Table truncated.

SQL>ANALYZE TABLE TERMINAL LIST CHAINED ROWS INTO chained_rows;

Table analyzed.

SQL>select count(*) from chained_rows;

COUNT(*)

----------

0

从上面过程中可以看出,对 TERMINAL 这张表的行迁移清除耗时总共不到五分钟的时间,

总体来说还是比较快的。从我在生产数据库中清除行迁移的经验来说,这种方法基本适用于

大部分存在有行迁移的表。

方法三:使用 TOAD 工具清除行迁移的方法

1. 备份要清除 RM 的表。

RENAME table_name TO table_name_temp;

2. Drop 所有其它表上关联到 table_name 的外键限制。

SELECT CONSTRAINT_NAME,CONSTRAINT_TYPE,TABLE_NAME from USER_CONSTRAINTS where

R_CONSTRAINT_NAME in (SELECT CONSTRAINT_NAME from USER_CONSTRAINTS where

TABLE_NAME='table_name' AND CONSTRAINT_TYPE=’P’);

ALTER TABLE table_name DROP CONSTRAINT XXXX;(XXXX 为上述的查询结果)

3. 重建 1 中被 rename 的表。

CREATE TABLE table_name AS SELECT * FROM table_name_temp WHERE 0 = 1;

4. 重建表中原来的数据。

INSERT /*+ APPEND */ INTO table_name SELECT * FROM table_name_temp;

5. 删除在 table_name_temp 上的索引和关联其他表的外键。

6. 在 table_name 上建立和原来一样的索引、主键和所有的外键限制。

7. 重新编译相关的存储过程、函数和包。

8. 删除表 table_name_temp。

对于使用这种方法来清除行迁移,全部的代码都是可以由 TOAD 工具来生成的。由于此

方法把表上的关联考虑进去了,也是一种比较的全面的考虑的一种清除方法,而且在清除过

程中重建了表和索引,对于数据库的存储和性能上都有提高。因为这种方法一开始是 rename

表为临时表,然后重建一个新表出来的,因此需要两倍的表的空间,因此在操作之前一定要

检查要清除的表所在的表空间的 free 空间是否足够;但是也有一定的缺陷,因为在新表中

重新插入原来的数据后需要重建索引和限制,因此在时间和磁盘的空间上都有比较大的开

销,而且对于前台的应用可能会有一段时间的中断,当然,这个中断时间就主要是消耗在重

建索引和重建限制上了,而时间的长短跟需要重建索引和限制的多少以及表的记录多少等等

因素都有关系。使用这种方法对于 7*24 小时要求的系统上清除行迁移不是很合适,因为使

用这种方法会导致系统可能有一段时间的停机,如果系统的实时性比较高,这种方法就不是

很适用了。

第 58 页 共 131 页

Page 59: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

方法四:使用 EXP/IMP 工具清除行迁移的方法

1. 使用 EXP 导出存在有行迁移的表。

2. 然后 TRUNCATE 原来的表。

3. IMP 开始导出的表。

4. 重建表上所有的索引。(可选)

使用这种方法可以不用重建索引,省去了这部分时间,但是完成之后索引的使用效率不

会很高, 好是在以后逐步的在线重建索引,这样是可以不需要中断业务的。但是需要考虑

的是 IMP 的时候会比较慢,而且会占用比较大的 IO,应该选择在应用不是很繁忙的时候做

这项工作,否则会对应用的正常运行产生较大的影响。对于这种方法还存在有一个比较大的

弊端,就是在 EXP 表的时候要保证该表是没有数据的更新或者是只读状态的,不能对表有插

入或者更新操作,否则会导致数据的丢失。

SQL> select count(*) from test;

COUNT(*)

----------

169344

SQL> truncate table chained_rows;

Table truncated.

SQL> analyze table test LIST CHAINED ROWS INTO chained_rows;

Table analyzed.

SQL> select count(*) from chained_rows;

COUNT(*)

----------

3294

$ exp allan/allan file=test.dmp tables=test

Export: Release 9.2.0.3.0 - Production on Sun Jun 6 13:50:08 2004

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

Connected to: Oracle9i Enterprise Edition Release 9.2.0.3.0 - Production

With the Partitioning, OLAP and Oracle Data Mining options

JServer Release 9.2.0.3.0 - Production

Export done in ZHS16GBK character set and AL16UTF16 NCHAR character set

About to export specified tables via Conventional Path ...

. . exporting table TEST 169344 rows exported

Export terminated successfully without warnings.

$ sqlplus allan/allan

SQL*Plus: Release 9.2.0.3.0 - Production on Sun Jun 6 13:50:43 2004

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

Connected to:

Oracle9i Enterprise Edition Release 9.2.0.3.0 - Production

第 59 页 共 131 页

Page 60: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

With the Partitioning, OLAP and Oracle Data Mining options

JServer Release 9.2.0.3.0 - Production

SQL> truncate table test;

Table truncated.

SQL> exit

Disconnected from Oracle9i Enterprise Edition Release 9.2.0.3.0 - Production

With the Partitioning, OLAP and Oracle Data Mining options

JServer Release 9.2.0.3.0 - Production

$ imp allan/allan file=test.dmp full=y ignore=y buffer=5000000

Import: Release 9.2.0.3.0 - Production on Sun Jun 6 13:51:24 2004

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

Connected to: Oracle9i Enterprise Edition Release 9.2.0.3.0 - Production

With the Partitioning, OLAP and Oracle Data Mining options

JServer Release 9.2.0.3.0 - Production

Export file created by EXPORT:V09.02.00 via conventional path

import done in ZHS16GBK character set and AL16UTF16 NCHAR character set

. importing ALLAN's objects into ALLAN

. . importing table "TEST" 169344 rows imported

Import terminated successfully without warnings.

$ sqlplus allan/allan

SQL*Plus: Release 9.2.0.3.0 - Production on Sun Jun 6 13:52:53 2004

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

Connected to:

Oracle9i Enterprise Edition Release 9.2.0.3.0 - Production

With the Partitioning, OLAP and Oracle Data Mining options

JServer Release 9.2.0.3.0 - Production

SQL> select count(*) from test;

COUNT(*)

----------

169344

SQL> select index_name from user_indexes where table_name='TEST';

INDEX_NAME

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

OBJ_INDEX

SQL> alter index OBJ_INDEX rebuild online;

Index altered.

SQL> truncate table chained_rows;

Table truncated.

SQL> analyze table test LIST CHAINED ROWS INTO chained_rows;

Table analyzed.

SQL> select count(*) from chained_rows;

COUNT(*)

----------

0

第 60 页 共 131 页

Page 61: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

方法五:使用 MOVE 命令来清除行迁移的方法

1. 查看要清除行迁移的表所在的表空间。

Select table_name,tablespace_name from user_tables where

table_name='table_name’;

2. 查看要清除行迁移的表上的具体索引。

select index_name,table_name from user_indexes where table_name=‘table_name’;

3. Move 要清除 RM 的表到指定的表空间中去。

alter table table_name move tablespace tablespace_name;

4. 重建表上的所有索引。

alter index index_name rebuild;

这种方法适用于 8i 及其以上的数据库版本,主要是利用数据库的一个 MOVE 命令来实现

行迁移的清除的,MOVE 命令的实质其实就是 INSERT … SELECT 的一个过程,在 MOVE 表的

过程中是需要两倍的原来的表大小的,因为中间过程是要保留原来的旧表的,新表创建完成

后旧表就被删除并释放空间了。MOVE 的时候要注意后面一定要加上表空间参数,所以必须

要先知道表所在的表空间;因为 MOVE 表之后需要重建索引,所以之前要确定表上的所有的

索引。

这种方法对于表记录数很大或者表上索引太多的情况不太适用,因为本身的 MOVE 就会

很慢, 而且 MOVE 表的时候会要锁定表,时间长了会导致对表的其他操作出现问题,导致数

据插入不了丢失数据;MOVE 表后还要重建索引,索引太多了的话重建的时间也会太长;再

者,这个方法也比较消耗资源,因此强烈建议在业务不繁忙的时候再执行。

以下是一个具体在生产数据库上清除行迁移的例子,在这之前已经调整过表的 pctfree

参数至一个合适的值了:

SQL>ANALYZE TABLE SERVICE LIST CHAINED ROWS INTO chained_rows;

Table analyzed.

SQL>SELECT count(*) from chained_rows;

COUNT(*)

----------

9145

SQL>select table_name,tablespace_name from user_tables where

table_name='SERVICE';

TABLE_NAME TABLESPACE_NAME

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

SERVICE DATA

SQL>select index_name,table_name from user_indexes where table_name='SERVICE';

INDEX_NAME TABLE_NAME

第 61 页 共 131 页

Page 62: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

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

I_SERVICE_ACCOUNTNUM SERVICE

I_SERVICE_DATEACTIVATED SERVICE

I_SERVICE_SC_S SERVICE

I_SERVICE_SERVICECODE SERVICE

PK_SERVICE_SID SERVICE

SQL>select count(*) from SERVICE;

COUNT(*)

----------

518718

SQL>alter table SERVICE move tablespace DATA;

Table altered.

SQL>alter index I_SERVICE_ACCOUNTNUM rebuild;

Index altered.

SQL>alter index I_SERVICE_DATEACTIVATED rebuild;

Index altered.

SQL>alter index I_SERVICE_SC_S rebuild;

Index altered.

SQL>alter index I_SERVICE_SERVICECODE rebuild;

Index altered.

SQL>alter index PK_SERVICE_SID rebuild;

Index altered.

SQL>truncate table chained_rows;

Table truncated.

SQL>ANALYZE TABLE SERVICE LIST CHAINED ROWS INTO chained_rows;

Table analyzed.

SQL>SELECT count(*) from chained_rows;

COUNT(*)

----------

0

利用 MOVE 命令来清除行迁移,执行的命令都相对比较的简单,上面的例子中清除表

SERVCIE 中的行迁移的时间大概在五分钟左右,其中 move 命令执行的时间为不到两分钟,

也就是锁表的时间大概是不到两分钟,对于大多数的应用来说一般问题都是不大的,放在系

统闲的时候执行基本上不会对应用产生什么太多的影响。

方法六:对于一些行迁移数量巨大而且表记录数巨大的表的行迁移的

清除方法

1. 使用 TOAD 工具或者别的方法获取存在有大量行迁移并且表记录很大的表的重建表

的 SQL,然后保存为脚本。

2. 使用 RENAME 命令将原始表重命名为一个备份表,然后删除别的表对原始表上的限

第 62 页 共 131 页

Page 63: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

制、以及原始表上的外键和索引。

3. 利用 1 中生成的脚本重建原始表,以及表上的限制,外键,索引等对象。

4. 然后按表模式导出 2 中备份的表,然后导入到另外的一个临时中转的数据库库中,

因为表的名字已经改变,所以导入后需要 RENAME 表为原来的名字,然后重新导出,

后再导入到原来的数据库中。

这种方法主要是用来针对一些数据量比较大,并且表上的行迁移也比较多的表的行迁移

清除。对于这些大表的行迁移的清除,正常来说都需要停应用一段较长时间才能够清除掉,

让人感觉比较的头疼,对于 7*24 小时的应用来说,down 机的时间越长损失则越大,当然是

要尽量的减短 down 机的时间。但是因为表本身比较大,不管怎样做什么操作都是会比较耗

费时间和资源的,但是如果应用在某段时间内主要是以插入数据为主,更新数据和删除数据

都很少的,因此可以考虑可以采用这么一种方法:先重命名表,然后重新建立一个和原来一

样的表,用来保证之后的应用的数据是可以正常插入的,从而使应用不用停很久,因为重建

一个没有任何数据的表结构的过程是很短暂的,大概需要几秒钟的时间,而重建好表了后就

能保证应用能够正常的写入数据,从而使应用几乎不用停顿,然后把开始重命名的原始表按

表模式导出,因为表的名字已经被改变,因此需要一个临时库来导入这些数据,然后重命名

回原来的名字,然后按原来的表名导出后再重新导入原始数据库,这样操作起来虽然会比较

麻烦,但是却是一种很有效很实际的方法,速度也很快,导出后导入,因为本身表结构已经

建立好了,不需要其他任何的多的操作,而且 关键的是这种方法所需要的 down 机时间是

短的。

SQL>ALTER TABLE USER.PAY RENAME TO PAY_X ;

然后导出 PAY_X 表;

$ exp USER/USER file=PAY_X.dmp tables=PAY_X

SQL>ALTER TABLE USER.BATCHPAYMENTDETAIL DROP CONSTRAINT

FK_BATCHPAYMENTDETAIL_OPAYID ;

SQL>ALTER TABLE USER.DEPOSITCLASSIFY DROP CONSTRAINT FK_DEPOSITCLASSIFY2 ;

SQL>ALTER TABLE USER.DEPOSITCREDITLOG DROP CONSTRAINT FK_DEPOSITCREDITLOG2 ;

SQL>ALTER TABLE USER.DEPOSIT DROP CONSTRAINT SYS_C003423 ;

SQL>ALTER TABLE USER.PAY_X DROP CONSTRAINT SYS_C003549 ;

SQL>DROP INDEX USER.I_PAY_STAFFID ;

SQL>CREATE TABLE USER.PAY

(

PAYID NUMBER(9),

ACCOUNTNUM NUMBER(9),

TOTAL NUMBER(12,2),

PREVPAY NUMBER(12,2),

PAY NUMBER(12,2),

STAFFID NUMBER(9),

PROCESSDATE DATE,

PAYNO CHAR(12),

TYPE CHAR(2) DEFAULT '0',

第 63 页 共 131 页

Page 64: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

PAYMENTMETHOD CHAR(1) DEFAULT '0',

PAYMENTMETHODID VARCHAR2(20),

BANKACCOUNT VARCHAR2(32),

PAYMENTID NUMBER(9),

STATUS CHAR(1) DEFAULT '0',

MEMO VARCHAR2(255),

SERVICEID NUMBER(9),

CURRENTDEPOSITID NUMBER(9),

SHOULDPROCESSDATE DATE DEFAULT sysdate,

ORIGINALEXPIREDATE DATE,

ORIGINALCANCELDATE DATE,

EXPIREDATE DATE,

CANCELDATE DATE,

DEPOSITTYPE CHAR(1)

)

TABLESPACE USER

PCTUSED 95

PCTFREE 5

INITRANS 1

MAXTRANS 255

STORAGE (

INITIAL 7312K

NEXT 80K

MINEXTENTS 1

MAXEXTENTS 2147483645

PCTINCREASE 0

FREELISTS 1

FREELIST GROUPS 1

BUFFER_POOL DEFAULT

)

NOLOGGING

NOCACHE

NOPARALLEL;

SQL>CREATE INDEX USER.I_PAY_STAFFID ON USER.PAY

(STAFFID)

NOLOGGING

TABLESPACE USER

PCTFREE 5

INITRANS 2

MAXTRANS 255

STORAGE (

INITIAL 1936K

NEXT 80K

MINEXTENTS 1

第 64 页 共 131 页

Page 65: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

MAXEXTENTS 2147483645

PCTINCREASE 0

FREELISTS 1

FREELIST GROUPS 1

BUFFER_POOL DEFAULT

)

NOPARALLEL;

SQL>CREATE UNIQUE INDEX USER.PK_PAY_ID ON USER.PAY

(PAYID)

NOLOGGING

TABLESPACE USER

PCTFREE 5

INITRANS 2

MAXTRANS 255

STORAGE (

INITIAL 1120K

NEXT 80K

MINEXTENTS 1

MAXEXTENTS 2147483645

PCTINCREASE 0

FREELISTS 1

FREELIST GROUPS 1

BUFFER_POOL DEFAULT

)

NOPARALLEL;

SQL>ALTER TABLE USER.PAY ADD (

FOREIGN KEY (STAFFID)

REFERENCES USER.STAFF (STAFFID));

SQL>ALTER TABLE USER.DEPOSITCLASSIFY ADD

CONSTRAINT FK_DEPOSITCLASSIFY2

FOREIGN KEY (PAYID)

REFERENCES USER.PAY (PAYID) ;

SQL>ALTER TABLE USER.DEPOSITCREDITLOG ADD

CONSTRAINT FK_DEPOSITCREDITLOG2

FOREIGN KEY (PAYID)

REFERENCES USER.PAY (PAYID) ;

SQL>ALTER FUNCTION "USER"."GENERATEPAYNO" COMPILE ;

SQL>ALTER PROCEDURE "USER"."ENGENDERPRVPAY" COMPILE ;

SQL>ALTER PROCEDURE "USER"."ISAP_ENGENDERPRVPAY" COMPILE ;

SQL>ALTER PROCEDURE "USER"."SPADDCREDITDEPOSIT" COMPILE ;

SQL>ALTER PROCEDURE "USER"."SPADDDEPOSITWITHOUTCARD" COMPILE ;

SQL>ALTER PROCEDURE "USER"."SPADJUSTLWDEPOSIT" COMPILE ;

……

然后将导出的表 PAY_X 的 dmp 文件导入一个临时的数据库中,然后在临时数据库中将其表名

第 65 页 共 131 页

Page 66: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

重新命名为 PAY,再按表模式将其导出。

imp USER/USER file= PAY_x.dmp tables=PAY ignore=y

SQL>rename PAY_X to PAY;

$ exp USER/USER file=PAY.dmp tables=PAY

后将这个 dmp 文件导入正式的生产数据库中即可。

以上的过程在重建好 PAY 表后整个应用就恢复正常了,而重命名表后重建表的时间是非

常之短的,我测试的时间大概是在几分钟之内就可以做完了,新数据就可以插入表了,剩下

的工作就是将旧的数据导入数据库,这个工作的时间要求上就没有那么高了,因为应用已经

正常了,一般来说利用晚上业务不忙的时候都可以把一张表的数据导入完成的。

以上的六种清除行迁移的方法各有各自的优缺点,分别适用于不同的情况下使用,利用

以上的几种清除行迁移的方法基本上就能完全清除掉系统中的存在的行迁移了,当然,具体

的生产环境中还需要具体问题具体分析的,针对不同类型的系统,系统中不同特点的表采用

不同的清除方法,尽量的减少停数据库的时间,以保证应用的不间断稳定运行。

[作者简介]

Coolyl:现任 itpub Oracle 管理版版主。

曾任职于国内某大型软件企业做 oracle 数据库的技术支持,客户遍及全国各个行业,尤其是电信,政

府行业。

现任职于某外资电信企业华北区分公司,DBA,负责华北区 40 多个数据库系统的维护,对大型数据库

管理经验丰富。

擅长数据库的维护,对于数据库的安装,调整,备份方面有自己独到的经验。同时也给一些国内的大

型企业做过 oracle 的培训,有一定的培训经验。

曾做过很多大型项目的数据库维护和支持工作,对 oracle 的维护有相当多的实际经验,善于现场解决

问题。

《Oracle 数据库 DBA 专题技术精粹》一书的主编及主要作者.

End

第 66 页 共 131 页

Page 67: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

关于索引使用情况的简单测试

By bzszp

前言:

索引,无疑是提高 sql 语句查询性能的重要手段之一,但是,往往有些时候,明明创建

了索引,但查询性能却没有什么改善,纠其原因,大部分情况是由于语句或者数据的问题,

ORACLE 优化其根本没有使用你辛苦创建的索引。这里我们就一起看看到底什么情况下

ORACLE 会使用索引,而什么情况下不使用。

本文适宜读者范围: 初、中级用户

系统环境:

OS: Windows 2000 Server sp4

Oracle: 8.1.6

创建测试表,并插入少量测试数据:

SQL> Create table tb_test (col_A number,col_B varchar2(20),col_C date); 表已创建。 SQL> declare 2 v_colC date:=to_date('2000-01-01','yyyy-mm-dd'); 3 begin 4 for i in 1..20 loop 5 insert into tb_test values(i,'data string '||i,v_colC+i); 6 end loop; 7 end; 8 / PL/SQL 过程已成功完成。 SQL> select count(*) from tb_test; COUNT(*) --------- 20

先看一下,没有创建任何索引的情况,sql 语句是如何执行的:

SQL> set autotrace on; SQL> select * from tb_test;

第 67 页 共 131 页

Page 68: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

COL_A COL_B COL_C --------- -------------------- ---------- 1 data string 1 02-1 月 -00 2 data string 2 03-1 月 -00 3 data string 3 04-1 月 -00 4 data string 4 05-1 月 -00 5 data string 5 06-1 月 -00 6 data string 6 07-1 月 -00 7 data string 7 08-1 月 -00 8 data string 8 09-1 月 -00 9 data string 9 10-1 月 -00 10 data string 10 11-1 月 -00 11 data string 11 12-1 月 -00 12 data string 12 13-1 月 -00 13 data string 13 14-1 月 -00 14 data string 14 15-1 月 -00 15 data string 15 16-1 月 -00 16 data string 16 17-1 月 -00 17 data string 17 18-1 月 -00 18 data string 18 19-1 月 -00 19 data string 19 20-1 月 -00 20 data string 20 21-1 月 -00 已选择 20 行。 Execution Plan --------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 TABLE ACCESS (FULL) OF 'TB_TEST'

跟预计的一样,执行的是全表扫描。

给 col_A 创建索引后的情况呢:

SQL> create unique index idx_test_colA on tb_test(col_A); 索引已创建。 SQL> select * from tb_test where col_A>15; COL_A COL_B COL_C --------- -------------------- ---------- 16 data string 16 17-1 月 -00

第 68 页 共 131 页

Page 69: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

17 data string 17 18-1 月 -00 18 data string 18 19-1 月 -00 19 data string 19 20-1 月 -00 20 data string 20 21-1 月 -00 Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TB_TEST' 2 1 INDEX (RANGE SCAN) OF 'IDX_TEST_COLA' (UNIQUE)

刚刚创建的索引被使用了,也达到了预期效果。

先别高兴,我们继续看下面这种情况,为 col_C 也创建了一个索引(idx_test_colC)。

SQL> create index idx_test_colC on tb_test(col_C); 索引已创建。 SQL> select * from tb_test where to_char(col_C,'yyyy-mm-dd')>'2000-01-10'; COL_A COL_B COL_C --------- -------------------- ---------- 10 data string 10 11-1 月 -00 11 data string 11 12-1 月 -00 12 data string 12 13-1 月 -00 13 data string 13 14-1 月 -00 14 data string 14 15-1 月 -00 15 data string 15 16-1 月 -00 16 data string 16 17-1 月 -00 17 data string 17 18-1 月 -00 18 data string 18 19-1 月 -00 19 data string 19 20-1 月 -00 20 data string 20 21-1 月 -00 已选择 11 行。 Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 TABLE ACCESS (FULL) OF 'TB_TEST'

由于在 col_C 列上面使用了 to_char()函数,索引不会使用,而执行的是全表扫描,如

果数据量很大的话,这条 sql 语句的执行效率可想而知了。这种情况在软件开发过程中是比

第 69 页 共 131 页

Page 70: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

较常见的。

更正后的效果:

SQL> select * from tb_test where col_C>=to_date('2000-01-10','yyyy-mm-dd'); COL_A COL_B COL_C --------- -------------------- ---------- 9 data string 9 10-1 月 -00 10 data string 10 11-1 月 -00 11 data string 11 12-1 月 -00 12 data string 12 13-1 月 -00 13 data string 13 14-1 月 -00 14 data string 14 15-1 月 -00 15 data string 15 16-1 月 -00 16 data string 16 17-1 月 -00 17 data string 17 18-1 月 -00 18 data string 18 19-1 月 -00 19 data string 19 20-1 月 -00 20 data string 20 21-1 月 -00 已选择 12 行。 Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TB_TEST' 2 1 INDEX (RANGE SCAN) OF 'IDX_TEST_COLC' (NON-UNIQUE)

表中数据缩小为 10 条

SQL> truncate table tb_test; 表已截掉。 SQL> declare 2 v_colC date:=to_date('2000-01-01','yyyy-mm-dd'); 3 4 begin 5 for i in 1..10 loop 6 insert into tb_test values(i,'data string '||i,v_colC+i); 7 end loop; 8 end; 9 /

第 70 页 共 131 页

Page 71: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

PL/SQL 过程已成功完成。 SQL> select * from tb_test; COL_A COL_B COL_C ---------- -------------------- ------------------- 1 data string 1 2000-01-02 00:00:00 2 data string 2 2000-01-03 00:00:00 3 data string 3 2000-01-04 00:00:00 4 data string 4 2000-01-05 00:00:00 5 data string 5 2000-01-06 00:00:00 6 data string 6 2000-01-07 00:00:00 7 data string 7 2000-01-08 00:00:00 8 data string 8 2000-01-09 00:00:00 9 data string 9 2000-01-10 00:00:00 10 data string 10 2000-01-11 00:00:00 已选择 10 行。 Execution Plan ---------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 TABLE ACCESS (FULL) OF 'TB_TEST'

由于整个表的数据量小于一次读取的大小,因此,使用索引的话反而不如直接进行全表

扫描效率高。

把数据量增加到 200000 行,

SQL> declare 2 v_colC date:=to_date('2000-01-01','yyyy-mm-dd'); 3 begin 4 for i in 1..200000 loop 5 insert into tb_test values(i,'data string '||i,v_colC+i/24); 6 if mod(i,5000)=0 then –防止回滚段空间不够,5000 行提交一次 7 commit; 8 end if; 9 end loop; 10 end; 11 / PL/SQL 过程已成功完成。 SQL> select count(*) from tb_test;

第 71 页 共 131 页

Page 72: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

COUNT(*) --------- 200000 Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 SORT (AGGREGATE) 2 1 TABLE ACCESS (FULL) OF 'TB_TEST'

不知大家注意到没有,上面的 select count(*) from tb_test;执行的是全表扫描,如

果使用 select count(col_A) from tb_test;(col_A 创建了 unique index)是否就会避免

全表扫描呢?select count(1) from tb_test 的情况呢?

我们马上就来看看

SQL> select count(col_A) from tb_test; COUNT(COL_A) ------------ 200000 Execution Plan ------------------------------------------------ 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 SORT (AGGREGATE) 2 1 TABLE ACCESS (FULL) OF 'TB_TEST' SQL> select count(1) from tb_test; COUNT(1) --------- 200000 Execution Plan ----------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 SORT (AGGREGATE) 2 1 TABLE ACCESS (FULL) OF 'TB_TEST'

可见,对于检索某个表所包含的数据行数的语句来说,count(*)与 count(col_A)以及

count(1)等执行的效率是同样的。

第 72 页 共 131 页

Page 73: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

比较下面两种情况,看看有什么区别

SQL> select col_A,col_B from tb_test where col_A between 190000 and 190010; COL_A COL_B --------- -------------------- 190000 data string 190000 190001 data string 190001 190002 data string 190002 190003 data string 190003 190004 data string 190004 190005 data string 190005 190006 data string 190006 190007 data string 190007 190008 data string 190008 190009 data string 190009 190010 data string 190010 已选择 11 行。 Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TB_TEST' 2 1 INDEX (RANGE SCAN) OF 'IDX_TEST_COLA' (UNIQUE) SQL> create index idx_test_colA_B on tb_test(col_A,col_B); 索引已创建。 SQL> select col_A,col_B from tb_test where col_A between 190000 and 190010; COL_A COL_B --------- -------------------- 190000 data string 190000 190001 data string 190001 190002 data string 190002 190003 data string 190003 190004 data string 190004 190005 data string 190005 190006 data string 190006 190007 data string 190007 190008 data string 190008 190009 data string 190009

第 73 页 共 131 页

Page 74: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

190010 data string 190010 已选择 11 行。 Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 INDEX (RANGE SCAN) OF 'IDX_TEST_COLA_B' (NON-UNIQUE)

我先执行了 select col_A,col_B from tb_test where col_A between 190000 and

190010,执行计划显示根据 IDX_TEST_COLA 索引执行了局部检索(range scan),紧接着根

据 index 提供的 rowid 进行了 rowid scan;而当为 col_A 以及 col_B 创建了组合索引

idx_test_colA_B 后,执行同样的语句,则只需要对 idx_test_colA_B 执行 index range scan

就可以了,这是由于创建组合索引以后,索引中包含了 col_A 以及 col_B 的数据,满足了

sql 语句的需要(select col_A,col_B from …),不需要根据 rowid 找到数据行读取了,

这就是组合索引存在意义所在。

如果需要的结果集中包含其它非组合索引列,进行 rowid scan 就是必须的了,不过不

要担心,rowid scan 效率也是非常高的,不会对性能造成很大影响,。

SQL> select * from tb_test where col_A between 190000 and 190010; COL_A COL_B COL_C --------- -------------------- ---------- 190000 data string 190000 03-9 月 -21 190001 data string 190001 03-9 月 -21 190002 data string 190002 03-9 月 -21 190003 data string 190003 03-9 月 -21 190004 data string 190004 03-9 月 -21 190005 data string 190005 03-9 月 -21 190006 data string 190006 03-9 月 -21 190007 data string 190007 03-9 月 -21 190008 data string 190008 04-9 月 -21 190009 data string 190009 04-9 月 -21 190010 data string 190010 04-9 月 -21 已选择 11 行。 Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TB_TEST' 2 1 INDEX (RANGE SCAN) OF 'IDX_TEST_COLA_B' (NON-UNIQUE)

第 74 页 共 131 页

Page 75: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

总结:

随着 ORACLE 版本的不断升级,ORACLE 的优化策略也将越来越合理。对于一般的应用系

统来说,通过合理的使用索引便可以解决 sql 性能问题,至于那些如果由于其它原因而导致

sql 性能低下的,这里就不做讨论了。

注:由于时间以及作者水平原因,文中如有错误或者介绍不全面的地方,欢迎指正。

[作者简介]

宋志平,常用网名 bzszp,现任 CSDN ORACLE 版大版主。

目前就职于山东青岛某软件公司,一直从事 ORACLE 开发以及相关工作。

在 oracle sql 语句以及 pl/sql 开发方面经验丰富,对 oracl 优化方面有所了解。

联系方式:[email protected]

End

第 75 页 共 131 页

Page 76: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

Oracle SQL 优化手册

翻译:Snowywolf

原文名称:Oracle SQL Tuning Pocket Reference 原著:Mark Gurry 出版商:O’Reilly 出版日期:2002 年 1 月 ISBN:0-596-00268-8 版权信息:O’Relly NetWork Safari Bookshelf

前言

本文是有关 Oracle SQL 优化的一个简明参考手册,而并不是一个全面的 Oracle 优化文

档。

完成本文的目标是将我们在实际工作中的优化经验共享给读者,我们优化过许多 Oracle

站点,这些站点中的很大一部分,尤其是大的站点,比如银行、大的金融机构、证券交易所

以及电子商务站点等,对性能的要求都非常高。

现在的应用系统对高可用性的要求越来越高,很多的应用开始部署为 24*7,程序中如何

使 SQL 运行得更快已成为迫切的任务。当完成一个 SQL 语句,我们必须确保它能够被准确、

快速地执行;当往一个表里添加一个索引,我们必须确保它不会对现有的 SQL 语句产生不利

的影响。本文将专注于解决这些方面的问题。

现在的许多站点使用了第三方的软件包,比如:Peoplesoft、SAP、Oracle Applications、

Siebel、Keystone 等等,优化这类程序非常困难,因为你不能访问到或是修改它们的代码,

但是不必失去信心,本文将给出一些窍门和技巧来帮助你优化针对这类的软件包的应用。

本文将尽力给出这样的信息:我们坚信,总有方法能改进应用程序的性能,使它能更好

地满足 终用户的需求。

由于篇幅所限,本文不可能包含 Oracle 的方方面面,也不能覆盖 Oracle 优化方面的所

有问题,如果本文能在 Oracle SQL 优化方面给您些许帮助,将是作者 大的收获。

强烈建议您在应用本文提到的建议时在开发数据库或是测试数据库(非生产数据库)中

进行一下测试。

本文适宜读者范围:初中级。

一.Oracle 9i 的新特性

Oracle 的每个新版本都有令人激动的新特性,本节将简要地列举一下 Oracle 9i 在 SQL

优化方面的新特性:

第 76 页 共 131 页

Page 77: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

引入了一个新的 INIT.ORA 参数:FIRST_ROWS_n,这个参数使 CBO 在针对 OLTP

应用进行优化时能生成更优的执行路径。参数中的 n 可以是 1,10,100,或是 1000,

如果将这个参数设为 FIRST_ROWS_1,Oracle 将按照 快返回首行的方案来决定

优执行路径;如果设为 FIRST_ROWS_10,Oracle 将按照 快返回 10 行的方案

来决定 优执行路径,以此类推。

针对 CURSOR_SHARING 参数提供了一个新的选项:SIMILAR。合理地设置

CURSOR_SHARING 参数可以有效地减少 SQL 语句硬解析的次数,减少内存占用,

加快 SQL 语句解析速度,减少 latch 争用等。但如果一味地将 CURSOR_SHARING

设置为 FORCE 则会在某些情况下干扰优化器的 优结果,并且不能充分利用统计

数据,不能发挥 CBO 的 大威力。SIMILAR 选项结合了 EXACT 选项和 FORCE 选

项的优点,从而相对少地减轻了对优化器的副作用。

引入了一个新的优化提示:CURSOR_SHARING_EXACT,这个优化提示可以在对

其他语句共享游标的上下文环境中对该语句进行独立解析。实质上来说,它是在语

句一级关闭掉了设置 CURSOR_SHARING 为 FORCE 或 SIMILAR 参数的效果。

在解决数据偏斜(skewness)分布的数据列的查询问题方面性能有了极大的提升。

数据偏斜的问题在实际应用中比较常见,比如在一个应用表中会有 1,000,000 行记

录的 STATUS 字段的值是’C’表示 CLOSED,而只有 100 行记录的 STATUS 字段的值

是’O’表示 OPENED,在 Oracle 9i 之前的版本中如果使用了绑定变量,Oracle 将

假定表中各种值是均匀分布的,以此例来说,Oracle 会假定’C’和’O’各有 50%

的记录,基于这种假定,即使 STATUS 字段上有索引,优化器在查询 STATUS=’C’

和 STATUS=’O’时也会倾向于使用全表扫描,对于 STATUS=’O’的查询来说,这实

在不是明智之举。而在 Oracle 9i 中,如果已经在表上做了统计,优化器会在决定

执行计划之前探测绑定变量的值,来决定是采用全表扫描还是使用索引,以取得

好的执行性能,针对此例,优化器会在查询 STATUS=’C’时使用全表扫描,而在查

询 STATUS=’O’时使用索引。

在 9i 中可以通过执行 ALTER INDEX MONITOR USAGE 命令来标识出未被使用的

索引。

可以使用 DBMS_SYSTEM 程序包来收集 SYSTEM 的统计信息,包括系统的 CPU 和

I/O 的占用情况,如果发现磁盘 I/O 是性能瓶颈,你可以做出相应的调整,来调整

Oracle 的执行计划。

9i 中加入了一些新的优化提示,如:NL_AJ, NL_SJ, FACT, NO_FACT, and

FIRST_ROWS(n),我们将在后面的章节中详细介绍这些优化提示。

Oracle 自 8i 版本 中引入了执行大纲(outlines)的概念,使用执行大纲,可以为

指定的 SQL 语句固化执行计划,但在有的时候需要对这个固化的执行计划进行一点

调整,8i 里没有提供相应的调整手段,Oracle 9i 里提供了解决方案,我们可以通

过 DBMS_OUTLN_EDIT 程序包来修改已经存储的执行大纲。

第 77 页 共 131 页

Page 78: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

二.SQL 优化器

优化器,作为数据库里的一个组件,在你每次执行 SQL 语句的时候,都要决定如何才能

以 好的方式访问这个 SQL 语句所操作的数据。Oracle 提供了两种优化器:基于规则的优

化器(Rule-based Optimizer,我们将简写为 RBO)和基于代价的优化器(Cost-based

Optimizer,我们将简写为 CBO)。

优化器依据以下信息来决定 佳的执行计划:

为 SQL 语句指定的语法

数据必须满足的条件(WHERE 从句)

SQL 语句需要访问的数据库表

从表中读取数据可能用到的所有的索引

Oracle RDBMS 的版本

当前的优化模式

SQL 语句中用到的优化提示

所有有效的对象统计结果(通过 ANALYZE 命令所收集到的)

表的物理存储位置(分布式 SQL)

INIT.ORA 中的参数设置(并行查询、异步 I/O 等等)

Oracle 提供了两种可选的优化器模式:基于规则的优化器(RBO)和更加智能的基于代价

的优化器(CBO)。

2.1 理解 RBO

基于规则的优化器(RBO)使用一系列预先定义的规则来决定采用什么样的执行路径访问

数据,在如下的情况下,RDBMS 将使用 RBO 优化器:

在 INIT.ORA 文件中设置了 OPTIMIZER_MODE=RULE

在 INIT.ORA 文件中设置了 OPTIMIZER_MODE=CHOOSE,并且语句中访问的所

有的表都没有统计信息。

在执行语句之前调用过 ALTER SESSION SET OPTIMIZER_MODE=RULE 命

令语句。

在执行语句之前调用过 ALTER SESSION SET OPTIMIZER_MODE=CHOOSE

命令语句,并且语句中访问的所有的表都没有统计信息。

在语句中使用了 rule 优化提示(例如: SELECT /*+RULE*/ …)

第 78 页 共 131 页

Page 79: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

RBO 中主要起作用的是 20 个分级规则,这些规则也经常被称为“黄金规则”。这些规则

告诉优化器如何决定一个 SQL 语句的 优执行路径,什么时候该使用索引,什么时候该执行

全表扫描。这些规则(如下表所示),是固定的,预先定义好的。与 CBO 不同,它们向来我

行我素,不受外界环境影响,不为外界资源(如表列、索引分布等)左右。

表 1-1. RBO 分组规则

顺序 规则

1 ROWID=constant

2 Cluster join with unique or primary key = constant

3 Hash cluster key with unique or primary key = constant

4 Entire Unique concatenated index = constant

5 Unique indexed column = constant

6 Entire cluster key = corresponding cluster key of another table in the same

cluster

7 Hash cluster key = constant

8 Entire cluster key = constant

9 Entire non-UNIQUE CONCATENATED index = constant

10 Non-UNIQUE index merge

11 Entire concatenated index = lower bound

12 Most leading column(s) of concatenated index = constant

13 Indexed column between low value and high value or indexed column LIKE

"ABC%" (bounded range)

14 Non-UNIQUE indexed column between low value and high value or indexed

column like `ABC%' (bounded range)

15 UNIQUE indexed column or constant (unbounded range)

16 Non-UNIQUE indexed column or constant (unbounded range)

17 Equality on non-indexed = column or constant (sort/merge join)

18 MAX or MIN of single indexed columns

19 ORDER BY entire index

20 全表扫描

尽管了解这些规则是非常有用的,但只了解它们并不足以告诉你如何优化基于 RBO 的查

询,为了弥补这些不足,下面的章节将提供一些上面的规则所不能告诉你的信息。

第 79 页 共 131 页

Page 80: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

2.1.1 RBO 规则之外的规则 #1

只有单列的索引能够被合并。

参见下面的 SQL 语句和索引:

SELECT col1, …

FROM emp

WHERE emp_name=’GURRY’

AND emp_no=127

AND dept_no=12;

Index1 (dept_no)

Index2 (emp_no, emp_name)

SELECT 语句将查看所有的被索引的列(此处是三个列:emp_no, emp_name 和 dept_no),

许多人认为 Oracle 将合并这两个索引,从而包含这三个数据列,来返回需要的数据。但实

际上,只有那个两列的索引(Index2)被使用,那个单列的索引(Index1)并没有被使用。

只有两个索引或多个索引都是单列的,Oracle 才能合并它们并在查询中使用它们。

Oracle 不能将一个多列的索引与其他索引进行合并。

在上面的情境中需要注意的是,如果那个单列的索引是一个唯一索引或是主关键字索

引,Oracle 将优先使用这个单列的索引而不是使用多列索引来优化查询。

比较上表中的规则 4 和规则 9 可以理解两种情况的差别。

Oracle 自 8i 版本引入了一个新的优化提示:INDEX_JOIN ,使用这个优化提示可以对

多列的索引进行合并使用。

2.1.2 RBO 规则之外的规则 #2

如果一个索引的所有列在 WHERE 子句中都被用到,那么在同等情况下,这个索引将比那

些只有部分字段在 WHERE 子句中用到的索引具有更高的优先级。参见下面的例子:

SELECT col1, ...

FROM emp

WHERE emp_name = 'GURRY'

AND emp_no = 127

AND dept_no = 12;

Index1 (emp_name)

Index2 (emp_no, dept_no, cost_center)

在这个例子中,只有 Index1 被用到,因为它的所有列(其实只有一个:emp_name)在 WHERE

子句中都被用到了,利用率是 100%,但 WHERE 子句并没有用到 Index2 的所有列(只用到了

第 80 页 共 131 页

Page 81: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

emp_no 和 dept_no,没有用到 cost_center),利用率是 66%,所以 Index1 有比 Index2

更高的优先级。

2.1.3 RBO 规则之外的规则 #3

如果有多个索引可以被 WHERE 子句利用,而且它们被用到了相同多数目的列,那么只有

后创建的索引会被用到。举例来看:

SELECT col1, ...

FROM emp

WHERE emp_name = 'GURRY'

AND emp_no = 127

AND dept_no = 12

AND emp_category = 'CLERK';

Index1 (emp_name, emp_category) (创建于 2002 年 2 月 11 日下午 4 点)

Index2 (emp_no, dept_no) (创建于 2002 年 2 月 11 日下午 5 点)

在这个例子里,只有 Index2 被用到,只因为它是在下午 5 点创建,而另一个索引是在

下午 4 点创建。

优化器的这种行为将产生一个问题:如果你在为表重建索引时是按与原先不同的顺序创

建,查询语句将会突然改用不同的索引,这有可能会导致令人难以理解的性能问题。

为了解决这一问题,许多站点在为索引命名时按创建的先后顺序为索引指定按字母排序

的命名,这样,当重建索引时,索引可以按字母顺序来重建,保持了原来的先后顺序。比如,

你可以创建一个序列,每向表中添加一个新的索引时给它的名称指定此序列的下一个值。

2.1.4 RBO 规则之外的规则 #4

如果一个索引的多个列是使用“=”操作作符访问,它将优于使用 LIKE 或 BETWEEN 操作

符访问的索引被使用。如下例所示:两个“=”操作符优于两个“=”操作符加一个 LIKE:

SELECT col1, ...

FROM emp

WHERE emp_name LIKE 'GUR%'

AND emp_no = 127

AND dept_no = 12

AND emp_category = 'CLERK'

AND emp_class = 'C1';

Index1 (emp_category, emp_class, emp_name)

Index2 (emp_no, dept_no)

在上面的例子里,尽管 Index1 有三个列被访问,而 Index2 只有两个列被访问,但结果

第 81 页 共 131 页

Page 82: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

是只有Index2被使用,Index1在查询中没有被用到,因为Index1的 emp_name列是使用LIKE

操作符来访问的。

2.1.5 RBO 规则之外的规则 #5

对于多列的索引,在 WHERE 子句中访问的列占总列数的比例对索引的优先级也有影响,

比例高的索引将优于比例低的索引被使用。

如下例所示:

SELECT col1, ...

FROM emp

WHERE emp_name = 'GURRY'

AND emp_no = 127

AND emp_class = 'C1';

Index1 (emp_name, emp_class, emp_category)

Index2 (emp_no, dept_no)

此例中,Index1 共有三个列,其中中的两个列在 WHERE 子句中被用到,所以 Index1 的

列的使用比例为 66%;Index2 的两个列中有一个列被用到,所以其占用比例为 50%,所以此

查询中 Index1 的优先级优于 Index2,在两个索引不能合并的情况下,只有 Index1 被使用。

在此处需要注明的是,如果一个索引是唯一索引或主键索引,那么不管它的列的使用比

例是多少,它的优先级都要比其他类型的索引高。

2.1.6 RBO 规则之外的规则 #6

如果将两个表关联查询,RBO 需要选择一个驱动表(driving table),驱动表选择得合适

与否对性能会有很大的影响,尤其是当优化器决定使用嵌套循环的时候(nested loops)。这

种情况下查询将先从驱动表中取出一条记录,然后在其他表中查取相关的记录,所以在这种

情况下保证从驱动表中选取的记录尽可能地少是非常重要的。

RBO 优化器环境下,满足下列条件的表将优先被设为驱动表:

有唯一或主关键字索引被使用的表

使用“=”操作符引用索引所有列的表

引用索引的列数占索引总列数比例 高的表

拥有多列组合索引的表

在 FROM 列表中位置靠后的表,如在下面的 SQL 语句中,表 EMP 将被选择为驱动表,因

为它处于 From 列表的 后的位置:

SELECT ....

第 82 页 共 131 页

Page 83: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

FROM DEPT d, EMP e

WHERE e.emp_name = 'GURRY'

AND d.dept_name = 'FINANCE'

AND d.dept_no = e.dept_no;

2.1.7 RBO 规则之外的规则 #7

如果 WHERE 子句中使用的列名是索引的第一个列时,RBO 将使用该索引,WHERE 子句中

是以函数的形式用到这个列。举例如下:

SELECT col1, ...

FROM emp

WHERE emp_name = 'GURRY';

Index1 (emp_name, emp_class, emp_category)

Index2 (emp_class, emp_name, emp_category)

Index1 会被使用,因为在 WHERE 子句中使用到的 emp_name 列是索引 Index1 的第一个

列,而相样拥有 emp_name 列的索引 Index2 不会被使用,因为 emp_name 不是它的第一个

列。

下面的例子演示了如果在子句中索引列上应用了函数的情况:

SELECT col1, ...

FROM emp

WHERE LTRIM(emp_name) = 'GURRY'

在这种情况下,因为在索引列上使用了函数,所以任何索引都将失效,查询中将不使用

任何索引。

2.2 理解 CBO

基于代价的优化器(The cost-based optimizer – CBO)相对于 RBO 更加地灵活并能更

好地适应数据的变化。为了得到一条 SQL 语句的 佳执行路径,CBO 不是单单使用固化的教

条式的规则,而是会利用数据库的很多资源信息,如表的大小,表中的行数,键值的分布情

况等等。

一旦一个表通过 ANALYZE 命令或是使用 DBMS_STATS 工具收集了统计信息,这些统

计信息就可以用在 CBO 对 优执行路径的判断中。如果没有对表收集统计信息,CBO 将只能

使用 RBO 的逻辑规则。所以在一个 Schema 里可以只对部分表收集统计信息,从而实现对某

些表使用 CBO 而对其他表使用 RBO 的效果。

提示:

ANALYZE 命令和 DBMS_STATS 收集有关表、簇和索引的统计信息,并将这些统计信息

第 83 页 共 131 页

Page 84: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

存储在数据字典中。

如果一个 SQL 语句中访问的任何一个表已经进行过 Analyze,拥有统计信息,SQL 语句

将默认使用 CBO 优化器,CBO 将对没有收集统计信息的表根据数据字典中的数据推测其统计

信息。

Oracle 在如下情况下将默认使用 CBO:

在 INIT.ORA 参数文件中设置了:OPTIMIZER_MODE = CHOOSE,而且语句中

访问到的表中至少有一个已收集了统计信息。

在连接会话中调用了:ALTER SESSION SET OPTIMIZER_MODE = CHOOSE 命

令,而且语句中访问到的表中至少有一个已收集了统计信息。

在 连 接 会 话 中 调 用 了 : ALTER SESSION SET OPTIMIZER_MODE =

FIRST_ROWS (或是 ALL_ROWS) 命令,而且语句中访问到的表中至少有一个已

收集了统计信息。

SQL 语句中使用了 FIRST_ROWS 或是 ALL_ROWS 优化提示 (例如:SELECT /*+

FIRST_ROWS */. . .)

2.2.1 ANALYZE 命令

对表或索引进行分析(ANALYZE)的方式或方法对 SQL 语句的性能会有令人意想不到的影

响。如果你的 DBA 在重建一个表或索引时忘记了分析表或索引,这一忽略对性能的影响可能

会是灾难性的;与些相反,如果你的 DBA 在每个周末都对数据进行分析(Analyze),那么在

新一周的开始将有一个新的开端,这种时候Oracle有可能会对 SQL语句生成新的执行计划,

这种新的执行计划在大多数情况下效果是好的,会导致性能的提升;但也不排除在有的情况

下会产生相反的效果。

在此必须着重强调的是:如果你的 SQL 语句的运行性能都非常好,请不要只为了好奇而

对数据对象进行 Analyze 操作。我曾经优化过的一个站点,它的关键 SQL 语句的响应时间在

一秒以内,但是站点的 DBA 以为 Analyze 可以进一步改进性能,所以他在每个周末都对表进

行 Analyze 操作,结果在一个周一的上午我接到一个电话告诉我那条 SQL 语句的响应时间已

接近 310 秒。

如果你确实需要经常对数据进行 Analyze,请记得在对数据进行重新 Analyze 之前调用

DBMS_STATS.EXPORT_SCHEMA_STATS 来备份之前的统计信息,这样如果在 Analyze 之后系统

的性能变得糟糕了,你可以将统计信息恢复成之前的样子。

在执行 Analyze 操作时你可以让 Oracle 遍历你表中的所有记录(ANALYZE COMPUTE)

或者是只对表中的数据进行取样以估计统计信息 (ANALYZE ESTIMATE)。通常我的做法

是:对非常大的表(有超过 1,000,000 行记录)使用 ANALYZE ESTIMATE 来取样估算,对

于中型或小表则采用 ANALYZE COMPUTE 进行全部扫描。

第 84 页 共 131 页

Page 85: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

强烈建议对索引列中有明显数据偏斜(data skewness)的表进行 Analyze 时使用 FOR

ALL INDEXED COLUMNS 。举例来说,如果一个表某列的值在大多数行中是某一个同样的

值时,我们说这个表有数据偏斜现象。FOR ALL INDEXED COLUMNS 选项可以使 CBO 注

意到列中数据的偏斜现象以针对不同的条件选择合适的执行路径。

当对一个表执行分析(通过 Analyze 命令)时,所有相关的索引将同时被分析。如果表上

的一个索引在后面被删除并重建,则需要重新进行分析。

在此需要注意的是,默认情况下存储过程 DBMS_STATS.GATHER_SCHEMA_STATS

和 GATHER_TABLE_STATS 只对表进行分析,而不对其索引进行分析,如果要同时对索引

进行分析,必须设置其参数 CASCADE=>TRUE。

下面是几个使用 ANALYZE 命令进行分析的范例:

ANALYZE TABLE EMP ESTIMATE STATISTICS SAMPLE 5 PERCENT FOR ALL

INDEXED COLUMNS;

ANALYZE INDEX EMP_NDX1 ESTIMATE STATISTICS SAMPLE 5 PERCENT FOR

ALL INDEXED COLUMNS;

ANALYZE TABLE EMP COMPUTE STATISTICS FOR ALL INDEXED COLUMNS;

如果对一个表进行了错误的分析,可以通过如下语句删除统计信息:

ANALYZE TABLE EMP DELETE STATISTICS;

如果在对大的数据表或索引进行分析时指定了 COMPUTE 选项,分析操作可能会花很长的

时间。经过实践我们发现在大多数情况下,在一个大表上进行 5%的取样估算分析:

ANALYZE ESTIMATE 5 PERCENT

可以收到和 ANALYZE COMPUTE 同样好的效果。

2.2.2 在上前线之前优化

对于 CBO 来说必须要面对的一个难题是如何在投入生产运行之前对数据库进行优化。绝

大多数的开发数据库和测试数据库中的数据量都比实际生产运行数据库的数据量小的多,所

以很多情况下,CBO 在生产数据库中将产生完全不同的执行计划。大多数站点难以或不允许

在将生产运行库拷贝为开发数据库或测试数据库,所以这对在开发阶段或测试阶段对数据库

的优化是一个严峻的考验。

Oracle8i 及后续版本提供了一些特性来解决这个问题,比如 DBMS_STATS 和执行大

纲(outline)。这些特性将在本文的后续章节中详细介绍。

2.2.3 CBO 的内部机理

与 RBO 不同,CBO 没有固定的性能估计规则,我们说 CBO 是灵活的,它可以适应不同的

环境,而这种适应性只有在在在必需的底层数据对象的统计信息时才能生效。对于 CBO 来说

第 85 页 共 131 页

Page 86: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

也有一点是固定不变的,那就是它总是计算各种不同执行计划的执行代价并进行比较,从中

选择代价 低的执行计划。

CBO 的优化过程大致可以分为以下几个步骤:

解析 SQL 语句 (检查语法、对象的访问权限等等)。

生成所有可能的执行计划的列表。

使用所有有效的对象统计信息来计算或估算每一种执行计划的代价(Cost)。

选择代价 低的执行计划

只有当SQL语句中至少有一个表拥有统计信息时CBO才发挥作用(CBO将估计语句中没有

统计信息的表的统计信息),否则 Oracle 将启用 RBO。但也有例外,如果使用 SQL 语句一级

的优化提示(statement-level HINTS)或设定优化目标为 ALL_ROWS 或 FIRST_ROWS,

则 Oracle 会在没有任何统计信息的情况下也强制使用 CBO。

为了 终能更好地使用 CBO,我们需要对它的工作机理有一些了解:

Primary key and/or UNIQUE index equality

CBO 认为唯一索引和主关键字索引的选择性是 100%,任何其他索引都没有这两种索引精

确,所以只要可能 CBO 都将使用 Unique Index 和 Primary Key。

Non-UNIQUE index equality

对于非唯一的索引来说,索引的选择性是计算出的,CBO 将假定表(索引)中数据是均匀

分布,并按此假设来计算索引的选择性(除非在进行 ANALYZE 操作时设置了 FOR ALL INDEXED

COLUMNS 选项)。

举例来看:

SELECT col1, ...

FROM emp

WHERE emp_category = 5;

Index1(emp_category)

假定统计信息中,emp_category 有 10 种不同的值:1,2,3…10,CBO 会假设表中这 10

种 category 的数据是均匀分布的,各占 10%的行数,所以 CBO 会计算出 emp_category=5 的

选择性(selectivity)是 90%。

如果有明显的数据偏斜,比如在表中 category=5 的行数超过 90%,而其他 category 的

总行数也不到 10%,这种情况下如果 CBO 按 90%的选择性计算出来的执行代价就很可能是错

误的。

所以在对有明显的数据偏斜的表进行 ANALYZE 操作时设置 FOR ALL INDEXED COLUMNS 选

项是非常有效的,它可以使 CBO 意识到数据偏斜的存在并在计算 Cost 时考虑数据偏斜的影

第 86 页 共 131 页

Page 87: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

响。

Range evaluation

对于在索引列上的范围查询,其选择性也是计算出来的,计算过程基于 近的在此列上

收集到的 大值和 小值的统计信息。

举例来看:

SELECT col1, ...

FROM emp

WHERE emp_category >2

and emp_category<5;

Index1(emp_category)

在 近的统计信息中,emp_category 列的 小值是 1, 大值是 10,CBO 会假设表中这

10 种 category 的数据是均匀分布的,各占 10%的行数,所以 CBO 会计算出 emp_category >2

and emp_category<5 的选择性(selectivity)是 80%(emp_category 的可能取值是 3 和 4)。

与上面类似,CBO CBO 将假定表(索引)中数据是均匀分布,并按此假设来计算索引的选

择性(除非在进行 ANALYZE 操作时设置了 FOR ALL INDEXED COLUMNS 选项)。

Range evaluation over bind variables

如前面所提到的,对于在索引列上的范围查询(Index Range)其选择性是计算出来的,

在 Oracle 9i 之前的版本中,因为绑定变量的值是在语句解析(parse)之后才传给优化器(值

是在执行计划已经生成后才传给游标--Cursor),所以优化器无法根据绑定的值来计算选择

性,为此,Oracle针对这种情况为优化器指定了规则,将无界的范围查询(例如WHERE dept_no

= :b1)的选择性硬性规定为 25%,而将有界的范围查询(例如 WHERE dept_no > :b1 AND

dept_no < :b2)的选择性定为 50%。显而易见,这种硬性的规定是无奈之举,而且在很多情

况下是很不合适的。

自 Oracle9i 开始,CBO 在决定执行计划之前可以得到绑定变量的值,这一问题 终得到

了解决。

Histograms

直方图(Histograms)在 Oracle 7.3 版本中引入,在这之前,CBO 无法辨别数据的分布是

否均衡,所以无法解决数据偏斜的现象;而现在,这一问题可以很好地解决了。

System resource usage

默认情况下,CBO 假定您是访问数据库的唯一用户,没有考虑到工作负载对于执行计划

的影响。

Oracle9i 提供了存储系统资源利用相关信息的能力,CBO 也就可以在决定执行计划时针

第 87 页 共 131 页

Page 88: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

对这些信息来做出相应的调整 (请参阅 DBMS_STATS.GATHER_SYSTEM_STATS 程序包的文档以

得到更多的信息).

Current statistics are important

如果表已经被 Analyzed 但是索引没有被 Analyzed ,或者是索引被 Analyzed 而表没有

被 Analyzed,CBO 常常会选择出完全错误的执行计划。

如果语句中的所有表没有任何统计信息,那么不应该使用语句一级的优化提示(inline

hints)来强制数据库使用 CBO 模式。

使用过时的统计信息会比在运行时估计统计信息更危险,但也需要认识到过于频繁地更

新统计信息也会产生你不想要的结果,尤其是在一个很多用户同时在线的繁忙的生产系统

上。

重新收集统计信息时一定要记得使用 DBMS_STATS.EXPORT_SCHEMA_STATS 来备

份原来的统计信息。

使用 COMPUTE 选项来对巨大的表和它的相关索引进行 Analyze 会花费非常非常长的时

间,占用非常多的 CPU 资源、磁盘 I/O 和临时表空间,这种操作在有的时候甚至是一种破坏

性的操作。对于这种情况,采用一个固定的值来对表进行抽样估算往往能收到非常好的效果。

结合由选择性规则(selectivity rules)计算出的信息和数据库 I/O 方面的信息,CBO 就

可以计算出每一种执行计划的代价(Cost)。

2.2.4 CBO 的执行计划

使用 EXPLAIN PLAN 工具 Oracle 提供了有关查询计划执行代价的相关信息, EXPLAIN

PLAN 可以显示计算出来的执行代价(calculated execution cost(s)),我们可以通过观察

plan 表中 COST 列的值的升高或降低来判断查询的执行代价的高低。举例如下:

EXPLAIN PLAN FOR

SELECT count(*)

FROM winners, horses

WHERE winners.owner=horses.owner

AND winners.horse_name LIKE 'Mr %';

COLUMN "SQL" FORMAT a56

SELECT lpad(' ',2*level)||operation||''||options||' '||object_name||

decode(OBJECT_TYPE, '', '', '('||object_type||')') "SQL",

cost "Cost", cardinality "Num Rows"

FROM plan_table

CONNECT BY prior id = parent_id

START WITH id = 0;

SQL Cost Num Rows ----------------------------------------------------------------------------------------------

第 88 页 共 131 页

Page 89: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

SELECT STATEMENT 44 1 SORT AGGREGATE HASH JOIN 44 100469 INDEX RANGE SCAN MG1(NON-UNIQUE) 2 1471 INDEX FAST FULL SCAN OWNER_PK(UNIQUE) 4 6830

通过启用 CBO (比如,通过使用优化提示(inline hints),通过创建或移除索引,或通

过调整表和索引的 Analyze 与否),我们可以看到优化器生成的各种不同的执行计划之间的

差别。我们可以使用 EXPLAIN PLAN 来实验各种不同的执行计划,然后选择一种代价 低的

执行计划。

为了得到 佳的执行性能,许多站点对绝大多数的表和索引进行 Analyze 以使用 CBO,

但会保留一小部分的表和索引不被 Analyze,以确保使用这一小部分表的查询使用 RBO 来优

化。这是一种聪明的方案,但一定要注意的是,不要将这一小部分没有 Analyze 的表与其

他已 Analyze 的表进行关联查询。

2.3 对优化器的一些常见的误解

让我们来消除一些对优化器的常见的误解。

Oracle8i 和 Oracle9i 不支持 RBO

这是完全错误的,曾经某些出版物提到过这个观点,但 Oracle 明确地向我们保证事情

完全不是这个样子。

RBO 中不能使用优化提示(Hints)

实际上使用 RBO 时大多数的优化提示都可用在 SQL 语句中。

RBO 中优化的 SQL 在 CBO 中也会运行得很好

如果曾经遇到这样的情况,那能说你是非常幸运的。实际上从 RBO 迁移到 CBO 时许多 SQL

语句都是需要重新优化的。

CBO 中优化的 SQL 在 RBO 中也会运行得很好

这个的可能性更小,除非 SQL 语句本身就是按照 RBO 的规则写的。

不能同时运行 RBO 和 CBO

通过将INIT.ORA 参数文件中的OPTIMIZER_MODE 设置为 CHOOSE,对部分表进行Analyze,

就可以同时运行 CBO 和 RBO,但需要注意不要将已 Analyze 过的表与未 Analyze 的表关联查

询。

第 89 页 共 131 页

Page 90: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

2.4 选择合适的优化器

如果你正在使用 RBO,那么我们强烈建议你迁移到 CBO,下面是建议这样做的理由:

可以减少编码时间

开发者不必了解优化规则(rules)

CBO 有更多的优化特性,以及更多的优化工具

第三方工具包的可移植性将得到增强。让更多第三方的工具包(third-party

packages) 除了希望在 Oracle 上运行,还希望在 DB2, Informix, and SQL*Server

上也能很好的运行。如果代码可以不必按 RBO 的规则来写,而是按照通用的 SQL 样

式来写就可以很大程度降低在不同的数据库平台上移植的难度,提供代码的可移植

性。

终端用户不必学习一大堆的优化规则即可开发出优化的代码。

Oracle 每个版本升级时 CBO 会有非常大的改进,而 oracle 已经不再改进 RBO。

CBO 降低了在表上添加新的索引的危险性。

有许多特性只能 CBO有效,这些特性包括 recognition of materialized views、star

transformation、函数索引等等。这类特性的数量是很大的,而且随着时间的推移,

RBO 与 CBO 的差距会越来越大。

Oracle 提供了诸如 DBMS_STATS 程序包和执行大纲(outlines)之类的特性来解决

CBO 在不同环境中执行计划不同的问题,如此可以在开发库或测试库里模拟生产库

的环境来对 SQL 进行优化。

(待续…)

[译者简介]

SnowyWolf:

任 itpub Oracle 电子文档版版主.

现就职于国内某大型 GIS 平台提供商,任开发经理,负责空间数据引擎开发。

对空间数据库有较深入的研究,擅长于 OCI 开发。

参加过 ITPUB 电子杂志的编辑排版,精于 chm 电子文档制作。

你可以在http://www.snowywolf.net上找到更多的信息.

End

第 90 页 共 131 页

Page 91: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

Oracle9i 数据库 Data Guard 实施及维护手册

By Kamus

一.Data Guard 介绍

备用数据库(standby database)是 ORACLE 推出的一种高可用性(HIGH AVAILABLE)数

据库方案,在主节点与备用节点间通过日志同步来保证数据的同步,备用节点作为主节

点的

备份,可以实现快速切换与灾难性恢复。

ORACLE 从 7.3 才开始支持 standby database。7.3.x-8.0.x 需要手工拷贝所有归档日

志并

手工同步,从 ORACLE815 开始,开始支持多节点复制,并实现了自动同步,但是这种同

是数据异步模式的,可能引起数据丢失。

Oracle9i 的 Data Guard 是对 Oracle8i 中 Standby Database 功能的加强,而 Standby

Database 技术出现的主要初衷就是为了容灾(Disaster Recovery),所以具有更强大功能

的 Data Guard 毫无疑问成了 Oracle 数据库高可用性解决方案中首选使用的产品。

Oracle 提供支持高可用性 (high availability) 相关产品主要有下面几种:

(1) Oracle Fail Safe on NT

(2) Oracle Real Application Cluster (RAC)

(3) Oracle Parallel Fail Safe

(4) Oracle Advanced Quening

(5) Oralce Advanced Replication

(6) Oracle Data Guard

这几种产品中, 让人困惑的是如何在 RAC,Data Guard 和 Advanced Replication 中

选择适合自己生产环境的高可用性产品。

因此我就先将这三种产品做一下比较:

RAC (Oracle Real Application Cluster)

RAC 的前身是 Oracle8i 中的 OPS(Oracle Parallel Server),RAC 是多个单 CPU 机或

第 91 页 共 131 页

Page 92: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

SMP(Symmetric Multi-Processing system) 或者 MPP(Massively Parallel Processing)的

cluster 。cluster 里面不同的服务器使用一个(一般是一个)或多个 oracle instances 与

一个 database 连接。

主要的技术特点:

(1) 数据库中所有的数据文件,控制文件和重作日志文件都是建立在裸设备(raw

devices)上的,虽然随着 OCFS 的推出,在某些平台上面已经开始支持 Cluster 文件系统,

但是总体来说 RAC 在技术方面对操作系统的设置有很高的依赖性,需要有 Cluster 软件的支

持,难度比较大。

(2)每个数据库实例都有自己单独的联机重作日志组,因此在做备份和恢复的时候,需

要特殊的处理。

(3)RAC的存储方面并没有额外的冗余,因此在介质损坏的情况下,还是需要依靠RAID 等

磁盘冗余方案来支持。

软件许可证方面,RAC 并未包括在数据库使用许可证 (license) 之内,需要额外购买;

同样,Oracle 产品的技术支持,也需在数据库支持之外另外购买 OPS/RAC 部分。

总体来说,RAC 的设置与维护还是比 Data Guard 复杂和昂贵得多。

高级复制(Advanced Replication )

主要的技术特点:

(1) Replication 使用分布式数据库技术在多个站点之间共享数据。

(2) Replicated Database 和 Distributed Database 并不一样,在分布式数据库系统

中数据在

多个站点同时有效,但是一个表只会存在于一个站点中,而对于 Replication 来说相同

的数据将同时存在于多个站点中。

(3) 使用 replication 的原因:

1) Availability:也就是提供了优秀的 failover 保护

2) Performance:由于有多个 server,所以可以将用户业务分布在不同的 server 上

3) Disconnected computing:实体化视图允许用户在和 master 断开后使用数据库

的子集,在重新连接上 master 之后再进行两者的同步。

4) Network load reduction:由于有多个 server,所以可以减少 master 的网络请

5) Mass deployment:通过变量产生自定义的实体化视图以满足多种需求

第 92 页 共 131 页

Page 93: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

(4) 在不同的 Oracle 发行版本之间以及不同操作系统的 Oracle 之间都可以使用

Advanced Replication。这是高级复制的 大优势所在。而 RAC 和 Data Guard 都需要操作

系统和数据库版本相同。

高级复制不需要除数据库之外额外的使用许可 (license) 。

高级复制要对需要同步的每个数据库对象都进行单独的复制生成准备工作,所以当数据

库中存在大量对象需要同步的话,高级复制的初期准备工作非常耗时。而且高级复制对于

DDL 操作不能很好支持,必须要使用特殊的包来执行 DDL 操作,才能将操作复制到远方数据

库。所以高级复制作为一个整体数据库的容灾方案并不十分理想,只有在由于费用问题,要

求灾备数据库和主数据库的硬件架构不同的情况下,才应该选择这种方案。

Data Guard

与 RAC 或者 OPS 比较 Data Guard 在高可用性方面的使用性,可以从几个方面来探讨:

(1) 数据库备份:Data Guard 克隆了原始数据库,因此原始数据库有备份,具有灾备

要求的冗余量;而 RAC/OPS 只有一份数据库,如果数据所在的硬盘发生了问题,需要另外

的方法(比如 RAID)解决。

(2) 服务器的数量及利用率:RAC/OPS 至少需要双机支持,支持动态负载平衡,对於

大量用户访问的环境,可以在多个服务器同时处理用户的请求。在多机系统环境,如果尚有

一台服务器运行正常,不会造成整个数据库系统由于故障彻底停机。Data Guard 可以设置

在同一个服务器上面,理论上支持单机环境。

(3) 故障停机时间:如上面所说,OPS/RAC 环境只要还有一台服务器正常运行,就不

会造成停机;Data Guard 环境中,primary 数据库到 Standby 数据库的切换,至少需要几

分钟的停机时间。

(4) 费用:使用许可证方面,Data Guard 不需要购买数据库之外的使用许可。同时在

维护费用方面,OPS/RAC 的实施也相对复杂,人力、物力相对昂贵。

通过上面几种产品的比较,再分析此次客户对于灾备的硬件投入和功能要求,我们认为

Data Guard 是比较合适的方案。

首先此次灾备环境中使用的都是 SUN 的小型机,符合 Data Guard 对于服务器同构的要

求,其次由于灾备库在上海,而主库在北京,也同样满足 Data Guard 对于 HA 的要求。

而 Data Guard 在也同样能够满足 多丢失一分钟的数据,并且使用灾备库作为历史查

询服务器这样的功能需求。

二.Data Guard 类型的比较

Oracle9i 在 Data Guard 的配置方面提供了几种不同的类型,根据客户对于高可用性的

不同要求,可以选择不同的 Data Guard 类型。

第 93 页 共 131 页

Page 94: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

下面对于 Data Guard 的几种类型作一个列举和比较。

Data Guard 环境中包含一个产品数据库,这是正常运行用以支撑日常业务的主数据库,

称为 Primary Database。另外包含一个或者多个灾备数据库,称为 Standby Database。

按照备用库(Standby Database)应用归档日志的不同方式,Standby Database 可以分

为物理备用库(Physical Standby)和逻辑备用库(Logical Standby)。

按照主数据库(Primary Database)的保护模式,整个 Data Guard 环境分为 大数据

保护模式(MAXIMIZE PROTECTION), 大可用性模式(MAXIMIZE AVAILABILITY), 大性能

模式(MAXIMIZE PERFORMANCE)。

按照主库向备用库传递重作信息的方式,可以分为 ARCH 方式和 LGWR 方式。

物理备用库可以运行在数据库三种保护模式中的任何一种模式下,逻辑备用库只可以运

行在 大可用性模式或者 大性能模式下。无论物理备用库还是逻辑备用库都可以在传输日

志上采用 ARCH 方式或者 LGWR 方式。

物理备用库(Physical Standby):

提供了一份跟主数据库在物理级别上完全相同的 copy,指在数据库的 block 级别都是完

全相同的,比如数据库表中记录的 rowid。物理备用库是通过不断地恢复 Primary Database

传入的重作日志数据信息来达到跟主数据库保持同步。

物理备用库在处于自动恢复重作日志信息的状态下,无法提供查询服务。因为此时的备

用数据库并不是处于正常打开的状态,数据库的非 sysdba 用户无法登录备用库,自然也就

无法进行普通的查询业务。

逻辑备用库(Logical Standby):

指在逻辑上跟主数据库保持一致,但是在物理层面上跟主数据库并不相同。逻辑备用库

是通过将 Primary Database 传入的重作日志数据信息转化为 SQL 语句,然后在备用库上重

新执行来达到跟主数据库保持同步。

逻辑备用库在应用重作信息的同时也可以提供查询功能。但是由于逻辑备用库应用重作

日志的方式限制,所以逻辑备用库在功能和性能上面都有所限制。以下是逻辑备用库的一些

限制条件。

1. 以下数据类型不被支持:

NCLOB ,LONG ,LONG RAW ,BFILE ,ROWID ,UROWID

2. 以下操作不被支持:

ALTER DATABASE ,ALTER SESSION ,ALTER SNAPSHOT

ALTER SNAPSHOT LOG ,ALTER SYSTEM SWITCH LOG

CREATE CONTROL FILE ,CREATE DATABASE ,

第 94 页 共 131 页

Page 95: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

CREATE DATABASE LINK ,CREATE PFILE FROM SPFILE ,

CREATE SCHEMA AUTHORIZATION

CREATE SNAPSHOT ,CREATE SNAPSHOT LOG ,CREATE SPFILE FROM PFILE

CREATE TABLE AS SELECT FROM A CLUSTER TABLE

DROP DATABASE LINK ,DROP SNAPSHOT ,DROP SNAPSHOT LOG

EXPLAIN ,LOCK TABLE ,RENAME ,SET CONSTRAINTS ,

SET ROLE ,SET TRANSACTION

3. 高级队列的管理和物化视图的刷新不被支持

4. 要求每张表应该有主键或者唯一性索引 ,如果必须有没有唯一性标识的表,那么可以

激活 Primary 库的 supplemental logging 属性,但是这样将会在重作日志中记录该表

中每一条记录的所有字段信息,会大大增加重作日志的记录量。

以下是 Data Guard 环境中物理备用库和逻辑备用库的配置图。

最大数据保护模式(MAXIMIZE PROTECTION)

提供 高等级的数据保护,重作信息从主库同步送到备用库。直到备用库成功接收重作

信息,主库上的事务才会提交。如果由于网络等问题,导致备用库不可用,那么主库也同时

会被关闭。这种模式保证了完全没有数据丢失。

最大可用性模式(MAXIMIZE AVAILABILITY)

在备用库正常的情况下,该模式提供了跟“ 大数据保护模式”一样的机制,保证没有

任何数据丢失。如果备用库不可用,那么将转换到“ 大性能模式”,操作可以在主库上继

续执行。当备用库重新可用之后,将会继续同步。但是如果在同步完成之前,主库由于故障

损坏,将会丢失数据(当然,可以通过 RAID,RMAN 等方式尽量保护主库即使出现故障也不

第 95 页 共 131 页

Page 96: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

丢失数据)。

最大性能模式(MAXIMIZE PERFORMANCE)

这种模式下,主库上的重作信息是异步传递到备用库上,不论备用库上是否已经成功接

收了重作信息,主库上的操作都会成功执行。所以这种模式提供了 好的性能,但是 低的

数据保护。这是 Oracle9i 配置 Data Guard 的默认模式。

ARCH 方式

当主库归档联机重作日志文件时,ARCH 归档进程在归档到本机的同时,将重作数据传递

到备用库,由备用库端的 RFS 进程(Remote File Server)接收,生成备用库端的归档日志

文件,然后由备用库端的 MRP 进程(物理备用库类型)或者 LSP 进程(逻辑备用库类型)将

归档日志文件恢复到备用库中。

传递方式如图:

LGWR 方式

物理备用库类型下,主库的 LGWR 进程在将重作数据写到本地联机重作日志文件中的同

时,将重作数据传递到备用库,备用库的 RFS 进程将收到的数据写入本地的备用重作日志文

件(Standby Redo Log)中。当主库日志切换时也触发备用库的日志切换,切换发生时,备

用库的归档进程将重作日志文件归档,然后由备用库端的 MRP 进程将归档日志文件恢复到备

用库中。

第 96 页 共 131 页

Page 97: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

传递方式如图:

逻辑备用库类型下,不可以创建备用重作日志文件(Standby Redo Log),所以处理流

程跟物理备用库稍有不同。

主库的 LGWR 进程在将重作数据写到本地联机重作日志文件中的同时,将重作数据传递

到备用库,备用库的 RFS 进程将收到的数据写入本地的归档日志文件中。当主库日志切换时

也触发备用库的日志切换,切换发生时,备用库的归档进程完成归档日志文件的 后生成,

然后由备用库端的 LSP 进程提取归档日志文件中的 SQL 语句,重新在备用库上运行一遍。

传递方式如图:

第 97 页 共 131 页

Page 98: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

后上述所有类型或者方式互相搭配进行一个比较。

Maximum Protection

Maximum Availability Maximum Performance

重 作 传 递

方式 LGWR LGWR LGWR 或者 ARCH

网 络 传 递

模式 同步 同步 当使用 LGWR 传递方式时为异步方式,如果

使用 ARCH 传递方式,那么不牵涉联机重作

数据的网络传输

磁 盘 写 入

选项 AFFIRM AFFIRM NOAFFIRM

是 否 需 要

备 用 重 作

日志文件

需要 只在物理备用库

类型中需要 如果物理备用库使用 LGWR 传递方式,那么

需要

备 份 库 类

型 物理 物理或逻辑 物理或逻辑

三.硬件配置

四.软件配置

五.实施 Data Guard 前提条件和注意事项

灾备环境中的所有节点必须安装相同的操作系统,但是操作系统的版本可以不

相同。

灾备环境中的所有节点必须安装完全相同版本的 Oracle 数据库软件,包括版

本号和发布号,比如必须都是 Oracle9.2.0.4。

主库必须处于归档(ARCHIVELOG)模式。

灾备环境中所有节点的硬件和操作系统架构必须相同,比如主节点是 Sparc

64-bit SunOS,那么备用节点也必须是 Sparc 64-bit SunOS。

主库可以是单实例,也可以是 RAC。

主节点和备用节点之间的硬件配置可以不同,比如 CPU 数量,内存数量,存储

的配置等等。

配置灾备环境的数据库用户必须具有 SYSDBA 权限。

第 98 页 共 131 页

Page 99: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

cluster 环境中两个节点的 tnsnames.ora, listener.ora, sqlnet.ora,

spfile, pfile 必须保证相同

六.实施步骤

Physical Standby 配置

修改控制文件,修改 大日志组为 10

alter database backup controlfile to trace;

ORACLE_HOME 为/export/home/oracle/app/oracle/product/9.2.0

190 作为 primary,185 作为 Standby

创建 Standby 的 Oracle 软件

打包 Primary 上的 oracle 软件

cd /export/home/oracle/app/oracle/product

tar cvf db.tar 9.2.0

ftp 到 Standby 服务器相应目录

创建 Standby 上的 Oracle 软件目录结构

mkdir -p /export/home/oracle/app/oracle/product

cd /export/home/oracle/app/oracle/product

tar xvf db.tar

cd /export/home/oracle/app/oracle

mkdir -p admin/ctsdb/bdump

mkdir -p admin/ctsdb/cdump

mkdir -p admin/ctsdb/udump

创建 Standby 上的 dba 组,oracle 用户,修改 oracle 用户的环境变量,修改/etc/system

文件

1。设置 Primary 强制 Logging

ALTER DATABASE FORCE LOGGING;

2。设置 Primary 为归档模式,启动自动归档

3。检查 Primary 中所有数据文件

4。关闭 Primary,关闭应用服务器,停止监听

5。cp 所有数据文件到本地备份路径

6。启动 Primary,保持监听和应用服务器处于停止状态

第 99 页 共 131 页

Page 100: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

7。生成 Standby 控制文件

ALTER DATABASE CREATE STANDBY CONTROLFILE AS '/tmp/control01.ctl';

8。生成初始化参数文件

CREATE PFILE='/tmp/initctsdb.ora' FROM SPFILE;

9。将 5,7,8 中生成的所有文件以及密码文件 cp 到 Standby 服务器

10。修改 Standby 的初始化参数文件

添加下面行:

*.standby_archive_dest='/export/spare/oradata/ctsdb/archive'

*.fal_server='ctsdb.primary'

*.fal_client='ctsdb.standby'

*.standby_file_management=auto

*.remote_archive_enable=TRUE

11。修改 Primary 和 Standby 的 lisener.ora 和 tnsnames.ora 文件

# LISTENER.ORA Network Configuration File:

/export/home/oracle/app/oracle/product/9.2.0/

network/admin/listener.ora

# Generated by Oracle configuration tools.

SID_LIST_LISTENER_DG =

(SID_LIST =

(SID_DESC =

(GLOBAL_DBNAME = ctsdb)

(ORACLE_HOME = /export/home/oracle/app/oracle/product/9.2.0)

(SID_NAME = ctsdb)

)

)

LISTENER_DG =

(DESCRIPTION =

(ADDRESS = (PROTOCOL = TCP)(HOST = 10.1.5.210)(PORT = 1522))

)

# TNSNAMES.ORA Network Configuration File:

/export/home/oracle/app/oracle/product/9.2.0/

network/admin/tnsnames.ora

# Generated by Oracle configuration tools.

CTSDB.STANDBY =

第 100 页 共 131 页

Page 101: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

(DESCRIPTION =

(ADDRESS_LIST =

(ADDRESS = (PROTOCOL = TCP)(HOST = 10.1.5.211)(PORT = 1522))

)

(CONNECT_DATA =

(SERVER = DEDICATED)

(SID = ctsdb)

)

)

CTSDB.PRIMARY =

(DESCRIPTION =

(ADDRESS_LIST =

(ADDRESS = (PROTOCOL = TCP)(HOST = 10.1.5.210)(PORT = 1522))

)

(CONNECT_DATA =

(SERVER = DEDICATED)

(SID = ctsdb)

)

)

12。设置 Standby 的 SQLNET.ORA 文件

添加 SQLNET.EXPIRE_TIME=2,该配置表示在 Standby 由于故障不可用时,Primary 将持

续检测 2 分钟,如果仍然不可用,则返回网络连接错误。

13。创建 Standby 的 spfile

CREATE SPFILE FROM PFILE='/tmp/initctsdb.ora';

14。启动 Standby

STARTUP NOMOUNT;

ALTER DATABASE MOUNT STANDBY DATABASE;

如果要使用 LGWR 进程传递 redo 数据,那么需要添加 standby redolog,如果使用 ARCH

进程传递 redo 数据,那么这步可以省略

alter database add standby logfile group 4

('/global/oradata/ctsdb/stdby_redo04.log') size 1024K;

alter database add standby logfile group 5

('/global/oradata/ctsdb/stdby_redo05.log') size 1024K;

alter database add standby logfile group 6

('/global/oradata/ctsdb/stdby_redo06.log') size 1024K;

alter database add standby logfile group 7

('/global/oradata/ctsdb/stdby_redo07.log') size 1024K;

ALTER DATABASE RECOVER MANAGED STANDBY DATABASE PARALLEL

第 101 页 共 131 页

Page 102: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

<CPU*2> DISCONNECT FROM SESSION;

为了防止以后 primary 和 standby 切换,可以在 primary 上也建立相应的 standby

redolog

15。设置 Primary 的归档地址

ALTER SYSTEM SET LOG_ARCHIVE_DEST_2='SERVICE=CTSDB.STANDBY

LGWR' SCOPE=BOTH;

ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_2=ENABLE SCOPE=BOTH;

16。测试 Primary 的归档能否应用到 Standby

ALTER SYSTEM ARCHIVE LOG CURRENT;

17。停止 Standby

alter database recover managed standby database cancel;

shutdown immediate;

18。切换到只读模式

ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;

ALTER DATABASE OPEN READ ONLY;

19。切换回管理恢复模式

ALTER DATABASE RECOVER MANAGED STANDBY DATABASE PARALLEL 8

DISCONNECT FROM SESSION;

以上为 MAX PERFORMANCE 模式的 DataGuard

如果要改为 MAX AVAILABILITY,进行如下操作:

检查当前 Primary 库的保护模式

select protection_mode from v$database;

转换数据库模式为 MAX AVAILABILITY:

shutdown immediate;

startup mount;

alter database set standby database to maximize availability;

alter database open;

如果要强制 Primary 一分种归档一次,那么设置 Primary 的初始化 参 数

ARCHIVE_LAG_TARGET:

alter system set ARCHIVE_LAG_TARGET=60 scope=both;

如果想要自动在 Standby 上应用 Primary 中创建数据文件等操作,需要在 Standby 上设

置:

alter system set STANDBY_FILE_MANAGEMENT=AUTO scope=both;

第 102 页 共 131 页

Page 103: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

使用 RMAN 进行 DataGuard 环境的快速配置总结:

1. 预先设置好Standby上所需的参数文件和路径, 修改 standby的 fal_server和 fal_client参数

2. 作 Primay 的联机 RMAN 备份 3. 启动 Primay,随时都可以生成 standby control file 4. 在 Standby 端,用生成的 standby control file, mount database 5. 在 Standby 端,RMAN 中作 restore databse 6. 设置 standby 到 RECOVER MANAGED 状态

Pirmay 和 Standby 之间作 switchover,此时 Primary 和 Standby 均为正常状态,并且网络

正常。

Primary:

SELECT SWITCHOVER_STATUS FROM V$DATABASE;

ALTER DATABASE COMMIT TO SWITCHOVER TO PHYSICAL STANDBY;

SHUTDOWN IMMEDIATE;

STARTUP NOMOUNT;

ALTER DATABASE MOUNT STANDBY DATABASE;

Standby:

SELECT SWITCHOVER_STATUS FROM V$DATABASE;

ALTER DATABASE COMMIT TO SWITCHOVER TO PRIMARY;

SHUTDOWN;

STARTUP;

Primay:

ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT

FROM SESSION;

Standby Failover 到 Primary,此时由于故障 Primary 宕机或者网络不通

以下命令均在 Standby 端执行

1.如果是使用 ARCH 传递 redo 数据,那么执行以下命令:

检查是否有 gap archive

SELECT THREAD#, LOW_SEQUENCE#, HIGH_SEQUENCE# FROM

V$ARCHIVE_GAP;

如果有则 register

ALTER DATABASE REGISTER PHYSICAL LOGFILE 'filespec1';

实行 Failover:

ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;

ALTER DATABASE ACTIVATE STANDBY DATABASE;

第 103 页 共 131 页

Page 104: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

ALTER DATABASE MOUNT;

ALTER DATABASE OPEN;

2.如果是使用 LGWR 传递 redo 数据,那么执行以下命令:

检查是否有 gap archive

SELECT THREAD#, LOW_SEQUENCE#, HIGH_SEQUENCE# FROM

V$ARCHIVE_GAP;

如果有则 register

ALTER DATABASE REGISTER PHYSICAL LOGFILE 'filespec1';

如果是由于网络问题而导致需要切换,那么通常 standby 端的 RFS 进程并不会意识到

primary 已经不可访问,所以 RFS 进程也不会释放当前的 standby redo log 文件。

如果是 primary 端的数据库实例由于故障中断,那么一般情况下 standby 端的 RFS 进程

会立刻意识到 primary 已经不可访问,也就会立刻释放当前的 standby redo log 文件。

只要 RFS 进程没有释放 standby redo log 文件,那么执行 ALTER DATABASE RECOVER

MANAGED STANDBY DATABASE FINISH 命令就会在 alertlog 文件中发现如下的报错信息

Warning: log 4 of thread 1 is being archived or modified

Recovery interrupted.

Media Recovery failed with error 261

如果在报上述错误的时候,执行 SWITCH,那么将会出现下面的错误:

ORA-16139: media recovery required

所以必须检查 alertlog 文件,直到发现如下信息才表示 RFS 进程已经释放了 standby

redo log 文件,这时候才可以作 FINISH:

RFS: Possible network disconnect with primary database

促使 RFS 进程释放 standby redo log 文件有两种方法:

1. 等待 RFS 进程的 network timeout,通常需要等待 8 分钟左右 2. 关闭 standby 数据库,再重新开启,这样会强制 RFS 进程释放 standby redo log

我们可以通过 v$managed_standby 视图来监控 RFS 进程何时释放

实行 Failover:

ALTER DATABASE RECOVER MANAGED STANDBY DATABASE FINISH;

alertlog 中将显示如下信息,表示 finish 成功:

Terminal Incomplete Recovery: UNTIL CHANGE 3738452

Terminal Incomplete Recovery: End-Of-Redo log allocation

Terminal Incomplete Recovery: log 4 reserved for thread 1 seq# 8772

TERMINAL RECOVERY changing datafile format version from 8.0.0.0.0 to

第 104 页 共 131 页

Page 105: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

9.0.0.0.0

Switching logfile format version from 8.0.0.0.0 to 9.0.0.0.0

Terminal Incomplete Recovery: clearing standby redo logs.

Terminal Incomplete Recovery: thread 1 seq# 8772 redo required

Terminal Incomplete Recovery: End-Of-Redo log

/global/oradata/ctsdb/stdby_redo04.log

Identified end-of-REDO for thread 1 sequence 8772

Terminal Incomplete Recovery: end checkpoint SCN 3738453

Media Recovery Complete

Switching logfile format version from 9.0.0.0.0 to 8.0.0.0.0

Terminal Incomplete Recovery: successful completion

Begin: Wait for standby logfiles to be archived

Wed Sep 1 13:42:28 2004

ARC1: Evaluating archive log 4 thread 1 sequence 8772

Wed Sep 1 13:42:28 2004

ARC0: Evaluating archive log 4 thread 1 sequence 8772

Wed Sep 1 13:42:28 2004

ARC1: Beginning to archive log 4 thread 1 sequence 8772

Wed Sep 1 13:42:28 2004

ARC0: Unable to archive log 4 thread 1 sequence 8772

Wed Sep 1 13:42:28 2004

Creating archive destination LOG_ARCHIVE_DEST_1:

'/global/oradata/ctsdb/archive/arch1_8772.log'

Wed Sep 1 13:42:28 2004

Log actively being archived by another process

Wed Sep 1 13:42:28 2004

ARC1: Completed archiving log 4 thread 1 sequence 8772

Wed Sep 1 13:42:43 2004

End: All standby logfiles have been archived

Resetting standby activation ID 4038461969 (0xf0b60a11)

Completed: ALTER DATABASE RECOVER MANAGED STANDBY DATABASE FINISH

FINSH 成功之后再执行 SWITCH:

ALTER DATABASE COMMIT TO SWITCHOVER TO PRIMARY;

SWITCH 成功之后,重新启动数据库:

SHUTDOWN IMMEDIATE;

STARTUP;

使用 Data Guard Broker

创建 Management Server repository:

emca

第 105 页 共 131 页

Page 106: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

启动 Management Server:

oemctl start oms

检查 Management Server 状态:

oemctl status oms sysman/oem_temp@bftest

启动 Intelligent Agent:

agentctl start agent

如果启动 agent 报错,则检查相应的 log 文件,如果 log 文件中有如下错误:

Failed while initializing user subsystem

Error initializing subsystems

nmiumini_initializeUM: Unable to initialize UQAgent

则进行如下操作之后,重新启动 agent:

rm $ORACLE_HOME/network/agent/*.q

alter system set resource_manager_plan='SYSTEM_PLAN' scope=both;

在所有站点上将 BROKER 启动。

SQL> ALTER SYSTEM SET DG_BROKER_START=TRUE SCOPE=BOTH;

System altered.

SQL> SHOW PARAMETER DG_BROKER_START

NAME TYPE VALUE

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

dg_broker_start boolean TRUE

连接 Data Guard Manager,必须使用具有 sysdba 权限的用户连接到 Primary 库上

>dgmgrl

DGMGRL> connect sys/dba

创建配置方案

DGMGRL> CREATE CONFIGURATION 'cts' AS

PRIMARY SITE IS 'bftest'

RESOURCE IS 'ctsdb'

HOSTNAME IS 'bftest'

INSTANCE NAME IS 'ctsdb'

SERVICE NAME IS 'ctsdb.primary'

SITE IS MAINTAINED AS PHYSICAL;

创建备用站点方案

DGMGRL> CREATE SITE 'report'

RESOURCE IS 'ctsdb'

HOSTNAME IS 'report'

第 106 页 共 131 页

Page 107: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

INSTANCE NAME IS 'ctsdb'

SERVICE NAME IS 'ctsdb.standby'

SITE IS MAINTAINED AS PHYSICAL;

激活配置方案

DGMGRL> ENABLE CONFIGURATION;

激活资源

DGMGRL> ENABLE RESOURCE 'ctsdb';

资源的日志传送模式必须和 Primary 库的数据保护模式相匹配,比如数据保护模式是

maximize availability,那么需要配置资源的 LogXptMode 属性为 SYNC 方式。

DGMGRL>ALTER RESOURCE 'ctsdb' ON SITE 'Boston' SET PROPERTY

LogXptMode=SYNC;

DGMGRL>ALTER RESOURCE 'report_db' ON SITE 'Beijing' SET PROPERTY

LogXptMode=SYNC;

DGMGRL> ALTER CONFIGURATION SET PROTECTION MODE AS

MAXAVAILABILITY;

查看资源情况

DGMGRL> show resource verbose 'ctsdb';

查看某个节点上资源中的某一属性

DGMGRL> show resource verbose 'ctsdb' 'LogXptMode' on site 'Boston';

DGMGRL> SHOW RESOURCE 'ctsdb' LogXptStatus;

查看 Broker 的日志

DGMGRL> show log latest on site 'Boston';

查看数据库告警日志

DGMGRL> show log alert latest on site 'Boston';

查看资源的各种属性

DGMGRL> SHOW RESOURCE 'ctsdb' SendQEntries;

DGMGRL> SHOW RESOURCE 'report_db' SbyLogQueue;

DGMGRL> show resource verbose 'ctsdb' InconsistentLogXptProps;

修改资源属性,将自动修改数据库的相应初始化参数

DGMGRL> ALTER RESOURCE product_db on site v280 SET PROPERTY

StandbyArchiveDest = '/global/oradata/ctsdb/archive';

Property "standbyarchivedest" updated.

第 107 页 共 131 页

Page 108: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

DGMGRL> ALTER RESOURCE product_db on site v280 SET PROPERTY

StandbyFileManagement = 'AUTO';

Property "standbyfilemanagement" updated.

DGMGRL> ALTER RESOURCE product_db on site v280 SET PROPERTY

ArchiveLagTarget = '3600';

Property "archivelagtarget" updated.

停止 Data Guard 环境中的某个节点

DGMGRL> ALTER RESOURCE 'report_db' ON SITE 'Beijing' SET STATE='offline';

启动 Data Guard 环境中的某个节点

DGMGRL> ALTER RESOURCE 'report_db' ON SITE 'Beijing' SET

STATE='LOGICAL-APPLY-ON';

修改 Data Guard 环境中的某个节点的状态

DGMGRL> ALTER RESOURCE 'report_db' ON SITE 'v480' SET

STATE='READ-ONLY';

先停止连接到备用库上的所有连接

DGMGRL> ALTER RESOURCE 'report_db' ON SITE 'v480' SET

STATE='PHYSICAL-APPLY-ON';

停止 Broker

SQL> ALTER SYSTEM SET DG_BROKER_START=FALSE;

作 Switchover

DGMGRL> SWITCHOVER TO 'v480';

然后关闭 Pirmary 和 Standby,重新启动

七.在 Cluster 环境中的主备切换步骤

在应用中 cluster 环境是很常见的,下面简单介绍一下在 Sun Cluster 3.0 的环境中,

如果作 Data Guard 主备数据库的 Switchover 工作。

1.由于 Cluster 环境的监控,我们要手动关闭数据库的话,必须先关闭 cluster,单独

起一个节点的 oracle。其中 listener.ora.sigle 的配置文件是预先写好的监听配置,主要

不同是用主机的真实 IP 替换原先 Cluster 环境中的虚拟 IP。

/usr/cluster/bin/scswitch -F -g oracle-rg

mount /global/oradata

cd /export/home/oracle/app/oracle/product/9.2.0/network/admin

cp listener.ora.sigle listener.ora

lsnrctl start

第 108 页 共 131 页

Page 109: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

lsnrctl start listener_dg

sqlplus “/ as sysdba”

startup

2.在 SQL*Plus 中依次进行以下操作,完成切换 Primary 和 Standby 的工作

主数据库端:

ALTER DATABASE COMMIT TO SWITCHOVER TO PHYSICAL STANDBY;

SHUTDOWN IMMEDIATE;

STARTUP NOMOUNT;

ALTER DATABASE MOUNT STANDBY DATABASE;

备用数据库端:

ALTER DATABASE COMMIT TO SWITCHOVER TO PRIMARY;

SHUTDOWN IMMEDIATE;

STARTUP;

主数据库端:

ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT

FROM SESSION;

八.参考文档

Oracle Data Guard Concepts and Administration Release 2 (9.2)

Oracle9i Data Guard Broker Release 2 (9.2)

技术专题总结:standby Database - snowhite、chao_ping

Oracle 9i 备用数据库配置使用参考手册 - piner

[作者简介]

张乐奕,通常使用的网名为kamus,也曾用过seraphim,现在任职于北京某大型软件公司,Oracle

数据库DBA,主要负责证券行业的核心交易系统数据库管理及维护工作。

热切关注Oracle技术和相关操作系统技术,出没于各大数据库技术论坛,目前是中国 大的Oracle

技术论坛www.itpub.net的数据库管理版版主,

本人所有文章,不经许可,不得转载。

End

第 109 页 共 131 页

Page 110: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

32bit oracle SGA 扩展原理 和 SGA 与 PGA 的制约关

By biti_rainy

32bit oracle 由于位数限制,使得 oracle 进程只能访问 4g(2 的 32 次方)以下的虚拟内

存地址,在很多时候这是一个很让人头疼的问题,因为空着许多内存而不能使用,而默认情

况下 SGA 不能超过 1.7g。比如我们的 linux 下有 8g 内存,却有部分空着不能用干着急。这

个时候我们就要考虑怎样扩展 oracle 的 SGA。那么首先,如何识别 32bit 的 oracle 呢?我

们可以通过如下查询得到

sys@OCN> select * from v$version;

BANNER

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

Oracle9i Enterprise Edition Release 9。2。0。4。0 - Production

PL/SQL Release 9。2。0。4。0 - Production

CORE 9。2。0。3。0 Production

TNS for Linux: Version 9。2。0。4。0 - Production

NLSRTL Version 9。2。0。4。0 - Production

如果是 64bit oracle,在查询结果中一定会显示 64bit 字样,没有出现,则一定是 32bit

oracle 。当然,在 os 上通过 file oracle 也能看到

[oracle@ocn2 bin]$ cd $ORACLE_HOME/bin

[oracle@ocn2 bin]$ file oracle oracle: setuid setgid ELF 32-bit LSB executable, Intel 80386, version 1, dynamically

linked (uses shared libs), not stripped [oracle@ocn2 bin]$

在某些 os 上,比如 AIX 上,64bit oracle 会正常显示信息,32bit 则不正常显示。

在确认了 32bit oracle 之后,我们要明白,通常情况下我们的 OS 进程只能访问 4g 以

下的空间,redhat linux AS 2。1 或者 AS3。0 版本例外,他们可以提供 VLM(Very large memory)

功能支持,使得通过转换可以使用 36bit 来标志内存地址,那么就是 2 的 36 次方理论上

大可支持 64g 内存访问。在 oracle 中,则是通过将内存当作文件来访问的,虚拟一个

/dev/shm 的文件系统,这个文件系统是完全由内存组成的,这样将突破 4g 的限制。那回过

来我们看看,既然进程可以访问 4g 以下内存为何通常 SGA 又是 1。7g 呢。

在 OS 中,规定了一个进程在应用程序中,能访问的虚拟内存空间为 0--3g,而 3g--4g

这段虚拟地址空间是保留给 kernel 使用的。要注意我们这里强调的是虚拟地址空间,并没

第 110 页 共 131 页

Page 111: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

有说物理地址空间,也就是说,假设有 8g 的内存,这 0--3g 的虚拟地址空间可能出现在 8g

内存的 3g--8g 部分内存段,并不是说是物理内存的 0--3g 段。而在这 0--3g 的虚拟地址中,

oracle 又是如何来使用的呢,这是固定好了地址的。

+++++++++++++++ 4g

+ +

+ +

+ +

+++++++++++++++ 3g: kernel

+ +

+ +

+ +

+++++++++++++++ 2g:process stack

+ +

+ +

+++++++++++++++ 1。25g: SGA 起点

+++++++++++++++ 1g: oracle 共享库装载起点

+ +

+ +

+ +

+++++++++++++++ 0g:oracle program(可执行代码)装载起点

在这段虚拟地址的分配中,1。25g 是 sga 的起点,而进程的私有空间的分配(stack 部

分)却是从靠近 3g 处开始的。也就是实际上 SGA 和进程私有空间是共用了 1。25g---3g 这部

分的,由于进程私有空间特别小,通常我们习惯性地认为 SGA 可以达到 1。7g。进程私有空

间有 0。05g 足够了。从 oracle 一启动开始,或者从任何一用户进程登陆开始,所有虚拟地

址的分配都已经固定好了,只有用户私有空间还可以扩展。我们来看一下数据库启动后 pmon

进程(实际上任何一个进程都是一样的)的虚拟地址分配情况。由于我一台机器上跑着 2 个数

据库,所以我们看其中一个,先看看数据库 SGA 相关信息

[root@ocnsb1 root]# su - oracle

[oracle@ocnsb1 oracle]$ sqlplus "/ as sysdba"

SQL*Plus: Release 9。2。0。4。0 - Production on Mon Jul 26 11:37:23 2004

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

Connected to:

Oracle9i Enterprise Edition Release 9。2。0。4。0 - Production

With the Partitioning, Real Application Clusters, OLAP and Oracle Data Mining

options

JServer Release 9。2。0。4。0 - Production

sys@OCN>select INSTANCE_NAME from v$instance ; INSTANCE_NAME

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

第 111 页 共 131 页

Page 112: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

roocn1

show">sys@OCN>show sga

Total System Global Area 437327188 bytes

Fixed Size 451924 bytes

Variable Size 301989888 bytes

Database Buffers 134217728 bytes

Redo Buffers 667648 bytes sys@OCN>exit Disconnected from Oracle9i Enterprise Edition Release 9。2。0。4。0 - Production

With the Partitioning, Real Application Clusters, OLAP and Oracle Data Mining

options

JServer Release 9。2。0。4。0 - Production [oracle@ocnsb1 oracle]$ ipcs ------ Shared Memory Segments --------

key shmid owner perms bytes nattch status

0x73a32bdc 131072 oracle 640 457179136 50

0x84cc76ac 163841 oracle 640 1379926016 90

------ Semaphore Arrays --------

key semid owner perms nsems status

0x8df96364 622592 oracle 640 64

0x53609d64 753665 oracle 640 504

------ Message Queues --------

key msqid owner perms used-bytes messages

[oracle@ocnsb1 oracle]$

我这里的共享内存段只有一个,并且就是SGA的大小(shmid为131072)。这是因为shnmax

设置太大的缘故

[oracle@ocn2 kernel]$ more /proc/sys/kernel/shmmax 3221225472 [oracle@ocn2 kernel]$

接下来我们看看 PMON 信息,首先要找到 pmon 进程号,然后去 /proc/pid/maps 中看该

进程的虚拟地址分配信息

[oracle@ocnsb1 oracle]$ ps -ef|grep pmon oracle 13655 1 0 Jul24 ? 00:00:00 ora_pmon_roocn1

oracle 13926 1 0 Jul24 ? 00:00:00 ora_pmon_ocn1

oracle 31435 31092 0 11:51 pts/3 00:00:00 grep pmon [oracle@ocnsb1 oracle]$

[oracle@ocnsb1 oracle]$ more /proc/13655/maps 08048000-0a4ba000 r-xp 00000000 08:05 681621 /opt/oracle/products/9。2。

0/bin/oracle

0a4ba000-0ad54000 rw-p 02471000 08:05 681621 /opt/oracle/products/9。2。

第 112 页 共 131 页

Page 113: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

0/bin/oracle

0ad54000-0ae07000 rwxp 00000000 00:00 0

这部分是 oracle program 装载信息,我们可以看到空间使用了 0--0ae07000 ,这部分

大小不足 256MB

40000000-40016000 r-xp 00000000 08:02 448102 /lib/ld-2。2。4。so

这是 oracle 共享库装载的起点,0x40000000 正好是 1g

40016000-40017000 rw-p 00015000 08:02 448102 /lib/ld-2。2。4。so 40017000-40018000 rw-p 00000000 00:00 0 40018000-40019000 r-xp 00000000 08:05 308464 /opt/oracle/products/9。2。0/lib/libodmd9。so 40019000-4001a000 rw-p 00000000 08:05 308464 /opt/oracle/products/9。2。0/lib/libodmd9。so 4001a000-40026000 r-xp 00000000 08:05 308345 /opt/oracle/products/9。2。0/lib/libskgxp9。so 40026000-4002a000 rw-p 0000b000 08:05 308345 /opt/oracle/products/9。2。0/lib/libskgxp9。so 4002a000-40038000 r-xp 00000000 08:05 308461 /opt/oracle/products/9。2。0/lib/libskgxn9。so 40038000-40039000 rw-p 0000d000 08:05 308461 /opt/oracle/products/9。2。0/lib/libskgxn9。so 40039000-4004d000 rw-p 00000000 00:00 0 4004d000-4032c000 r-xp 00000000 08:05 308455 /opt/oracle/products/9。2。0/lib/libjox9。so4032c000-4043c000 rw-p 002de000 08:05 308455 /opt/oracle/products/9。2。0/lib/libjox9。so4043c000-4043e000 rw-p 00000000 00:00 0 4043e000-40441000 r-xp 00000000 08:02 448115 /lib/libdl-2。2。4。so 40441000-40442000 rw-p 00002000 08:02 448115 /lib/libdl-2。2。4。so 40442000-40443000 rw-p 00000000 00:00 0 40443000-40465000 r-xp 00000000 08:02 448117 /lib/libm-2。2。4。so 40465000-40466000 rw-p 00021000 08:02 448117 /lib/libm-2。2。4。so 40466000-40475000 r-xp 00000000 08:02 448147 /lib/libpthread-0。9。so 40475000-4047d000 rw-p 0000e000 08:02 448147 /lib/libpthread-0。9。so 4047d000-40490000 r-xp 00000000 08:02 448120 /lib/libnsl-2。2。4。so 40490000-40491000 rw-p 00012000 08:02 448120 /lib/libnsl-2。2。4。so 40491000-40493000 rw-p 00000000 00:00 0 40493000-40494000 r-xp 00000000 08:02 352330 /usr/lib/libaio。so。1 40494000-40495000 rw-p 00000000 08:02 352330 /usr/lib/libaio。so。1 40495000-405ca000 r-xp 00000000 08:02 448111 /lib/libc-2。2。4。so 405ca000-405cf000 rw-p 00134000 08:02 448111 /lib/libc-2。2。4。so 405cf000-405d3000 rw-p 00000000 00:00 0 405d3000-405d4000 r-xp 00000000 08:02 146106 /lib/libredhat-kernel。so。1。0。1 405d4000-405d5000 rw-p 00000000 08:02 146106 /lib/libredhat-kernel。so。1。0。1

第 113 页 共 131 页

Page 114: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

405d5000-405f9000 rw-p 00000000 00:00 0 405fa000-40604000 r-xp 00000000 08:02 448136 /lib/libnss_files-2。2。4。so 40604000-40605000 rw-p 00009000 08:02 448136 /lib/libnss_files-2。2。4。so 40605000-40685000 rw-p 00000000 08:02 69445 /dev/zero 40685000-406c6000 rw-p 00000000 00:00 0

共享库消耗了不到 20MB 的空间

50000000-6b000000 rw-s 00000000 00:04 131072 /SYSV73a32bdc

(deleted)

这是 SGA 的起点,0x50000000 表示 1。25g

6b000000-6b001000 r--s 1b000000 00:04 131072 /SYSV73a32bdc (deleted)

6b001000-6b0a2000 rw-s 1b001000 00:04 131072 /SYSV73a32bdc

(deleted)

6b0a2000-6b0a3000 r--s 1b0a2000 00:04 131072 /SYSV73a32bdc (deleted)

6b0a3000-6b400000 rw-s 1b0a3000 00:04 131072 /SYSV73a32bdc

(deleted)

sga 虚拟空间分配到这里,通过计算 16 进制数,正好和我们的 SGA 大小吻合,131072 就

是我们在 ipcs 查看的时候的 shmid

bffe5000-bffee000 rwxp ffff8000 00:00 0

bfff0000-bfff1000 r-xs 00000000 08:02 69304 /dev/vsys

由于 0xc0000000正好是3g(16进制数c=12,4*3=12,0x40000000表示1g),则这里表示

进程私有空间的分配的起点。查看 oracle 任何一个用户登陆进程也将发现这样的虚拟地址

分配。在这里我们很容易看出来,oracle program 和共享内存库所占用的空间很小,没有

必要给那么大,实际上,oracle program 给 256M 足够安全,而共享库给 50M 也足够安全

了,也就是从理论上来讲,我们可以把 oracle program 所需要压缩在 0x10000000 以下,

共享库所需要内存压缩在 0x12000000以下,这样SGA的起点就可以提升到0x12000000(0。

3g)。而原来是从 0x5000000(1。25g)开始的,只有大约 1。7g 分配给 SGA,现在从 0。3g

开始分配 SGA 则可以接近 2。7g,比如分配 2。65g 内存给 SGA。要实现这个功能,我们需要

重新编译 oracle program,降低共享库虚拟内存分配的地址和 SGA 的分配起点位置。

0x4000000 这个共享库装载的起点,是由进程的 mapped_base 来决定的

[oracle@ocnsb1 oracle]$ more /proc/13655/mapped_base 1073741824

这个大小是 1G,则意味着共享库的装载从虚拟地址的 1g 位置开始,如果要降低这个地

址,需要在 oracle 启动之前,也就是用 root 用户把将启动 oracle 的进程的 mapped_base

降低到 256M,这样 oracle 启动之后的产生的进程都将继承这个值。

su - root echo 268435456 > /proc//mapped_base

当然我们也可以通过一些 shell 来实现 oracle 用户登陆之后自动降低 mapped_base 的

功能,这个在 google 上就能找到了。

第 114 页 共 131 页

Page 115: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

SGA 起点从 1。25g 降低到 0。3g 则需要重新编译 oracle program。必须要强调的是,

SGA 的起点是和共享库的起点 mapped_ase 相关的,SGA 的起点至少得大于共享库的起点 0。

05g 以上才是安全的,否则数据库将不能启动或者崩溃。

关闭 oracle

su – oracle

cd $ORACLE_HOME/rdbms/lib

修改共享库装载地址的文件定义

genksms -s 0x12000000 > ksms。s

编译好目标文件

make -f ins_rdbms。mk ksms。o

重新编译 oracle 可执行文件

make -f ins_rdbms。mk ioracle

至于 redhat linux AS 2。1 以上版本 oracle 的 VLM 的使用则也是比较简单的了,google很容易找到的。。

在这里我要指出一个问题,也是我们在实践中遇到的一个问题,那就是,若 SGA 分配的

很大,但没有使用 VLM,几乎很靠近 3g 的时候,大约只留下 20m 左右。这样当一个进程进

行 hash join,由于我们的 pga_aggregate_target 设置为 1g,oracle 默认单个进程使用 PGA

可以达到 pga_aggregate_target * 5% = 50M,则使得在进行 hash join 的时候出错

ORA-04030: out of process memory when trying to allocate 254476 bytes

(hash-join subh,kllcqas:kllsltba)

我们调整 pga_aggregate_target 减小到 400M 则该查询执行成功。因为没有使用 VLM 的

情况下单个进程的内存分配空间必须在 3g 以下,而 PGA 的分配也属于这个范畴。如果使用

VLM 则 PGA 已经被分配到 4g 以上部分的虚拟地址,不再有这个问题。在此不再对 VLM进行过多的阐述,因为使用也比较简单,从原理上来讲就是通过 os 扩展 32bit 到 36bit,oracle使用文件来管理内存,并支持进程访问 4g 以上部分的虚拟内存。linux 上这种用法得到推广

的根本原因是因为其 64bit oracle很少被使用,其他如 sunOS/hp unix/AIX 等都广泛使用 64bit oracle 了,这些方法也就失去价值了。

下面我们来看看 32bit 下 SGA 与 PGA 之间的制约关系

在我的测试中,由于我降低了 SGA 的起点(降低 SGA 起点和本文章没有实质上的关系,

仅仅因为我的测试数据库正好是被降低了 sga 起点而已),从 0x5000000 降低到 0x42000000,也就是说,当没有降低的时候,SGA 的理论极限值是约小于 1。75G,我降低起点后,SGA的极限值大约是 1。95G。

sys@OCN> show sga

Total System Global Area 2064719084 bytes

第 115 页 共 131 页

Page 116: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

Fixed Size 453868 bytes

Variable Size 385875968 bytes

Database Buffers 1677721600 bytes

Redo Buffers 667648 bytes

sys@OCN> 我的 SGA_MAX_SIZE 的大小这时为 2064719084 。 sys@OCN> show parameters sga_max_size

NAME TYPE VALUE

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

sga_max_size big integer 2064719084

实际上,我这个时候的 SGA_MAX_SIZE 比真实的 SGA 设置要大一些,这是我手工调

大的。我们来观察单个数据库进程的 maps

[oracle@ocnsb2 oracle]$ ps -ef|grep pmon oracle 18346 1 0 12:16 ? 00:00:00 ora_pmon_roocn

oracle 18535 18493 0 13:04 pts/0 00:00:00 grep pmon

[oracle@ocnsb2 oracle]$ more /proc/18346/maps 08048000-0a4b9000 r-xp 00000000 08:05 324868 /opt/oracle/products/9 。 2 。

0/bin/oracle

0a4b9000-0ad53000 rw-p 02470000 08:05 324868 /opt/oracle/products/9 。 2 。

0/bin/oracle

0ad53000-0adec000 rwxp 00000000 00:00 0

40000000-40016000 r-xp 00000000 08:02 448102 /lib/ld-2。2。4。so

40016000-40017000 rw-p 00015000 08:02 448102 /lib/ld-2。2。4。so

40017000-40018000 rw-p 00000000 00:00 0

40018000-40019000 r-xp 00000000 08:05 1038540 /opt/oracle/products/9 。 2 。

0/lib/libodmd9。so

40019000-4001a000 rw-p 00000000 08:05 1038540 /opt/oracle/products/9 。 2 。

0/lib/libodmd9。so

4001a000-40026000 r-xp 00000000 08:05 1038423 /opt/oracle/products/9 。 2 。

0/lib/libskgxp9。so

40026000-4002a000 rw-p 0000b000 08:05 1038423 /opt/oracle/products/9 。 2 。

0/lib/libskgxp9。so

4002a000-40038000 r-xp 00000000 08:05 1038537 /opt/oracle/products/9 。 2 。

0/lib/libskgxn9。so

40038000-40039000 rw-p 0000d000 08:05 1038537 /opt/oracle/products/9 。 2 。

0/lib/libskgxn9。so

40039000-4004d000 rw-p 00000000 00:00 0

4004d000-4032c000 r-xp 00000000 08:05 1038531 /opt/oracle/products/9 。 2 。

0/lib/libjox9。so

4032c000-4043c000 rw-p 002de000 08:05 1038531 /opt/oracle/products/9 。 2 。

0/lib/libjox9。so

第 116 页 共 131 页

Page 117: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

4043c000-4043e000 rw-p 00000000 00:00 0

4043e000-40441000 r-xp 00000000 08:02 448115 /lib/libdl-2。2。4。so

40441000-40442000 rw-p 00002000 08:02 448115 /lib/libdl-2。2。4。so

40442000-40443000 rw-p 00000000 00:00 0

40443000-40465000 r-xp 00000000 08:02 448117 /lib/libm-2。2。4。so

40465000-40466000 rw-p 00021000 08:02 448117 /lib/libm-2。2。4。so

40466000-40475000 r-xp 00000000 08:02 448147 /lib/libpthread-0。9。so

40475000-4047d000 rw-p 0000e000 08:02 448147 /lib/libpthread-0。9。so

4047d000-40490000 r-xp 00000000 08:02 448120 /lib/libnsl-2。2。4。so

40490000-40491000 rw-p 00012000 08:02 448120 /lib/libnsl-2。2。4。so

40491000-40493000 rw-p 00000000 00:00 0

40493000-405c8000 r-xp 00000000 08:02 448111 /lib/libc-2。2。4。so

405c8000-405cd000 rw-p 00134000 08:02 448111 /lib/libc-2。2。4。so

405cd000-405f4000 rw-p 00000000 00:00 0

405f5000-405ff000 r-xp 00000000 08:02 448136 /lib/libnss_files-2。2。4。so

405ff000-40600000 rw-p 00009000 08:02 448136 /lib/libnss_files-2。2。4。so

40600000-40680000 rw-p 00000000 08:02 69445 /dev/zero

40680000-406c1000 rw-p 00000000 00:00 0

42000000-be400000 rw-B 00000000 00:04 524288 /SYSV0676004c (deleted)

bffe4000-bffee000 rwxp ffff7000 00:00 0

0a4b9000-0ad53000 rw-p 02470000 08:05 324868 /opt/oracle/products/9 。 2 。

0/bin/oracle

0ad53000-0adec000 rwxp 00000000 00:00 0

40000000-40016000 r-xp 00000000 08:02 448102 /lib/ld-2。2。4。so

40016000-40017000 rw-p 00015000 08:02 448102 /lib/ld-2。2。4。so

40017000-40018000 rw-p 00000000 00:00 0

40018000-40019000 r-xp 00000000 08:05 1038540 /opt/oracle/products/9 。 2 。

0/lib/libodmd9。so

40019000-4001a000 rw-p 00000000 08:05 1038540 /opt/oracle/products/9 。 2 。

0/lib/libodmd9。so

4001a000-40026000 r-xp 00000000 08:05 1038423 /opt/oracle/products/9 。 2 。

0/lib/libskgxp9。so

40026000-4002a000 rw-p 0000b000 08:05 1038423 /opt/oracle/products/9 。 2 。

0/lib/libskgxp9。so

4002a000-40038000 r-xp 00000000 08:05 1038537 /opt/oracle/products/9 。 2 。

0/lib/libskgxn9。so

40038000-40039000 rw-p 0000d000 08:05 1038537 /opt/oracle/products/9 。 2 。

0/lib/libskgxn9。so

40039000-4004d000 rw-p 00000000 00:00 0

4004d000-4032c000 r-xp 00000000 08:05 1038531 /opt/oracle/products/9 。 2 。

0/lib/libjox9。so

4032c000-4043c000 rw-p 002de000 08:05 1038531 /opt/oracle/products/9 。 2 。

0/lib/libjox9。so

4043c000-4043e000 rw-p 00000000 00:00 0

第 117 页 共 131 页

Page 118: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

4043e000-40441000 r-xp 00000000 08:02 448115 /lib/libdl-2。2。4。so

40441000-40442000 rw-p 00002000 08:02 448115 /lib/libdl-2。2。4。so

40442000-40443000 rw-p 00000000 00:00 0

40443000-40465000 r-xp 00000000 08:02 448117 /lib/libm-2。2。4。so

40465000-40466000 rw-p 00021000 08:02 448117 /lib/libm-2。2。4。so

40466000-40475000 r-xp 00000000 08:02 448147 /lib/libpthread-0。9。so

40475000-4047d000 rw-p 0000e000 08:02 448147 /lib/libpthread-0。9。so

4047d000-40490000 r-xp 00000000 08:02 448120 /lib/libnsl-2。2。4。so

40490000-40491000 rw-p 00012000 08:02 448120 /lib/libnsl-2。2。4。so

40491000-40493000 rw-p 00000000 00:00 0

40493000-405c8000 r-xp 00000000 08:02 448111 /lib/libc-2。2。4。so

405c8000-405cd000 rw-p 00134000 08:02 448111 /lib/libc-2。2。4。so

405cd000-405f4000 rw-p 00000000 00:00 0

405f5000-405ff000 r-xp 00000000 08:02 448136 /lib/libnss_files-2。2。4。so

405ff000-40600000 rw-p 00009000 08:02 448136 /lib/libnss_files-2。2。4。so

40600000-40680000 rw-p 00000000 08:02 69445 /dev/zero

40680000-406c1000 rw-p 00000000 00:00 0

42000000-be400000 rw-B 00000000 00:04 524288 /SYSV0676004c (deleted)

这里可以看出单个进程中根据 SGA_MAX_SIZE 预分配了 0x42000000 --

0xbe400000 这段虚拟内存空间,虽然实际 SGA 并没有这么大,但是正是这段空间的预留,

为 9i 中动态增大 SGA 提供了可能。也就是说进程能访问的虚拟地址空间是登陆上数据库的

时候决定的,这样即使 sga 真正地发生了变化,只要在 SGA_MAX_SIZE 之内,该进程都可

以访问这些虚拟内存空间。

sys@OCN>select (to_number('be400000','xxxxxxxxxx') -

to_number('42000000','xxxxxxxxxx'))/1024/1024 from dual; (TO_NUMBER('BE400000','XXXXXXXXXX')-TO_NUMBER('42000000','XXXXXXXXXX

'))/1024/1024

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

1988

sys@OCN> bffe4000-bffee000 rwxp ffff7000 00:00 0 [oracle@ocnsb2 oracle]$

从这里可以看出进程的私有内存分配的顶点,我们看

0xbe400000--0xbffe4000 属于 oracle 进程可使用的 PGA 的空间大小

sys@OCN> select to_number('bffe4000','xxxxxxxxxx') -

to_number('be400000','xxxxxxxxxx') from dual; TO_NUMBER('BFFE4000','XXXXXXXXXX')-TO_NUMBER('BE400000','XXXXXXXXXX'

)

第 118 页 共 131 页

Page 119: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

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

29245440

从这里可以看出 PGA 能使用的空间大约是 29245440 字节

我们来做一个测试

sys@OCN> show parameters pga NAME TYPE VALUE

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

pga_aggregate_target big integer 524288000

在 oracle 中单个进程的 PGA 的使用遵循的原则是 小于 min(pga_aggregate_target *5%, 100MB),在这样的设置下我执行对两个大表做 hash join 的查询,结果是成功完成。然后我修

改 pga_aggregate_target = 1024M

sys@OCN> alter system set pga_aggregate_target = 1024m;

System altered。

sys@OCN> show parameters pga

NAME TYPE VALUE

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

pga_aggregate_target big integer 1073741824

当我再运行这个查询的过程中,我同时观察该进程的 PGA 使用量

在 session 1 中执行 1* select * from company c,member m where c。admin_member_id = m。login_id

alibaba@OCN> /

ERROR:

ORA-04030: out of process memory when trying to allocate 254476 bytes (hash-join

subh,kllcqas:kllsltba)

no rows selected

Execution Plan

在 session2 中观察结果(不停地执行下面的查询观察变化)

sys@OCN> select spid,USERNAME,PGA_USED_MEM ,PGA_ALLOC_MEM,PGA_FR

EEABLE_MEM, PGA_MAX_MEM from v$process;

SPID USERNAME PGA_USED_MEM PGA_ALLOC_MEM

PGA_FREEABLE_MEM PGA_MAX_MEM

第 119 页 共 131 页

Page 120: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

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

0 0 0 0

18346 oracle 147425 476981 0 476981

18348 oracle 244313 570985 0 570985

18350 oracle 1304737 1635765 0 1635765

18354 oracle 2945957 3300193 0 3300193

18356 oracle 200089 534729 0 534729

18358 oracle 4368569 4741969 0 4741969

18360 oracle 151577 551357 0 551357

18362 oracle 165841 510101 0 510101

18364 oracle 156625 485493 0 485493

18366 oracle 157009 485493 0 485493

18368 oracle 4362441 4748549 0 4748549

18370 oracle 4362441 4715245 0 4715245

18388 oracle 191285 790553 196608 790553

18406 oracle 29041865 30095501 0 30095501

我们发现,执行 hash join 的进程的 PGA 大达到 29041865 之后,就报出错误 4030 而

返回了,基本吻合前面关于 SGA_MAX_SIZE 与进程私有空间虚拟地址的顶点之间的计算。

[作者简介]

冯春培,网络 ID biti_rainy

曾任 itpub Oracle 开发版版主,现任 itpub Oracle 管理版版主和超级版主。

有丰富的 oracle 实践经验,对数据库的体系结构、备份恢复、sql 优化、数据库整体性能优化、oracle

internal 都有深入研究。

开发出身,对数据库应用设计中如何正确地应用 oracle 特性以扬长避短具有深刻理解。

曾于某电信集成公司负责计费系统的开发,然后成为某系统集成公司的 DBA,再辗转在香港一家跨国

公司珠海研发中心担任技术负责人(公司主要产品就是 sql 与数据库优化工具,产品主要销往欧洲

和北美),此后成为自由职业者,为客户提供独立的 oracle 数据库的技术服务和高级性能调整等培

训,同时提供 ITPUB 华南和华东的培训。

目前服务于国内某大型电子商务网站,维护系统数据库并提供开发支持。

《Oracle 数据库 DBA 专题技术精粹》一书的主编及主要作者。

更多个人作品:http://blog.itpub.net/biti_rainy

End

第 120 页 共 131 页

Page 121: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

关于 shared pool 的深入探讨(之一)

By Eygle

题记:

在 Oracle 的设置管理中,SGA 的设置一直是非常重要的一部分内容.虽然在 Oracle10g中,Oracle 实现了自动 SGA 调整,但是了解 Oracle SGA 的原理,正确设置 SGA 各组件仍然是

DBA 的一个基本工作.

在 SGA 的设置中,shared pool 无疑是 复杂和 重要的部分.本文以及系列文章从内部原

理探讨 shared pool 的原理及设置.

本文没有过多的从基础讲起,需要读者具有一定的基础知识,适宜读者范围:中高级

关于 shared pool 的设置一直是一个争议较多的内容.

很多文章上说,shared pool 设置过大会带来额外的管理上的负担,从而在某些条件下会导

致性能的下降.

那么这个管理上的负担指的是什么内容呢?

本文对这个内容作一定的深入探讨.

本文只涉及一个方面,后续的文章将从其他方面继续讨论.

(一)基础知识

我们可以通过如下命令转储 shared pool 共享内存的内容:

SQL> alter session set events 'immediate trace name heapdump level 2';

Session altered.

本测试中引用的两个 trace 文件:

9i: SQL> @gettrcname

TRACE_FILE_NAME

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

/opt/oracle/admin/hsjf/udump/hsjf_ora_24983.trc

8i: SQL> @gettrcname

第 121 页 共 131 页

Page 122: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

TRACE_FILE_NAME

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

/usr/oracle8/admin/guess/udump/guess_ora_22038.trc

关于这里用到的 gettrcname 脚本,你可以在以下网址找到:

http://www.eygle.com/faq/How.To.Get.Tracefile.Name.htm

Shared Pool 通过 free list 管理 free 块,Free List 按不同 size 划分 Bucket

(二)Oracle8i 中的管理方式

在 Oracle8i 中,不同 bucket 的 size 范围如下所示(size 显示的是下边界):

oracle:/usr/oracle8/admin/guess/udump>cat guess_ora_22038.trc|grep Bucket

Bucket 0 size=44

Bucket 1 size=76

Bucket 2 size=140

Bucket 3 size=268

Bucket 4 size=524

Bucket 5 size=1036

Bucket 6 size=2060

Bucket 7 size=4108

Bucket 8 size=8204

Bucket 9 size=16396

Bucket 10 size=32780

我们注意,在这里,小于 76 的块都位于 Bucket 0 上;大于 32780 的块,都在 Bucket 10 上.初始的,数据库启动以后,shared pool 多数是连续内存块.当空间分配使用以后,内存块开始被

分割,碎片开始出现,Bucket 列表开始变长

Oracle 请求 shared pool 空间时,首先进入相应的 Bucket 进行查找,如果找不到,则转向下

一个非空的 bucket,获取第一个 chunk,分割这个 chunk,剩余部分会进入相应的 Bucket,进一步

增加碎片

终的结果是,Bucket 0 上的内存块会越来越多,越来越碎小

( 在我这个测试的小型的数据库上 ,Bucket 0 上的碎片已经达到 9030 个 , 而shared_pool_size 设置仅为 150M)

通常如果每个 Bucket 上的 chunk 多于 2000 个,就被认为是 share pool 碎片过多

而在大多数情况下,我们请求的都是相对小的 chunk,这样搜索 Bucket 0 往往消耗了大量

的时间以及资源,这可能导致 share pool Latch 被长时间的持有,导致更多的 share pool 竞争

所以在 Oracle9i 之前,如果盲目的增大 shared_pool_size 或设置过大的 shared_pool_size,

第 122 页 共 131 页

Page 123: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

往往会适得其反.

(三)Oracle9i 中的 shared pool 管理方式

我们看一下 Oracle9i 中的处理方式:

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

SQL*Plus: Release 9.2.0.3.0 - Production on Wed Aug 18 22:13:07 2004

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

Connected to:

Oracle9i Enterprise Edition Release 9.2.0.3.0 - Production

With the Partitioning, OLAP and Oracle Data Mining options

JServer Release 9.2.0.3.0 - Production

SQL> alter session set events 'immediate trace name heapdump level 2';

Session altered.

SQL> @gettrcname

TRACE_FILE_NAME

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

/opt/oracle/admin/hsjf/udump/hsjf_ora_24983.trc

SQL>

SQL> !

[oracle@jumper oracle]$ cd $admin

[oracle@jumper udump]$ cat hsjf_ora_24983.trc|grep Bucket

Bucket 0 size=16

Bucket 1 size=20

Bucket 2 size=24

Bucket 3 size=28

Bucket 4 size=32

Bucket 5 size=36

Bucket 6 size=40

Bucket 7 size=44

Bucket 8 size=48

Bucket 9 size=52

Bucket 10 size=56

Bucket 11 size=60

第 123 页 共 131 页

Page 124: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

Bucket 12 size=64

Bucket 13 size=68

Bucket 14 size=72

Bucket 15 size=76

Bucket 16 size=80

Bucket 17 size=84

Bucket 18 size=88

Bucket 19 size=92

Bucket 20 size=96

Bucket 21 size=100

Bucket 22 size=104

Bucket 23 size=108

Bucket 24 size=112

Bucket 25 size=116

Bucket 26 size=120

Bucket 27 size=124

Bucket 28 size=128

Bucket 29 size=132

Bucket 30 size=136

Bucket 31 size=140

Bucket 32 size=144

Bucket 33 size=148

Bucket 34 size=152

Bucket 35 size=156

Bucket 36 size=160

Bucket 37 size=164

Bucket 38 size=168

Bucket 39 size=172

Bucket 40 size=176

Bucket 41 size=180

Bucket 42 size=184

Bucket 43 size=188

Bucket 44 size=192

Bucket 45 size=196

Bucket 46 size=200

Bucket 47 size=204

Bucket 48 size=208

Bucket 49 size=212

Bucket 50 size=216

Bucket 51 size=220

Bucket 52 size=224

Bucket 53 size=228

Bucket 54 size=232

Bucket 55 size=236

第 124 页 共 131 页

Page 125: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

Bucket 56 size=240

Bucket 57 size=244

Bucket 58 size=248

Bucket 59 size=252

Bucket 60 size=256

Bucket 61 size=260

Bucket 62 size=264

Bucket 63 size=268

Bucket 64 size=272

Bucket 65 size=276

Bucket 66 size=280

Bucket 67 size=284

Bucket 68 size=288

Bucket 69 size=292

Bucket 70 size=296

Bucket 71 size=300

Bucket 72 size=304

Bucket 73 size=308

Bucket 74 size=312

Bucket 75 size=316

Bucket 76 size=320

Bucket 77 size=324

Bucket 78 size=328

Bucket 79 size=332

Bucket 80 size=336

Bucket 81 size=340

Bucket 82 size=344

Bucket 83 size=348

Bucket 84 size=352

Bucket 85 size=356

Bucket 86 size=360

Bucket 87 size=364

Bucket 88 size=368

Bucket 89 size=372

Bucket 90 size=376

Bucket 91 size=380

Bucket 92 size=384

Bucket 93 size=388

Bucket 94 size=392

Bucket 95 size=396

Bucket 96 size=400

Bucket 97 size=404

Bucket 98 size=408

Bucket 99 size=412

第 125 页 共 131 页

Page 126: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

Bucket 100 size=416

Bucket 101 size=420

Bucket 102 size=424

Bucket 103 size=428

Bucket 104 size=432

Bucket 105 size=436

Bucket 106 size=440

Bucket 107 size=444

Bucket 108 size=448

Bucket 109 size=452

Bucket 110 size=456

Bucket 111 size=460

Bucket 112 size=464

Bucket 113 size=468

Bucket 114 size=472

Bucket 115 size=476

Bucket 116 size=480

Bucket 117 size=484

Bucket 118 size=488

Bucket 119 size=492

Bucket 120 size=496

Bucket 121 size=500

Bucket 122 size=504

Bucket 123 size=508

Bucket 124 size=512

Bucket 125 size=516

Bucket 126 size=520

Bucket 127 size=524

Bucket 128 size=528

Bucket 129 size=532

Bucket 130 size=536

Bucket 131 size=540

Bucket 132 size=544

Bucket 133 size=548

Bucket 134 size=552

Bucket 135 size=556

Bucket 136 size=560

Bucket 137 size=564

Bucket 138 size=568

Bucket 139 size=572

Bucket 140 size=576

Bucket 141 size=580

Bucket 142 size=584

Bucket 143 size=588

第 126 页 共 131 页

Page 127: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

Bucket 144 size=592

Bucket 145 size=596

Bucket 146 size=600

Bucket 147 size=604

Bucket 148 size=608

Bucket 149 size=612

Bucket 150 size=616

Bucket 151 size=620

Bucket 152 size=624

Bucket 153 size=628

Bucket 154 size=632

Bucket 155 size=636

Bucket 156 size=640

Bucket 157 size=644

Bucket 158 size=648

Bucket 159 size=652

Bucket 160 size=656

Bucket 161 size=660

Bucket 162 size=664

Bucket 163 size=668

Bucket 164 size=672

Bucket 165 size=676

Bucket 166 size=680

Bucket 167 size=684

Bucket 168 size=688

Bucket 169 size=692

Bucket 170 size=696

Bucket 171 size=700

Bucket 172 size=704

Bucket 173 size=708

Bucket 174 size=712

Bucket 175 size=716

Bucket 176 size=720

Bucket 177 size=724

Bucket 178 size=728

Bucket 179 size=732

Bucket 180 size=736

Bucket 181 size=740

Bucket 182 size=744

Bucket 183 size=748

Bucket 184 size=752

Bucket 185 size=756

Bucket 186 size=760

Bucket 187 size=764

第 127 页 共 131 页

Page 128: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

Bucket 188 size=768

Bucket 189 size=772

Bucket 190 size=776

Bucket 191 size=780

Bucket 192 size=784

Bucket 193 size=788

Bucket 194 size=792

Bucket 195 size=796

Bucket 196 size=800

Bucket 197 size=804

Bucket 198 size=808

Bucket 199 size=812

Bucket 200 size=876

Bucket 201 size=940

Bucket 202 size=1004

Bucket 203 size=1068

Bucket 204 size=1132

Bucket 205 size=1196

Bucket 206 size=1260

Bucket 207 size=1324

Bucket 208 size=1388

Bucket 209 size=1452

Bucket 210 size=1516

Bucket 211 size=1580

Bucket 212 size=1644

Bucket 213 size=1708

Bucket 214 size=1772

Bucket 215 size=1836

Bucket 216 size=1900

Bucket 217 size=1964

Bucket 218 size=2028

Bucket 219 size=2092

Bucket 220 size=2156

Bucket 221 size=2220

Bucket 222 size=2284

Bucket 223 size=2348

Bucket 224 size=2412

Bucket 225 size=2476

Bucket 226 size=2540

Bucket 227 size=2604

Bucket 228 size=2668

Bucket 229 size=2732

Bucket 230 size=2796

Bucket 231 size=2860

第 128 页 共 131 页

Page 129: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

Bucket 232 size=2924

Bucket 233 size=2988

Bucket 234 size=3052

Bucket 235 size=3116

Bucket 236 size=3180

Bucket 237 size=3244

Bucket 238 size=3308

Bucket 239 size=3372

Bucket 240 size=3436

Bucket 241 size=3500

Bucket 242 size=3564

Bucket 243 size=3628

Bucket 244 size=3692

Bucket 245 size=3756

Bucket 246 size=3820

Bucket 247 size=3884

Bucket 248 size=3948

Bucket 249 size=4012

Bucket 250 size=4108

Bucket 251 size=8204

Bucket 252 size=16396

Bucket 253 size=32780

Bucket 254 size=65548

(四)总结

我们看到,在 Oracle9i 中,Free Lists 被划分为 0~254,共 255 个 Bucket

每个 Bucket 容纳的 size 范围

Bucket 0~199 容纳 size 以 4 递增

Bucket 200~249 容纳 size 以 64 递增

从 Bucket 249 开始,Oracle 各 Bucket 步长进一步增加:

Bucket 249: 4012 ~4107 = 96

Bucket 250: 4108 ~8203 = 4096

Bucket 251: 8204 ~16395 = 8192

Bucket 252: 16396~32779 = 16384

Bucket 253: 32780~65547 = 32768

Bucket 254: >=65548

在 Oracle9i 中,对于小的 chunk,Oracle 增加了更多的 Bucket 来管理.0~199 共 200 个

Bucket,size 以 4 为步长递增;200~249 共 50 个 Bucket,size 以 64 递增.这样每个 Bucket 中容纳

的 chunk 数量大大减少,查找的效率得以提高.

第 129 页 共 131 页

Page 130: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

这就是 Oracle9i 中 shared pool 管理的增强,通过这个算法的改进.Oracle8i 中,过大 shared pool 带来的栓锁争用等性能问题在某种程度上得以解决.

关于本系列的进一步探讨,你可以在我的个人网站上找到:

关于 shared pool 的深入探讨(一)

http://www.eygle.com/internal/shared_pool-1.htm

关于 shared pool 的深入探讨(二)

http://www.eygle.com/internal/shared_pool-2.htm

关于 shared pool 的深入探讨(三)

http://www.eygle.com/internal/shared_pool-3.htm

关于 shared pool 的深入探讨(四)

http://www.eygle.com/internal/shared_pool-4.htm

关于 shared pool 的深入探讨(五)

http://www.eygle.com/internal/shared_pool-5.htm

关于 shared pool 的深入探讨(六)

http://www.eygle.com/internal/shared_pool-6.htm [作者简介]

盖国强,网名 eygle

曾任 ITPUB MS 版版主,现任 itpub Oracle 管理版版主.

曾任职于某国家大型企业,服务于烟草行业,开发过基于 Oracle 数据库的大型 ERP 系统,属国家信息产业

部重点工程.同时负责 Oracle 数据库管理及优化,并为多家烟草企业提供 Oracle 数据库管理、优化及技术支

持.

目前任职于北京某电信增值业务系统提供商企业,首席 DBA,负责数据库业务.管理全国 30 多个数据库

系统。项目经验丰富,曾设计规划及支持中国联通增值业务等大型数据库系统.

实践经验丰富,长于数据库诊断、性能调整与 SQL 优化等.

高级培训讲师,培训经验丰富,曾主讲 itpub dba 培训及 itpub 高级性能调整等主要课程.

《Oracle 数据库 DBA 专题技术精粹》一书的主编及主要作者.

你可以在http://www.eygle.com上找到关于作者的更多信息.

End

第 130 页 共 131 页

Page 131: Csdn Emag(Oracle)第一期

http:/emag.csdn.net CSDN 电子杂志 ------------------------- 创刊号总第一期

本期杂志制作人员:

主编/定稿/审稿: eygle([email protected]

排版/校订:

Snowywolf ([email protected]

第 131 页 共 131 页