数据库oracle数据库学习

oracle数据库学习  时间:2021-04-05  阅读:()
目录第1章数据库的基本知识11.
1数据库技术11.
1.
1了解数据库11.
1.
2信息、数据、信息处理21.
1.
3数据库管理技术的发展31.
2数据模型61.
3数据库管理系统111.
3.
1数据的安全121.
3.
2维护和实施完整性131.
3.
3理解事务141.
3.
4数据独立性141.
3.
5与数据库通信161.
4关系数据库管理系统161.
4.
1关系模型171.
4.
2Codd十二条法则.
181.
5小结19第2章逻辑数据库的设计与实现212.
1数据库设计原理212.
1.
1数据库设计的内容、方法和步骤.
212.
1.
2系统规划222.
1.
3需求分析232.
1.
4概念设计242.
1.
5逻辑设计252.
1.
6物理设计262.
1.
7实现和维护282.
2关系模型和规范化292.
2.
1关系模型292.
2.
2规范化312.
2.
3第一范式到第五范式332.
2.
4域/关键字范式372.
2.
5关系综合392.
2.
6设计折中41VII2.
3用实体联系模型设计数据库.
422.
3.
1实体联系模型到数据库设计的转换.
432.
3.
2树、网络和材料单552.
4逻辑数据库的实现:物理数据库的设计.
582.
4.
1关于应用类型582.
4.
2定量评估的使用592.
4.
3出于性能的考虑使非标准化612.
4.
4理解存储分层结构622.
4.
5冗余廉价磁盘阵列632.
4.
6DBMS中的瓶颈.
642.
4.
7平台的选择642.
4.
8操作系统集成和通用内存/CPU建议.
652.
4.
9物理设计原则和常用硬件设计建议.
662.
5小结68第3章结构化查询语言SQL713.
1Oracle数据库的基本概念.
713.
2SQL的基本概念.
723.
3数据库查询733.
3.
1SQL的基本结构.
733.
3.
2简单查询的语法743.
3.
3查询条件的描述763.
3.
4SQL命令的编辑.
783.
4数据操纵793.
4.
1插入数据793.
4.
2删除和修改803.
4.
3提交和回滚813.
5创建表和视图813.
6SQL*Plus的报表.
843.
6.
1报表示例843.
6.
2报表格式命令853.
6.
3编辑文件命令873.
7函数883.
7.
1基本函数883.
7.
2组函数913.
8复杂查询933.
8.
1连接运算933.
8.
2子查询953.
9特权和角色963.
10索引983.
11并发控制98VIII3.
12管理员使用的SQL*Plus1003.
12.
1系统管理的SQL*Plus.
1003.
12.
2使用SQL*Plus的COPY命令.
1083.
12.
3使用SQL*Plus创建SQL.
1103.
12.
4在SQL*Plus中对用户权限的限制1123.
12.
5追踪SQL语句.
1163.
12.
6SQL*Plus8.
1版的增强1223.
13小结124第4章Oracle8数据库介绍1284.
1Oracle8.
1284.
1.
1最新版本的Oracle8.
1284.
1.
2Oracle8主要的改进.
1294.
1.
3Oracle8产品家族.
1314.
1.
4在应用环境中装备Oracle8.
1324.
2Oracle数据库体系.
1324.
2.
1SYS和SYSTEM模式1324.
2.
2数据库组件1334.
2.
3数据库段1394.
2.
4Oracle数据字典.
1424.
2.
5其他数据库对象1434.
3Oracle的一些基本概念.
1444.
3.
1进程1444.
3.
2内存与速度1454.
3.
3磁盘存储1464.
3.
4与DBMS的连接.
1474.
3.
5多处理器配置1484.
3.
6容错1494.
4分区1494.
4.
1什么是分区1504.
4.
2Oracle8分区的实例.
1524.
4.
3分区索引1544.
4.
4维护操作1554.
4.
5并行能力1574.
4.
6附加的考虑1584.
5面向对象的特性1594.
5.
1面向对象的背景1594.
5.
2面向对象技术1604.
5.
3Oracle8对象选项.
1614.
5.
4REF属性.
1624.
5.
5方法163IX4.
5.
6集合、变量数组和嵌套表1644.
5.
7对象视图1654.
6Oracle8i概述.
1664.
6.
1Oracle8i中的Java能力.
1664.
6.
2因特网文件系统(iFS)1744.
6.
3OracleinterMedia1754.
6.
4OracleWebDB.
1764.
6.
5Oracle8i的可用性和可恢复性.
1764.
6.
6安全性1774.
6.
7其他特性1784.
7Oracle8i的附加主题.
1814.
7.
1新的行内部地址(ROWID)1814.
7.
2口令管理的增强1834.
7.
3恢复管理器概念1854.
7.
4高级队列概念1884.
7.
5约束、国家语言支持和SYS安全性1894.
8小结190第5章Oracle8数据库编程1945.
1用PL/SQL对Oracle数据库编程.
1945.
1.
1程序块结构语言PL/SQL.
1945.
1.
2用PL/SQL说明变量.
1965.
1.
3一些常见的控制结构1975.
1.
4在PL/SQL程序中使用SQL语句.
2015.
1.
5PL/SQL子块的应用.
2035.
1.
6过程的说明2045.
1.
7函数的说明2065.
2用PL/SQL进行程序开发2095.
2.
1建立存储过程或函数2105.
2.
2检索存储过程2135.
2.
3过程和函数的提前说明2145.
2.
4在SQL语句中使用存储函数.
2175.
2.
5将结果存储到表中以及调用存储过程或函数.
2175.
2.
6包2185.
2.
7附加PL/SQL数据类型.
2255.
2.
8设定变量默认值2355.
3PL/SQL编程的高级技术2355.
3.
1在PL/SQL中处理错误.
2355.
3.
2例外部分2365.
3.
3预定义例外2375.
3.
4例外说明241X5.
3.
5成功或失败:查看SQLCODE和SQLERRM2425.
3.
6用RAISE_APPLICATION_ERROR返回错误.
2435.
3.
7使用游标检索数据2435.
3.
8使用游标进行FOR循环.
2525.
3.
9%FOUND、%NOTFOUND和%ROWCOUNT.
2545.
3.
10用数据库触发器执行事物规则.
2565.
3.
11建立触发器2575.
3.
12用触发器对列值进行有效性检验.
2595.
3.
13使用触发器加强安全性2615.
3.
14使用触发器设置列的值2625.
3.
15级联触发器2635.
3.
16在触发器中不能使用COMMIT和ROLLBACK.
2655.
3.
17从触发器中调用存储过程2655.
3.
18对触发器的删除、启用和废止.
2675.
4小结267第6章Oracle与C语言接口——Pro*C.
2716.
1Pro*C概述2716.
2Pro*C程序基本结构2716.
2.
1一个简单的Pro*C程序2716.
2.
2Pro*C程序的基本结构2726.
3Pro*C中的SQL语言.
2736.
3.
1简单查询语句2736.
3.
2数据操纵语句2736.
3.
3使用游标的查询语句2736.
3.
4使用指示变量2746.
3.
5使用嵌入的PL/SQL块.
2766.
3.
6Pro*C中的出错处理2766.
4编译运行Pro*C程序步骤2776.
4.
1预编译选项2786.
4.
2在各种操作系统下运行Pro*C程序步骤2806.
5小结281第7章Oracle8组件和对象2837.
1Oracle进程.
2837.
1.
1Oracle进程.
2837.
1.
2Oracle主进程.
2837.
1.
3选项进程2877.
2Oracle内存.
2907.
2.
1在Oracle8使用内存.
2907.
2.
2系统全局区(SGA)2917.
2.
3程序全局区(PGA)294XI7.
2.
4用户工作空间2957.
3Oracle文件.
2967.
3.
1Oracle文件和它们的用途.
2977.
3.
2数据文件2987.
3.
3日志文件3007.
3.
4控制文件3027.
3.
5初始化和配置文件3027.
3.
6日志和跟踪文件3047.
3.
7文件大小的自动调整3057.
3.
8数据分布优化3057.
3.
9标准文件位置3067.
4Oracle数据对象.
3077.
4.
1Oracle8数据库对象.
3077.
4.
2表3087.
4.
3索引3107.
4.
4视图3127.
4.
5同义词3137.
4.
6存储过程和包3147.
4.
7聚簇3147.
4.
8序列3147.
4.
9表空间3157.
4.
10分区3177.
4.
11对象数据类型3177.
4.
12约束3187.
5小结319第8章用SQL*Report开发报表.
3238.
1概述3238.
1.
1SQL*Report的组成.
3238.
1.
2SQL*Report是怎样工作的3238.
2报表正文格式化程序——RPF3248.
2.
1RPF的特点说明3248.
2.
2RPF句法3248.
2.
3RPF命令介绍3258.
2.
4RPF的特殊情况处理3298.
2.
5RPF的使用3308.
2.
6RPF使用举例3318.
3报表生成程序RPT.
3318.
3.
1关于RPT的说明.
3328.
3.
2RPT语句解释.
3328.
4小结342XII第9章数据库的安全性、完整性、并发控制和恢复3449.
1数据库的安全性3449.
1.
1数据库的存取控制3459.
1.
2特权和角色3479.
1.
3审计3499.
2数据完整性3499.
2.
1完整性约束3509.
2.
2数据库触发器3519.
3并发控制3529.
3.
1数据库不一致的类型3529.
3.
2封锁3539.
3.
3Oracle多种一致性模型.
3539.
3.
4封锁机制3539.
3.
5手工的数据封锁3559.
4数据库备份和恢复3569.
4.
1数据库恢复所使用的结构3569.
4.
2在线日志3569.
4.
3归档日志3589.
4.
4数据库备份3599.
4.
5数据库恢复3599.
5小结361第1章数据库的基本知识1.
1数据库技术1.
1.
1了解数据库数据库技术是研究数据库的结构、存储、设计和使用的一门软件科学,是进行数据管理和处理的技术.
随着计算机应用的普及,数据库应用领域不断向纵横两个方向扩展.
现在,企事业、交通运输、情报检索、金融等各行业,纷纷建立以数据库为核心的信息系统.
人们在实际应用中向数据库技术提出更新、更高的要求,推动着数据库技术不断向前发展.
数据库在当今信息管理和处理中的重要作用越来越明显.
从某种意义上来讲,数据库建设的规模,数据库信息的质量和数量,数据库的使用程度,是衡量一个国家信息化程度的标志.
在过去的许多年里,有许多关于"数据库"这个名词的定义.
数据库是一个服务于一个核心目标的数据的有组织的集合.
数据库中的数据是有组织的,从某种意义上来说,数据库中存储的数据采用一种不变的方式被存储、格式化、存取以及显示.
因为数据库不含有无关的或者冗余的数据,它可以适用于一个核心目标.
一本电话簿就是一个很好的数据库例子,它包含有关的数据(名字),让人们能够查找电话号码;它不包含无关的数据,如某人的电话机的颜色;它只储存那些与它的目标相关的信息.
最常见的,一个数据库的目标是商务应用,但是也可能储存科学、军事或者其他数据,这些数据通常不能当作商务数据看待.
因此,有商业数据库、科学数据库、军事数据库以及其他的数据库等等.
另外,数据不仅能根据它的应用分类,还能根据它的格式分类,现代数据库包括多种类型的数据.
例如,现在数据库储存图像、图表、声音、视频或者包括两种或多种类型的复合文档,已经是很普通的事了.
当讨论数据库特别是数据库设计时,通常称数据库所服务的核心目标为它的业务(business),而不管它属于什么特殊的领域,如太空、生物医学或其他.
此外,在实际生活中,你会发现数据通常有它明确的业务应用.
在早些年,编写程序实现自动数据处理(AutomaticDataProcessing,ADP)要求的程序员发现,在每次运行中,他们需要频繁地存取数据,这就是通常所说的对永久内存的需要,即从程序的一次运行到下一次运行时,需要将数据存留或储存.
这个基本的需要成为数据库发展的开端.
其次的需要——简单的数据存储,也促进了数据库的产生.
在线归档和历史数据就是2Oracle8i数据库开发与专业应用一对特别的例子.
尽管文件、目录和文件系统能满足多数普通的数据存储需要(包括索引变化),但数据库可以做文件系统所能做的工作,并且还可做更多的工作.
现代数据库通常为上级组织或者企业的部门,或者它们的小型组织单位实现存储处理需求.
因此,用术语"企业范围(enterprisewide)"来代表整个组织的商务范围,用"部门范围(departmentwide)"来代表一个部门级的范围,用"工作组(workgroup)"代表一个部门内的一些单位.
通常,在部门范围和工作组级上查找数据库.
偶尔,你会查找服务于企业范围的数据库,例如工资单和人事数据库,但是他们在数量上远远少于那些较小的数据库.
实际上,当几个部门的数据库放在一起或合并成为一个大数据库时,这就是建立一个数据库(DataWarehouse,DW)的本质.
那些充当大型数据库的数据源的小型数据库,称为可操作数据库.
然而,这不是新东西,一个操作数据库就是产生数据的数据库,多年来一直被叫做成品数据库;只有在建立数据仓库的前提下,你才会发现成品数据库是指可操作数据库或者有时是指可操作的数据存储.
随着因特网技术的出现,数据库和数据仓库现在常常作为前端Web浏览器的后端使用.
当工作组数据库合并起来以满足一个大型部门需要时,结果通常相当于一个数据中心(DataMart,DW),一个DW就是一个部门规模的数据仓库.
和术语"数据库"那样,术语"数据仓库"也会有多种定义.
然而,当你把几个小型数据库集成为一个大型数据库,为一个较广泛的组织服务时,如果该数据库存储历史数据、提供决策支持、提供数据汇总、提供只读数据,并且实质上充当所有向它提供数据的相关成品数据库的数据接收器,那么它通常被看作是一个数据仓库.
另外,如果一个数据库增大的原因是因为该数据库是一个长时期储存数据的历史数据库(例如一个人口普查数据库),或者因为它必须储存数据的类型(例如一个卫星遥测数据库),那么它通常被称为一个非常大的数据库(VeryLargeDatabase,VLDB).
随着时间的发展,由于磁盘容量的增大和价钱的下降、均衡多处理技术机器的出现、冗余廉价磁盘阵列(RedundantArrayofInexpensiveDisks,RAID)技术的发展、数据库软件的增多或规模化,判定一个数据库是否为VLDB的条件不断变化.
当前,一个常用的准则是任何100GB或100GB以上的数据库就可以被看作是一个VLDB;而就在几年前,10GB就被看作是分割点了.
1.
1.
2信息、数据、信息处理归纳起来,信息、数据、信息与数据的联系,可以这样来定义:1.
信息(Ioformation)信息是指现实世界事物的存在方式或者运动状态的反应.
信息具有可感知、可存储、可加工、可传递和可再生等自然属性,信息也是社会上各行各业不可缺少的资源,这是它的社会属性.
2.
数据(Data)数据是指用物理符号记录下来的可以鉴别的信息.
数据在形式上可以表现为数字、文字、图像或其他特殊符号.
3.
信息与数据的关系数据是信息的符号表示,或称载体;信息是数据的内涵.
信息与数据是密切相关的.
第1章数据库的基本知识3因此,在某些不需要严格分辨的场合,可以把两者不加区分地使用,例如信息处理也可以说成数据处理.
例如:700~1000某校每年学生入学人数数据信息4.
信息处理的基本环节人们将原始信息表示成数据,然后对这些数据进行汇集、存储、综合、推导,从这些原始、杂乱、难以理解的数据中抽去或推导出新的数据,这些结果对某些特定的人们来说是有价值的、有意义的,它表示了新的信息,可以作为决策或推导的依据.
这一过程通常称为数据处理或信息处理,其处理活动的基本环节如图1-1所示.
图1-1信息处理基本环节众所周知,信息是有价值的,信息的价值与它的准确性、及时性、完整性和可靠性有关.
因为信息的价值必须通过使用信息的决策者的行为结果来实现,所以,为了提高信息的价值,就要用科学的方法来管理信息,这种科学的方法就是数据库技术.
1.
1.
3数据库管理技术的发展数据库管理技术是指对数据进行分类、组织、编码、存储、检索和维护的技术.
数据管理技术的发展是和计算机技术及其应用的发展联系在一起的,经历了由低级到高级的发展过程.
这一过程大致可分为四个阶段:人工管理阶段;文件系统阶段;数据库系统阶段;高级数据库技术阶段.
1.
人工管理阶段人工管理阶段是指20世纪50年代中期以前的阶段.
当时计算机处于发展的初期,计算机主要用于科学计算,所用的数据并不多,而且数据的结构一般都比较简单,计算机系统本身的功能还很弱,没有大容量的外存和操作系统,程序的运行由简单的管理程序来控制.
这一阶段的特点如图1-2所示,可概括为:(1)数据不能长期保存在计算机中;(2)数据作为程序的组成部分不能独立存在,即数据和程序完全结合成一个不可分割的整体;4Oracle8i数据库开发与专业应用(3)数据由程序员在程序中进行管理,无专门的软件对数据进行管理;(4)数据面向应用,不同应用的数据之间相互独立、彼此无关,即便两个不同应用涉及到相同的数据,也必须各自定义,无法互相参照和使用;(5)数据大量冗余(Redundancy).
图1-2人工管理阶段2.
文件系统阶段文件系统阶段是从20世纪50年代后期到60年代中期这一阶段.
在这一阶段,由于计算机技术的发展,出现了磁带、磁鼓和磁盘等较大容量的存储设备,软件方面有了操作系统,计算机的应用范围也由科学计算领域扩展到数据处理领域.
如图1-3所示,这一阶段的特点是:图1-3文件系统管理阶段(1)数据可以以操作系统的文件形式长期保存在计算机中,文件的组织方式由顺序文件逐步发展到随机文件;(2)操作系统的文件管理系统提供了对数据的输入和输出操作接口,进而提供数据存取方法;(3)一个应用程序可以使用多个文件,一个文件可以为多个应用程序使用,数据可以共享;(4)数据仍然是面向应用的,文件之间彼此孤立,不能反映数据之间的联系,因而仍存在数据的大量冗余和不一致性(Inconsistency).
3.
数据库系统阶段数据库系统阶段从20世纪60年代后期开始.
随着计算机硬件和软件技术的发展,开展了对数据组织方法的研究,并开发了对数据进行统一管理和控制的数据库管理系统,在计算机科学领域中逐步形成了数据库技术这一独立分支.
数据管理中数据的定义、操作及控制统一由数据库管理系统来完成.
图1-4说明了这一阶段的特点.
第1章数据库的基本知识5(1)采用一定的数据模型来组织数据,数据不再面向应用,而是面向系统.
(2)程序独立于数据,实现了数据的独立性.
(3)数据的冗余度明显减少,从而减少了数据的不一致性.
(4)为用户的数据操作提供了方便的用户接口,实现了数据共享.
(5)提供了下列数据控制功能:数据的完整性(数据的正确性和一致性);数据的安全性(数据的安全和保密,以防被盗窃和失密);数据的并发控制(实现数据共享,防止相互干扰和恶意破坏);数据库的恢复(发生数据损坏时尽可能恢复到一致状态).
图1-4数据库阶段4.
高级数据库技术阶段高级数据库技术阶段大约从20世纪70年代后期开始.
在这一阶段中,计算机技术获得更快的发展,并更加广泛地与其他科学技术相互结合和相互渗透,在数据库领域中诞生了很多高新技术,并产生了许多新型数据库,其中有些已经成熟并进入了实用阶段.
(1)分布式数据库分布式数据库是数据库技术和计算机网络相互渗透和有机结合的产物.
分布式数据库是由一组数据组成,这些数据物理上分布在计算机网络的不同结点上(结点也称为场地),既能完成本地的局部应用,又参与设计多个场地的全局应用.
即这些分布的数据逻辑上属于同一个整体.
分布式数据库的这个定义强调了数据与处理的分布性、各场地的自治性和数据的逻辑整体性.
分布性是指数据不是存储在一台计算机的存储设备中,从而和集中式数据库相区别.
自治性是指各个场地相互独立,完成本地应用,并无主次之分.
逻辑性是指在逻辑上与集中式数据相同,数据是一个整体,而不是分散在计算机网络不同结点上的各自逻辑独立的数据库(或文件系统),如图1-5所示.
分布式数据库的重要特性是数据分布的透明性,分布式数据库是一个统一整体.
用户不必关心数据的逻辑分布,更不必关心数据的物理分布的细节.
对用户来说,访问分布式数据库如同访问集中式数据库一样,只要指出访问哪些数据,而不需要指出到哪里或如何访问这些数据.
(2)面向对象数据库20世纪60年代末期,在程序设计语言中引入了面向对象的概念.
通过面向对象的程6Oracle8i数据库开发与专业应用图1-5分布式数据库系统示意图序设计来解决程序的重用问题.
将面向对象的概念引入数据库领域,产生了面向对象数据库系统.
面向对象技术最重要的进展是,数据和数据操作的方法作为对象由面向对象的数据库管理系统来统一管理,任何被开发的应用都成为对象目标库的一部分,由开发者和用户所共享.
共享缩小了数据库和应用程序的差距,降低了应用程序的开发费用,同时也减少了系统出现问题的可能性.
同时,面向对象技术中所用的方法能精确处理现实世界中复杂的目标对象.
例如,图像、声音、文本文件等,都可以被定义为抽象数据类型,而且在系统运行时对它们的内容进行检查.
在面向对象技术中,属性的继承性使得可以在对象中共享数据和操作,对象之间的通信成为数据和程序间交换信息的标准.
面向对象的数据库技术已经可以处理复杂的企业范围内变化的事物对象.
1.
2数据模型模型是抽象地模仿现实世界的事物,在数据库技术中,使用数据模型(DataModel)的概念描述数据库的结构和语义.
根据应用的不同,数据模型可分为两类或两个层次:(1)概念数据模型:只描述信息特性和强调语义,而不涉及信息在计算机中的表示,是现实世界到信息世界的第一层抽象.
最常用的是实体联系模型(EtinityRelationModel).
(2)数据结构模型:直接描述数据库中数据的逻辑结构,这类模型涉及到计算机系统,通讯网络第1章数据库的基本知识7又称为基本数据模型.
它是用于机器世界的第二层抽象,通常包括一组严格定义的形式化语言,用来定义和操纵数据库中的数据.
最常用的有:层次模型(HierarchicalModel);网状模型(NetworkModel);关系模型(RelationalModel);面向对象模型(Object-OrientedModel).
1.
实体联系模型(EtinityRelationModel)实体联系模型(简记为E-R模型)是P.
P.
Chen于1971年提出的.
E-R模型中的基本语义单位是实体与联系,它可以形象地用图形表示,称为E-R图.
E-R图是直观表示概念模型的有力工具.
在E-R图中,以矩形框表示实体类型(考虑问题的对象),用菱形框表示联系类型(实体间的联系),用椭圆形框表示实体类型和联系类型的属性,相应的名字均记入框中.
联系类型与其涉及的实体类型之间以直线连接,并在直线端部标注联系的种类,如:1:1表示1对1的联系;n:n表示1对多的联系;m:m表示多对多的联系.
下面通过例子来说明E-R模型.
例1-1:为仓库管理设计一个E-R模型.
仓库主要管理零件的进库、出库、采购等事项.
仓库根据需要向外面厂家购买零件,而许多工程项目需要仓库供应零件.
这个E-R模型如图1-6所示.
图1-6E-R图示例联系类型也可以发生在多于两个实体类型之间.
如上例中,如果规定某个工程项目是指定需要某个厂家的零件,那么E-R图如图1-7所示.
图1-7三个实体类型之间的联系M8Oracle8i数据库开发与专业应用需要注意的是,在E-R图中,联系类型的属性中可以不包括与它相关的实体的键,当将E-R图转化为逻辑模型时再将它给出.
E-R模型有两个明显的优点:(1)接近人的思想,容易理解;(2)与计算机无关,用户容易接受,因此E-R模型已成为数据库概念设计的一个重要的设计方法.
2.
网状模型(NetworkModel)用网状结构表示实体类型及实体之间联系的数据模型称为网状模型.
网状模型是美国DASYL委员会数据库任务组(DBTG)于1969年提出的一种模型,用于设计网状数据库.
在网状模型中,一个子结点可以有多个父结点,在两个结点之间可以有一种或多种联系,如图1-8所示.
图1-8网状模型示例网状模型有许多成功的数据库管理系统,它们在20世纪70年代和80年代得到了广泛的应用.
网状模型实现实体间m:n联系比较容易.
记录之间联系是通过指针实现的,因此数据的联系十分密切.
网状模型的数据结构在物理上也易于实现,效率较高,但是应用程序的编写较复杂,程序员必须熟悉数据库的逻辑结构.
在网状模型中,任意两个记录类型之间都可以组成一个系类型结构.
因此以记录类型为结点的结构图是网络结构.
从E-R图到网络模型的转换规则主要有两条:(1)把E-R图的实体类型和联系类型全部转换成相应的记录类型;(2)把E-R图中实体类型与有联系的每个联系类型,分别组成一个系类别.
3.
层次模型(HierarchicalModel)用树型(层次)结构表示实体类型以及实体间的联系是层次模型的主要特征,如图1-9所示.
层次结构是一棵有向树,树的结点是记录类型,根结点只有一个,根结点以外的结点有且只有一个父结点.
上一层记录类型和下一层记录类型间的联系是1:n联系(包括1:1联系).
第1章数据库的基本知识91969年,IBM公司推出IMS系统,它是最典型的层次模型系统,曾在20世纪70年代商业中广泛应用.
图1-9层次模型示例4.
关系模型(RelationalModel)用二维表格形式结构表示实体类型以及实体间联系的模型称为关系模型.
关系模型比较简单,容易被初学者接受.
关系在用户看来是一个二维表格,记录是表中的行,属性是表中的列.
例1-1的E-R图可以转换成如图1-10所示的关系模型.
图1-10关系模型示例关系模型和网状、层次模型的最大区别是:(1)关系模型用表格数据而不是通过指针来表示和实体间联系.
(2)关系模型的数据结构简单、易懂,只需要简单的查询语句就可对数据库进行操作.
关系模型是数学化的模型,可把表格看成一个集合,因此集合论等知识可引入到关系模型中来.
关系模型已是一个成熟的有前途的模型,已得到广泛的应用.
5.
面向对象模型(Object-OrientedModel)由于关系模型比网状、层次模型更为简单灵活,因此在数据处理领域中,关系数据库的使用已相当普遍.
但是,现实世界存在着许多含有更复杂数据结构的实际应用领域,例如CAD数据、图形数据等,需要有一种数据模型来表达这类信息.
随后,在人工智能研究中也出现了类似的需要,这种数据模型就是面向对象数据模型.
10Oracle8i数据库开发与专业应用面向对象数据模型的新概念有以下几点:(1)对象和对象标识(OID):对象是现实世界中实体的模型化,与记录、属性的概念相似,但远比它们复杂.
每一个对象都有一个唯一的标识,称为对象标识(OID).
对象标识OID不等于关系模式中的记录标识RID或属性标识TID.
OID是独立的,全系统唯一.
(2)封装(Encapsulate):每一个对象是状态(State)和行为(Behavior)的封装.
对象的状态是该对象属性的集合.
对象的行为是在该对象状态上操作的方法(程序代码)的集合.
被封装的状态和行为在对象外部是看不见的,只能通过现实定义的消息传递来访问.
如图1-11所示.
图1-11对象示意图(3)对象的属性(ObjectAttribute):对象的某个属性可以是单值或值的集合.
对象的一个属性值本身在该属性看来也是一个对象.
(4)类和类层次类:所有具有相同属性和方法集的对象构成了一个对象类.
任何一个对象都是某个对象类的一个实例(Instance).
对象类中属性的定义域可以是任何类,包括:基本类:整型,实型,字串等;一般类:包含自身属性和方法类本身.
例如,"所有文件"构成文件类,文件类中的每个文件是对象,如图1-12所示.
图1-12类层次示意图类层次:所有的类组成了一个有根有向无环图,称为类层次(结构).
一个类可以从直接或间接祖先(超类)中继承(Inherit)所有的属性和方法,该类称为子类.
(5)继承(Inherit):子类可以从超类中继承所有属性和方法.
类继承可分为单继承和多重继承两种.
第1章数据库的基本知识11单继承——一个类只能有一个超类;多重继承——一个类可以有多个超类.
这样,在已有类的基础上定义新的类时,可以定义特殊的属性和方法,而不必重复定义父类已有的东西,这有利于实现可扩充性(Extensibility).
例1-1中的E-R图,可以设计成如图1-13所示的面向对象模型.
图1-13面向对象模型的示例这个面向对象模型中有五个类,分别是:P-P,P-S,PROJECT,PART,SUPPLIER,其中类P-P的属性J#取值为类PROJECT中的对象属性,P#取值为类PART中的对象属性,类P-S中的属性P#取值为类PART中的对象,属性S#值为类SUPPLIER的对象,这就充分表达了图1-6中的E-R图的全部语义.
面向对象数据模型比网络、层次、关系数据模型更具有丰富的表达能力.
但正因为面向对象模型的丰富表达能力,模型相对复杂,实现起来较困难,所以尽管面向对象系统很多,但大多是试验型的或专用的,尚未通用化.
1.
3数据库管理系统数据库管理系统(DatabaseManagementSystem,DBMS)就是管理一个数据库的软件,它充当所有数据的知识库,并对它的存储、安全、一致性、并发操作、恢复和访问负责.
DBMS有一个数据词典(有时被称为系统目录)其中储存着它拥有的每个事物的数据,例如名字、结构、位置和类型,这种关于数据的数据也被称为元数据(metadata).
在一条数据的生存周期里(从它的创建到删除),这条数据的逻辑和物理信息都被记录在数据词典中.
数据库系统管理员(DatabaseAdministrator,DBA)应该熟悉DBMS的数据词典;在数据库的整个生命周期内,数据词典为他服务.
数据库管理系统是基于某种数据结构模型、以统一的方式管理和维护数据库,并提供访问数据库接口的通用软件.
DBMS一般具有以下功能:(1)数据库定义功能,提供DataDefinedLanguage(DDL)及其翻译程序,定义数据库结构(模式及模式间映像)、数据完整性和保密性约束等.
12Oracle8i数据库开发与专业应用(2)数据库操纵功能,提供DataManipulateLanguage(DML)及其翻译程序,实现对数据库数据的查询、插入、更新和删除操作.
(3)数据库运行和控制功能,包括数据安全性控制、数据完整性控制、多用户环境的并发控制等.
(4)数据库维护功能,包括数据库数据的载入、转储和恢复,数据库的维护和数据库的功能及性能分析和监测等.
(5)数据字典(DataDictionary,DD),存放数据库各级模式结构的描述,是访问数据库的接口.
在大型系统中,DD也可单独成为一个系统.
(6)数据通信功能,包括与OS的联机处理、分时处理和远程作业传输的响应接口等,这一功能对分布式数据库系统尤为重要.
1.
3.
1数据的安全数据库安全管理的基本功能是保护数据库和其内容免受非法暴露、更新或破坏.
除此之外,安全还有许多其他功能.
安全有法律、社会和伦理方面的考虑,它关系到某人访问信息的权限以及让其他人知道这些权限.
在成品数据库中,安全性一直是一个重点,在开发或者测试数据库中也常如此.
这通常不是有没有安全性的问题,而是有多大安全性的问题.
除了操作系统和网络安全设施外,一个DBMS通常提供几层安全设施.
最常见的情形是,DBMS要求用户登录用户账号的口令,口令被验证为真,才能访问数据库.
DBMS也提供其他的机制,例如组、角色、权限,这些都是提供更加精良的安全措施.
提供这些安全级不是为了加强安全性,而是为了建立商业安全策略.
例如,只有一个经过验证属于航空组的用户才能存取航空数据;又例如,只有经过验证拥有操作者角色的用户才能备份数据库.
1.
标识和鉴别无论是银行、办公室、家、计算机系统,还是数据库系统,安全系统中的初级防卫是在入口点.
入口点的控制至少应与前面所列的这些系统差不多.
例如,你从银行取钱之前,你必须先提供身份识别表明你在那里有账户.
然后,你要从指定账户取钱时,银行通常还要进一步鉴别你的身份.
数据库系统或计算机系统没有区别.
在允许某人进入系统前,用户必须首先让系统知道他是谁.
然后,系统可根据授权用户的列表,并指示是否允许其进入.
这是第一级的防卫:用户名的识别.
第二级的防卫判断用户是否就是他或她声明的人.
此鉴别可采用多种形式.
在最简单的形式中,系统可能还需要一个只让系统和用户知道的口令.
在较复杂的形式中,鉴别可能包括眼睛的视网膜扫描、指纹、密码卡输入、语音识别或一些其他的复杂识别形式.
我们可将鉴别的策略和机制扩充到较低数据库,作为这两个手段的次要用法.
我们可将访问入口与文件、对象、关系、操作或数据库系统的其他成分结合起来.
要折衷考虑此类系统的构造开销、维护开销和全部开销造成的性能损失.
2.
授权一旦允许某个用户进入系统,我们要不要限制他访问系统在你的主机中,如果有人可进入并浏览你的e-mail或新产品的方案,你肯定不愿意.
你可能希望进一步对用户加以第1章数据库的基本知识13限制,从而使他们只能看到和使用那些你认为合适他们访问的数据.
授权是限制某个用户在系统内的视图和操作的方法.
授权策略和机制用于决定和设置访问级别、访问粒度和被允许访问的关系.
授权机制包括各种访问的能力,类似指定座位和访问质量的许可证,或者说该机制是表的访问控制表,他们表示数据库成分或数据库用户,以及它们对数据项的访问和执行的权限.
访问限制级别的范围可从不能访问到访问和操作不受限制.
常见的权限介于两者之间.
系统可能给一些用户只读权限,而限制其他一些用户读访问.
一些用户可能只是生成数据,却没有理由查看内部数据,因而只有写访问权限.
一些用户可能获得某个数据项或区域的读和写权限,而其他人可能获得特殊的操作权限.
授权机制必须提供用户得到何种数据库视图及其内容.
我们可能希望让一些用户看到一个关系或对象的部分视图而非全部,或只限制访问数据库的一个子集.
实现此功能的典型方法是通过一个视图机制,它只让某个用户了解数据库的特定子类型或子成分.
最后,即使有了这些限制,数据库安全子系统还必须与真正的破坏分子打交道,这些人企图通过非法手段获得有关数据库的信息.
控制这种类型的访问必须考虑访问的关联和访问的持续时间和范围,还应包括一组推断规则,通过这些规则的检查,可以设法监测某个人企图破坏数据库的隐秘手段.
要抵制这类人,数据库可能需要对信息加以限制.
例如,数据库可能给破坏分子发送错误或不完全数据,以便隐藏保密数据.
出于安全考虑,要严格管理一个数据项的多个变量,这很复杂.
安全系统可能需要用多种方法查看合作信息,以便限制和监测某人何时企图用非密信息可能推导出受限或保密信息.
最后,我们讨论一下浏览的额外开销.
对真正的用户而言,浏览是一个重要特性,而对安全侵犯者而言是一个强大工具.
浏览器能查看不超过她或他许可的安全级别的各种数据,可能收集足够的无关信息演绎出一些重要信息.
例如,如果你想要知道何时在五角大楼中有大事发生,只需要查看比萨饼的分送信息.
如果在短时期内和一日内各钟点的比萨饼数量大有增长,说明有一项大行动正在密谋或计划中.
安全是数据库领域内的重要问题,虽然其使用和实现要折衷考虑限制访问的需求和限制访问有关的开销.
开销可能是一次性的,涉及数据库的初始构造和生成,或者以后可能还有开销.
以后的开销来自权限的在线检查和测试访问中可能隐藏的工作.
1.
3.
2维护和实施完整性数据的完整性是指它的一致性和正确性.
对于一致的数据,在它所有的出现的场合中,必须以相同的方式建模和实现,对于正确的数据,它必须是正确、精确和有意义的.
DBMS维护完整性的一个方法是在一条数据项发生改变的过程中进行锁定.
数据库通常是在数据库页级或行级锁定数据.
锁定偶尔也允许并发操作,在下面你将涉及到这种情形.
DBMS实施完整性的另一个方法是:如果一条数据储存在多个地方,那么把变化复制到这条数据上.
DBMS实施完整性的最后一个方法是通过监视输入的或改变的数据值,使他们全部符合要求的规格(例如:一个范围检查).
如果接着的是合适的建模和实现过程,DBMS会自动地帮助实施这种完整性,例如,14Oracle8i数据库开发与专业应用通过一个触发器或者约束条件.
没有完整性,数据是没有价值的.
有了完整性,数据就是信息.
完整性不仅能增强数据,它还给予数据以价值.
当DBMS提供多用户存取时,它必须管理并发操作.
那就是说,当几个人同时访问相同的数据库(特别是同一条数据)时,DBMS必须保证这种并发访问能够以某种形式实现.
并发可以广义上定义为同时发生,即两个或者多个用户在同一时期访问同一数据.
DBMS实现并发操作的方法倒不太复杂,但背后的实际程序却很复杂.
本质上说,当两个或者多个人只想简单地浏览一下同一个数据而不改变它时,一切还好.
但当至少一个人想改变数据而其他人想浏览或者也想改变数据时,DBMS必须储存多个备份.
当每个人都完成改动后,DBMS必须将所有改变的备份保存为一条正确的数据.
前面已经提到并发管理的一种方式是加锁.
通常来讲,锁越精密(越小),并发性就越好(那就是说,更多的用户无需等待即可同时访问).
行通常比较小的数据库页或块都小,因此,行级锁可较好地管理短小、杂乱数据的处理,块级锁可较好地管理长的、连续数据的处理.
这就是并发性和完整性是如何结合的.
当一个人想查看或者更改一条数据时,这个人就是执行数据库的一个事务.
1.
3.
3理解事务作为DBMS标准的一部分,DBMS有一个事务管理器(transactionmanager),它的目的是管理并发操作和确保事务的完整性.
事务管理器的工作是艰巨的,因为它必须允许许多人同时访问相同的数据,并且在访问之后要把数据放回到数据库中,就好像是某个时间上只有一个人存取数据,他完成工作后另一个人才开始工作,这样确保数据的正确性.
DBMS解决数据的多个备份的基本方案就在这中间.
如果(并且是只有)数据是串行的,那么在保持数据的准确性的同时也进行了事务处理.
简单地说,DBMS必须重新整理所有改变,以使得它们的最终结果仿佛发生在一个文件中.
事务是并发或工作的单位.
不能产生比一个事务更小或更少的东西,也就是说,没有人能够只完成数据改变的一部分.
全部事务必须都是原子的,所以每个单独的事物要么完成,要么不完成.
直到20世纪现代物理发展起来以前,原子一直被当作物质的最小单位.
同样,事务也是并发的最小单位,它要么全有,要么全无.
一个被完成的事物可以说是被提交了,没有完成的事物则是被回滚了.
DBMS用事务作为恢复的单位来控制恢复,正常完成、手工要求中止以及意料之外的退出都要求DBMS重新访问数据的多个备份来提交或回滚数据.
为了回滚或者前滚,DBMS保持了一个事务日志.
回滚是一个撤销操作,前滚是一个重做操作,例如,由于一个硬件或者软件错误,一个已提交的事物无法将它的操作从内存中存储到磁盘就会发生前滚,DBMS只是简单地重做这个操作.
因此,在DBMS中事务恢复的关键是一个事务必须是原子的,而且在必要时可以做、不做或重做.
1.
3.
4数据独立性1.
数据库的体系结构数据库系统的体系结构是数据库系统的一个重要总框架.
尽管数据库软件产品种类繁多,使用的数据库语言各异,基础操作系统不同,采用的数据结构模型相差甚大,但是绝第1章数据库的基本知识15大多数数据库系统在总体结构上都具有三级模式的结构特征.
数据库的三级模式结构有外模式、模式和内模式组成,如图1-14所示.
(1)外模式:又称子模式或用户模式,是模式的子集,是数据的局部逻辑结构,也是数据库用户看到的数据视图.
(2)模式:又称逻辑模式或概念模式,是数据库中全体数据的全局逻辑结构和特性的描述,也是所有用户的公共数据视图.
(3)内模式:又称存储模式,是数据在数据库系统中的内部表示,即数据的物理结构和存储方式的描述.
图1-14数据库系统的体系结构2.
数据独立性数据库系统的三级模式是对数据的三级抽象,数据的具体组织由数据库管理系统负责,使用户能逻辑地处理数据,而不必考虑数据在计算机中的表示和存储方法.
为了实现三个抽象层次的转换,数据库系统在三级模式中提供了两次映像:外模式/模式映像和模式/内模式映像.
所谓映像就是存在某种对应关系.
外模式到模式的映像,定义了外模式与模式之间的对应关系.
模式到内模式的映像,定义了数据的逻辑结构和物理结构之间的对应关系.
由于上述的两次映像,使数据库管理中的数据具有两个层次的独立性.
一个是数据物理独立性.
模式和内模式之间的映像是数据的全局逻辑结构和数据的存储结构之间的映像,当数据库的存储结构发生了改变,例如存储数据库的硬件设备变化或存储方法变化,引起内模式发生变化.
由于模式和内模式之间的映像,是数据的结构可以16Oracle8i数据库开发与专业应用保持不变,因此应用程序可以不必修改.
另一个是数据的逻辑独立性,外模式和模式之间的映像是数据的全局逻辑结构和数据的局部逻辑结构之间的映像.
例如,数据管理的范围扩大或某些管理的要求发生改变后,数据的全局逻辑结构发生变化,对不受该全局变化映像的那些局部而言,至多改变外模式与模式之间的映像,基于这些局部逻辑结构所开发的应用程序就不必修改.
数据的独立性是数据库系统的最重要的特征之一,采用数据库技术使得应用程序的维护工作量大大减轻.
1.
3.
5与数据库通信如果你不能和一个DBMS对话,那么这个DBMS就不是很好的.
你可能会问怎样和DBMS对话,可以通过一种存取或查询语言访问数据库.
结构化查询语言(StructureQueryLanguage,SQL)是当今主要的查询语言,它主要用于管理主流类型的DBMS——关系型DBMS(RDBMS).
所有与数据库相关的通信往来都是通过DBMS完成的,为了做这件事,你可以使用SQL或者其他类似的东西.
数据库系统管理员(DBA)使用查询语言来建立并维护数据库,用户使用查询语言来访问数据库并查看或者更改数据库.
1.
4关系数据库管理系统1970年,E.
F.
Codd创立了关系模式概念.
在RDBMS(例如DB2)产生之前,层次(IMS)和网状(IDMS)模式是常见的.
在这些模式之前,使用平面文件(操作系统文件不一定平面)来建立数据库,并且使用第三代语言(3GL)访问例程.
实际上,一些专用系统仍然是按这种方式建立的,只是进行了修改或根本没有变化.
在大型机和微机中依然存在着许多这样的遗留数据库.
CODASYL(数据系统语言协会)是数据库任务组(DatabaseTaskGroup,DBTG)创建的一种数据库标准,这是一种基于COBOL的网络数据库标准,并且IDMS是一个厂商的实现.
但是,从70年代起,RDBMS已经逐渐地控制了市场,如Oracle、Sybase、Informix和Ingres.
最近,面向对象(Object-Oriented,OO)的DBMS已经成为最为突出的数据库管理系统,并找到了许多适当的应用环境,如CAD/CAM、工程、多媒体等等.
面向对象的DBMS适于在这些领域中应用,因为在一个几乎非事务性的环境中,它们具有控制复型数据类型实力.
由于竞争,RDBMS厂商为了提供包括文本、音频、图像和视频数据类型的面向对象/多媒体性能,已经制造了商业可用的通用服务器.
Oracle的UniversalServer就是一个例子.
另外,用户定义的数据类型或可扩展类型,已经被扩大或增加到核心数据库服务器中,Oracle8就提供了这样的性能.
类似这样的RDBMS产品被认为是混合的,然而它们明显比以前的RDBMS更具有主流性.
此外,多维数据库(Multi-DimensionalDatabase,MDD)也分享了部分市场份额,这些数据库为带有许多必须被多维存取或列表的变量(例如行为科学数据)的应用提供了高度索引化的数据.
在传统的RDBMS中,这几乎是不可能实现的,数据只允许单独使用.
再者,为和MDD竞争,RDBMS供应商提供了一些它们自己的层次产品,这些产品提供超级索引化的数据,并使用了特殊的技术,例如位映射索引.
Oracle的Express就是一个多维数第1章数据库的基本知识17据库的例子.
1.
4.
1关系模型你已经了解了DBMS的主要任务,为了进一步了解一个RDBMS是由什么构成的,你必须先了解关系模型.
下列情况出现在一个关系模型中:(1)数据的基础项是关系;(2)在这些表上的操作只产生关系(关系型闭合).
什么是关系这是一个描述两个集合的元素如何相互联系或如何一一对应的数学概念.
因此,关系模型是建立在数学基础上的.
然而,对你来说,关系只是一个带有一些特殊属性的表,一个关系模型把数据组织到表中,而且仅在表中.
客户、数据库设计者、数据库系统管理员和用户都以同样的方式——即从表中查看数据.
那么,表就是关系模型的近义词.
一个关系型表有一组命名的属性(attribute)或列,以及一组元组(tuple)或行.
有时列被称为域,行被称为记录.
表1-1有四行三列.
表1-1汽车表制造模型品牌价格ToyotaCamry$25KHondaAccord$23KFordTaurus$20KVolkswagenPassat$20K一个关系表必须符合某些特定条件,才能成为关系模型的一部分:(1)储存在单元中的数据必须是原子的.
每个单元只能存储一条数据,这也叫信息原则(InformationPrinciple),尽管在过去的数年中按某些违反这一条的方式已经建立了许多系统,但违反这一条将不能运用良好的设计原则.
当一个单元包含多于一条的信息时,这叫做信息编码(informationcoding),一个很好的例子是一个车辆识别号码(VehicleIdentificationNumber,VIN).
如果它被存储成一列,这将违反信息,因为它包含了许多条信息,例如产地、型号、出厂日期等等.
在这样的情况下,是否采用违背理论的方案是一个设计的选择问题,尽管在多数情况下,结果证明这对数据的完整性是不利的.
(2)储存在列下的数据必须具有相同数据类型.
(3)每行是唯一的(没有完全相同的行).
(4)列没有顺序.
(5)行没有顺序.
(6)列有一个唯一性的名称.
除了表和它们的属性,关系模型有它自己的特殊的操作.
不需要深入研究关系性数学,只需说明这些操作可能包括的列的子集、行的子集、表的连接以及其他数学集合操作(如联合)等就够了.
真正要知道的事情是这些操作把表当作输入,而将产生的表作为输出.
SQL是当前RDBMS的ANSI标准语言,它包含这些关系型操作.
在SQL占主导地位之前,一种具有竞争性的语言是来自Ingres的QUEL或QUEry语言,另一种是UDL(统一数据语言,UnifiedDataLanguage).
ANSI(美国国家标准化组织)是一个具有广泛范围的标准18Oracle8i数据库开发与专业应用实体,其中包括计算机语言(如SQL)的标准.
允许数据操作或数据处理的主要语句是SELECT、INSERT、UPDATE和DELETE.
因此,这些数据操作中任何一个都是事务.
允许数据定义或结构化处理的主要语句是CREATE、ALTER和DROP.
所有这些都可以使用一组子句来代替,这些子句可以利用多种变化来定义和存取组成数据关系表的结构和数据.
因此,SQL既是一种数据定义语言(DataDefinitionLanguage,DDL),又是一种数据操作语言(DataManipulationLanguage,DML).
统一的DDL和DML肯定比两种不同的语言和接口更有效、更有用.
数据库系统管理缘何用户可以通过完全相同的语言访问数据库.
关系模型要求的最后一件事是两个基础的完整性原则.
它们是实体完整性原则(entityintegrityrule)和引用完整性原则(referentialintegrityrule).
首先,让我们看看两个定义:(1)主键(primarykey)是能唯一标志行的一列或一组列的集合.
有时,多个列或多组列可以被当作主键.
(2)由多个列构成的主键被称为连接键(concatenatedkey)、组合键(compoundkey),或者通常称为符合键(compositekey).
数据库设计者决定哪些列的组合能够最准确和有效地反映业务情形,这并不意味着其他的数据未被存储,只是那一组列被选做主键而已.
剩余有可能被选为主键的列被叫做候主键(candidatekey)或替代键(alternatekey).
一个外键(foreignkey)是一个表中的一列或一组列,他们在其他表中作为主键而存在.
一个表中的外键被认为是对另外一个表中主键的引用.
实体完整性原则简洁地表明主键不能全部或部分地空缺或为空,引用完整性原则简洁地表明一个外键必须为空或者与它所引用的主键当前的存在的值相一致.
一个RDBMS就是一个建立在前面这些关系模型基础上的,一般能满足所提供的全部要求的DBMS.
但是,在20世纪70年代末到80年代初,RDBMS开始销售的时候,SQL超越了本质为非关系型的系统,受到普遍欢迎,并被称为关系型.
这引发了一些修正活动,即Codd12条法则(1985).
1.
4.
2Codd十二条法则DBMS应该遵循Codd提出的12条法则,才能被分类到完全关系型.
(1)信息法则.
信息表现为储存在单元中的数据,正如前面所讨论过的,将VIN作为一个单个的列使用,违反了这条规则.
(2)授权存取法则.
每一个数据项必须通过一个"表名+行主键+列名"的组合形式访问.
例如,如果你能用数组或指针访问一个列,就违反了这条规则.
(3)必须以一致的方式使用空值.
如果由于缺少数字值,空值(Null)被当作0来处理,或者由于缺少字符值而被当作一个空格处理,那么它就违法了这条规则.
空值仅仅是指缺少数据而且没有任何数值.
如果缺少的数据需要值,软件提供商通常提供缺省值的能力满足这一目的.
(4)一个活跃的、在线数据字典应作为关系型被存储,并且该字典应该可以通过常规的数据存取语言访问.
如果数据字典的任何部分储存在操作系统文件里,就违反了这一规则.
(5)除了可能的低级存取例程外,数据存取语言必须提供所有的存取方式,并且是存第1章数据库的基本知识19取的仅有方式.
如果你能通过一个实用程序而不是一个SQL接口来存取支持一个表的文件,就有可能违反了本规则.
(6)所有能被更新的视图应当是可更新的.
例如,如果你将三个表连接起来,作为一个视图的基础,但却不能更新这个视图,则违反了本规则.
(7)必须有集合级的插入、更新和删除.
目前,大多数RDBMS都在某种程度上提供了这种能力.
(8)物理数据的独立性.
应用不能依赖于物理结构,如果一个支持某表的文件从一张盘移动到其他盘上或重新命名,不应该对应用产生影响.
(9)逻辑数据的独立性.
应用不依赖于逻辑结构,如果一个表必须被分成两个部分,那么应该提供一个视图,把两段连接在一起,以便不会对应用产生影响.
(10)完整性的独立性.
完整性规则应该储存在数据字典中.
主键约束、外键约束、检查约束、触发器等等都应该储存在数据字典中.
(11)分布独立性.
一个数据库即使被分布,也应该能继续工作.
这是规则(8)的一个扩展,一个数据库不仅能在一个系统(本地的)分布,也能在通过系统的网络(远程的)分布.
(12)非破坏性法则.
如果允许低级存取,一定不能绕过安全性或完整性,这些规则是常规的数据存取语言所遵守的,例如,一个备份或载入工具不能绕过验证、约束和锁来备份或载入数据.
然而,软件供应商出于速度的原因,通常提供这些功能.
那么,数据库系统管理员就有责任确保数据的安全性和完整性,如果瞬间出现问题,应该立即恢复.
例如当载入VLDB时,可以临时禁止并重新打开约束检查.
如果一个DBMS能满足本节中所讨论的所有基本原则和这12条法则,那么它就可以被当作一个RDBMS.
Codd用他的法则总结了这一切:"对于一个有资格成为RDBMS的系统来说,该系统必须排它地使用它的关系型工具来管理数据库.
"1.
5小结1.
问:什么是数据库和数据库技术它有哪些种类答:在过去的许多年里,有许多关于"数据库"这个名词的定义.
数据库是一个服务于一个核心目标的数据的有组织的集合.
数据库中的数据是有组织的,从某种意义上来说,数据库中存储的数据采用一种不变的方式被存储、格式化、存取以及显示.
因为数据库不含有无关的或者冗余的数据,它可以适用于一个核心目标.
数据库技术是研究数据库的结构、存储、设计和使用的一门软件科学,是进行数据管理和处理的技术.
有商业数据库、科学数据库、军事数据库以及其他的数据库等等.
另外,数据不仅能根据它的应用分类,还能根据它的格式分类,现代数据库包括多种类型的数据.
例如,现在数据库储存图像、图表、声音、视频或者包括两种或多种类型的复合文档,已经是很普通的事了.
2.
问:数据库管理技术的发展经历了哪些阶段答:数据管理技术的发展是和计算机技术及其应用的发展联系在一起的,经历了由低20Oracle8i数据库开发与专业应用级到高级的发展过程.
这一过程大致可分为四个阶段:人工管理阶段;文件系统阶段;数据库系统阶段;高级数据库技术阶段.
3.
问:数据模型有哪些种类或层次最常用的有哪些答:模型是抽象地模仿现实世界的事物,在数据库技术中,使用数据模型(DataModel)的概念描述数据库的结构和语义.
根据应用的不同,数据模型可分为两类或两个层次:(1)概念数据模型:只描述信息特性和强调语义,而不涉及信息在计算机中的表示,是现实世界到信息世界的第一层抽象.
最常用的的是实体联系模型(EtinityRelationModel).
(2)数据结构模型:直接描述数据库中数据的逻辑结构,这类模型涉及到计算机系统,又称为基本数据模型.
它是用于机器世界的第二层抽象,通常包括一组严格定义的形式化语言,用来定义和操纵数据库中的数据.
最常用的有:层次模型(HierarchicalModel);网状模型(NetworkModel);关系模型(RelationalModel);面向对象模型(Object-OrientedModel).
4.
问:什么是数据库管理系统答:数据库管理系统(DatabaseManagementSystem,DBMS)就是管理一个数据库的软件,它充当所有数据的知识库,并对它的存储、安全、一致性、并发操作、恢复和访问负责.
5.
问:数据安全管理的基本功能是什么可以通过哪些方式实现答:数据库安全管理的基本功能是保护数据库和其内容免受非法暴露、更新或破坏.
除此之外,安全还有许多其他功能.
安全有法律、社会和伦理方面的考虑,它关系到某人访问信息的权限以及让其他人知道这些权限.
除了操作系统和网络安全设施外,一个DBMS通常提供几层安全设施.
最常见的情形是,DBMS要求用户登录用户账号的口令,口令被验证为真,才能访问数据库.
DBMS也提供其他的机制,例如组、角色、权限,这些都是提供更加精良的安全措施.
6.
问:如何判断一个数据库管理系统是否能被当作RDBMS答:如果一个DBMS能满足1.
4.
2节中所讨论的所有基本原则和这12条法则,那么它就可以被当作一个RDBMS.
第2章逻辑数据库的设计与实现2.
1数据库设计原理数据库设计是数据库应用领域中的主要研究课题.
数据库设计的任务是针对一个给定的应用环境,在给定的(或选择的)硬件环境、操作系统及数据库管理系统等软件下,创建一个性能良好的数据库模式,建立数据库及其应用系统,使之能有效地收集、存储、操作和管理数据,满足用户的各类要求.
目前关系型数据库管理系统占有优势地位,本节的内容将围绕关系型数据库展开.
2.
1.
1数据库设计的内容、方法和步骤1.
数据库设计与数据库引用系统设计在数据库领域,常常把使用数据库的各类系统统称为数据库应用系统.
一般用于管理的信息系统可以建立在文件系统之上,也可以建立在数据可管理系统之上,即可以是数据库应用系统,也可以不是数据库应用系统.
数据库应用系统通常是指以数据库为基础的信息系统.
所以严格来说,数据库设计是数据库应用系统设计的一部分.
在实际应用中,这两个概念往往区分不太明确.
2.
数据库设计的内容数据库设计通常是在一个通用的DBMS支持下进行的,即利用现成的DBMS作为开发基础.
具体地说,数据库设计包括结构特性的设计和行为特性的设计两方面的内容.
结构特性设计是指确定数据库的数据模型.
数据库反映了现实世界的数据及数据间的联系,要求满足应用需求的前提下,尽可能减少冗余,实现数据共享.
行为特性的设计是指确定数据库应用的行为和动作,应用的行为体现在应用程序中,所以行为特性的设计主要是应用程序的设计.
数据库设计工作量大,而且过程比较复杂,是一项数据库工程,也是一项庞大的软件工程,数据库设计的各阶段可以和软件工程的各阶段对应起来,软件工程的某些方法和工具同样可以适用于数据库工程.
两者的区别在于:软件工程比较强调行为特性的设计;在数据库工程中,由于数据库模型是一个相对稳定的并为所有用户共享的数据基础,所以数据库工程中更强调对于结构特性的设计,并与行为特性的设计结合起来.
3.
数据库设计方法和步骤为了使数据库设计更合理更有效,需要有效的指导原则,这种指导原则称作数据库设计方法学.
首先,一个好的数据库设计方法学,应该能在合理的期限内,以合理的工作量,产生一个有实用价值的数据库结构.
这里的"实用价值",是指满足用户关于功能、性能、安全22Oracle8i数据库开发与专业应用性、完整性及发展需求等诸方面的要求,同时又服从于特定DBMS的约束,并且可用简单的数据库模型来表示.
其次,方法学应具有足够的灵活性和通用性,不仅能够为具有不同经验的人使用,而且能够为受不同数据模型及不同DBMS限制的人使用.
最后,方法学应该是可再生的(Reproductable),即不同的设计者应用同一方法学设计同一问题时,应该得到相同或类似的结果.
数据库设计方法中比较著名的有新奥尔良(NewOrleans)方法.
它将数据库设计过程分为四个阶段:需求分析(分析用户需求),概念设计(信息分析和定义),逻辑设计(设计实现)和物理设计(物理数据库设计).
后来,S.
B.
Yao等又将数据库设计分为五个步骤.
又有人主张数据库设计应包括数据可系统开发的全过程,并在每一阶段结束时都要进行评审,以便及早发现设计错误、早期纠正,同时主张各阶段也不是严格线性的,而是采取"反复探寻、逐步求精"的方法.
这种数据库设计步骤要注意以下几点:(1)设计步骤是从数据库应用系统设计和开发的全过程来考察数据库设计问题,因此,它既包括数据库模型的设计,也包括围绕数据库展开的应用处理的设计过程.
(2)在设计过程中努力把数据库设计和系统其他成分的设计紧密结合.
把数据和处理的需求收集、分析、抽象、设计、实现在各阶段同时进行,相互参照,互相补充,以完善两方面的设计.
(3)在有关处理特性的设计描述中,采用的设计方法和工具在软件工程和信息系统设计等课程中都有介绍,这里不再讨论.
本节重点讨论数据特性的设计描述,以及在结构特性设计中如何参照处理特性设计来完善数据模型设计的问题.
2.
1.
2系统规划1.
系统规划的任务系统规划应根据设计的系统的规模来确定它的具体内容.
如果设计一个规模很大、涉及面很广、用户要求高、难度大的一个大型信息系统,就应该按信息工程的要求进行总体战略规划,即进行以总体数据规划为中心的总体规划和总体设计,包括制定开发和建立大型信息系统的企业信息化规划的方针、战略策略等,有关内容可参见有关信息工程的资料.
下面,我们对一般模型的数据库系统提出系统设计各阶段的任务及其工作成果.
系统规划是确定系统的名称、范围;确定系统开发的目标功能和性能;确定系统所需的资源(人员、设备、资金等);估计系统开发的成本;确定系统实施计划及进度;分享估算系统可能达到的效益;确定系统设计的原则和技术路线等.
2.
阶段成果该阶段的成果是系统的总体规划报告,其主要内容包括:(1)系统一般概述:系统名称,任务提出,系统范围等.
(2)系统特点:复杂性——是否涉及多媒体、实施检索、动态检索等;综合性——是否涉及多层次、多主体、多功能等;连续性——与现行系统接口、保护投资、可扩展性等方面的特点;第2章逻辑数据库的设计与实现23移植性——计算机系统环境改变、异构互连等.
(3)系统目标:目标树(总目标、分目标、子目标等).
(4)系统所需资源:现有情况,系统需求和落实情况.
(5)成本估算:分期估算.
(6)效益评估:效益包括社会效益和经济效益.
(7)可行性分析,包括:技术上的可行性(软硬件问题,技术性问题);系统开发和运行环境的可行性.
(8)设计原理:用于第一原则,系统开发的各个阶段尽可能吸收用户参加,倾听用户意见,及时交流问题以便统一认识,提高设计质量.
(9)技术路线:尽可能采用已经成熟的最新技术和方法,尽可能使用国际和国家及本企业的标准代码,尽可能保护现有投资(包括信息),尽可能与周边环境相适应等.
(10)系统开发的组织落实:各类人员比例,每一成员能投入时间等.
(11)系统开发计划及进度安排等.
2.
1.
3需求分析1.
需求分析任务需求分析阶段的任务是:对现实实际要处理的对象(组织、部门、企业等)进行详细调查,在了解现行系统的概况、确定新系统功能的过程中,收集支持系统目标的基础数据及其处理方法.
需求分析是在用户调查的基础上,通过分析,逐步明确用户对系统的需求,包括数据需求和围绕这些数据的业务处理需求.
需求分析一般自顶向下地进行.
调查的重点是"数据"和"处理".
通过调查要从用户处获得对数据库的下列需求:(1)信息需求.
信息需求定义未来信息系统使用的所有信息,弄清用户将向数据库输入什么样的信息数据,从数据库中要求获得什么样的信息内容,将要输出什么样的信息等,即在数据库中需要存储哪些数据、对这些数据将做如何处理等,描述数据间本质上和概念上的联系,描述信息的内容和结构,以及信息之间的联系等性质.
(2)处理需求.
处理需求定义未来系统数据处理的操作功能,藐视操作的优先次序,包括操作执行的频率和场合,操作与数据之间的联系等.
处理需求还包括弄清用户要完成什么样的处理功能、每种处理的执行频度、用户需求的响应时间以及处理的方式是联机处理还是批处理等,同时也要弄清安全性和完整性的约束.
在需求分析中,通过自顶向下、逐步分解的方法分析系统.
任何一个系统都可以抽象为图2-1所示的数据流图(DataFlowDiagram,DFD)的形式.
数据流图是从"数据"和"处理"两方面来表达数据处理过程的一种图形化的表示方法.
在数据流图中,用方框表示数据处理(加工);用箭头的线段表示数据的流动和流动方向,及数据的来源和去向;用"书形框"表示要求在系统中存储的数据.
在系统分析阶段,不必确定数据的具体存储方式.
在此后的实现中,这些数据的存储形式可能是数据库中的关系,也可能是操作系统的文件.
数据流图的"处理"抽象表达了系统的功能要求,系统的整体功能要求可以分解为系统的若干子功能要求,通过逐步分解的方法,一直可以分解到将系统的工作过程表达清楚为止.
在功能分解的同时,每个子功能在处理时所用的数据存储也被逐步分解,从而形成若干层次的数据流图.
24Oracle8i数据库开发与专业应用图2-1数据流图2.
需求分析的基本步骤(1)需求的收集:需求收集是指收集数据、发生时间、频率、发生规则、相互联系、约束条件、计划控制及决策过程等.
注意不仅要注重收集弄清处理流程,还要注重规约.
收集方法可以是交谈、书面填表、开调查会、查看和分析业务记录、实地考察或资料分析法等.
(2)需求的分析整理:①数据流程分析:以数据流图表示.
②数据分析结构描述:除DFD外,还有一些规范表格作补充描述.
一般有:数据清单(数据元素表)、业务活动清单(事务处理表)、完整性及一致性要求、响应时间要求、预期变化的影响.
它们是数据字典的雏形,主要包括:a.
数据项:它是数据的最小单位,包括项名、含义、别名、类型、长度、取值范围及与其他项的逻辑联系等;b.
数据结构:是若干数据项的有序集合,包括数据结构名、含义、组成的成分等;c.
数据流说明:数据流可以是数据项,也可以是数据结构,表示某一加工的输入和输出数据,包括数据流名、说明、流入的加工名、流出的加工名、组成的成分等;d.
数据存储说明:说明加工中需要存储的数据,包括数据存储名、说明、输入数据流、输出数据流、组成的成分、数据量、存储方式、操作方式等;e.
加工过程:包括加工名、加工的简要说明、输入输出数据流等.
③数据分析统计:指将收集的数据按基本输入数据(包括人工录入、系统自动采集、转入等)、存储数据(包括一次性存储量、周期递增量)、输出数据(包括报表输出、转出等)分别进行统计.
④分析围绕数据的各种业务处理功能,并以带说明的系统功能结构图形式输出.
3.
阶段成果需求分析的阶段成果是系统需求说明书,此说明书主要包括数据流图、数据字典的雏形表格、各类数据的统计表格、系统功能结构图的必要的说明.
系统需求说明书将作为数据库设计全过程的重要依据文件.
2.
1.
4概念设计数据库概念设计的任务是产生反映企业组织需求的数据库概念结构,即概念模型.
概第2章逻辑数据库的设计与实现25念模型不依赖于计算机系统和具体的DBMS.
设计概念模型的过程称为概念设计.
1.
概念模型表达概念设计结果的工具称为概念模型.
概念模型应具备:(1)丰富的语义表达能力,能表达用户的各种需求,包括描述现实世界中各种对象及其复杂的联系,以及用户对数据对象的处理要求等.
(2)易于交流和理解.
概念模型是DBA、应用系统开发人员和用户之间的主要交流工具.
(3)易于变动.
概念模型要能灵活地加以改变,以反映用户需求和环境的变化.
(4)易于向各种数据模型转换,易于从概念模型导出与DBMS有关的逻辑模型.
2.
概念设计的工具概念设计的工具最著名、最实用的是P.
P.
S.
chen于1976年提出的"实体联系法"(E-R法),这种方法将现实世界结构统一属性、实体以及实体之间的联系来描述.
3.
概念设计的策略和主要步骤设计概念结构的策略有如下几种:(1)自顶向下:首先定义全局概念结构的框架,再做逐步细化.
(2)自底向上:首先定义每一局部应用的概念结构,然后按一定的规则把它们集成,从而得到全局概念结构.
(3)由里向外:首先定义最重要的那些核心结构,再逐渐向外扩充.
(4)混合策略:混合策略是把自顶向下和自底向上结合起来的方法,它先自顶向下设计一个概念结构的框架,然后以它为骨架再自底向上设计局部概念结构,并把它们集成.
这里对常用的自底向上设计策略给出数据库概念设计的主要步骤:①进行数据抽象,设计局部概念模式;②将局部概念模式综合成全局概念模式;③进行评审,改进.
2.
1.
5逻辑设计逻辑设计的目的,是从概念模型导出特定的DBMS可以处理的数据库的逻辑结构(数据库的模式和外模式),这些模式在功能、性能、完整性、一致性约束及数据库可扩充性等方面都满足用户的要求.
1.
逻辑设计的步骤和内容(1)形成初始模式:把E-R图的实体和联系模型,转换成选定的DBMS支持的数据类型(层次、网络、关系、面向对象).
(2)子模式设计:子模式是应用程序与数据库的接口,允许有效访问数据库而不破坏数据库的安全性.
(3)模式评价:根据定量分析和性能测算,对逻辑数据库结构(模型)做出评价.
定量分析是指处理频率和数据容量及其增长情况.
性能测算是指逻辑记录访问数目、一个应用程序传输的总字节数和数据库的总字节数等.
(4)修正模式:为使模式适应信息的不同表示,可利用DBMS功能,如建立索引,散列功能等,但不修改数据库的信息.
2.
E-R模型向关系模型的转换E-R模型可以向现有的各种数据库模型转换,对不同的数据库模型有不同的转换规则.
26Oracle8i数据库开发与专业应用向关系模型转化的规则是:(1)一个实体类型转换成一个关系模式,实体的属性就是关系的属性,实体的键就是关系的键.
(2)一个联系类型转换成一个关系模式,参与该联系类型的各实体的键以及联系的属性转换成关系的属性.
该关系的键为有三种可能情况:①若联系为1∶1联系,则每个实体的键均是该关系的辅键(候选键);②若联系为1∶n联系,则关系的键为n端实体的键;③若联系为m∶n联系,则关系的键为诸相关实体的键的组合.
3.
关系数据库的逻辑设计(1)导出初始关系模式:将E-R图按规则转换成关系模式.
(2)规范化处理:消除异常,改善完整性、一致性和存储效率,一般达到3NF就行.
规范化过程实际上就是单一化过程,即让一个关系描述一个概念,若多于一个概念的就把它分离出来.
(3)模式评价:模式评价的目的是检查数据库模式是否满足拥护的要求,它包括功能评价和性能评价.
(4)优化模式:如模式有疏漏要新增关系或属性,如模式的性能不好,则要采用合并、分解,或选用另外结构等.
①合并:对具有相同关键字的关系模式,如它们的处理主要是查询操作,且常在一起使用,可将这类关系模式合并.
②分解:虽已达到规范化,但因某些属性过多时,可将它分解成两个或多个关系模式.
这种属性分解称为垂直分解.
要注意的是,垂直分解所得到的每一关系都应包含主键.
(5)形成逻辑设计说明书:逻辑设计说明书包括:①应用设计指南:访问方式,查询路径,处理要求,约束条件等.
②物理设计指南:数据访问量,传输量,存储量,递增量等.
③模式及子模式的集合:模式和子模式可用DBMS语言描述,也可列表描述.
2.
1.
6物理设计数据库的物理设计是指已确定的逻辑数据库结构(逻辑模型),研制出一个有效、可实现的数据库结构(存储结构或物理结构)的过程.
物理设计常常包括某些操作约束,如响应时间与存储要求等.
数据库的物理设计的主要任务是:对数据库中数据在物理设备上的存放结构和存取方法进行设计.
数据库物理结构依赖于给定的计算机系统,而且与具体选用的DBMS密切相关.
1.
物理设计的步骤物理设计可分为五步,前三步为结构设计,后两步为约束和程序设计.
(1)存储记录的格式设计对数据类型特征做分析,对存储记录进行格式化,决定如何进行数据压缩或代码化.
可使用"垂直分割法",对含有较多属性的关系,按其中属性的使用频率不同进行分割;或使用"水平分割法",对含有较多记录的关系,按某些条件进行分割.
并把分割后的关系定义在相同或不同类型的物理设备上,或在同一设备的不同区域上,从而使访问数据库的代第2章逻辑数据库的设计与实现27价最小,提高数据库的性能.
(2)存储设计方法物理设计中最重要的一个考虑,是把存储记录在全范围内进行物理安排,存放的方式有以下四种:①顺序存放,平均查询次数为关系的记录的二分之一;②杂凑存放,查询次数由杂凑算法决定;③索引存放,要确定建立何种索引,及索引的表和属性;④聚簇(cluster)存放,"记录聚簇"是指将不同类型的记录分配到相同的物理区域中去,以充分利用物理顺序性的优点,从而提高访问速度,即把经常在一起使用的记录聚簇在一起,以减少物理I/O次数.
(3)访问方法设计访问方法设计为存储在物理设备上的数据提供存储结构和查询路径(这与数据库管理系统有很大关系).
(4)完全性和安全考虑根据逻辑设计说明书中提供的对数据库的约束条件、具体的DBMS、OS的性能特征和硬件环境,设计数据库的完整性和安全措施.
(5)应用设计应用设计包括:人机接口设计(菜单等)、屏幕设计、I/O格式设计、处理加工设计等.
(6)形成物理设计说明书在物理设计中,应充分注意物理数据的独立性.
所谓物理数据的独立性,是指消除由于物理数据结构设计决策而引起对应用程序的修改.
物理设计的结果是物理设计说明书,其内容包括存储记录格式、存储记录位置分布及访问方法、能满足的操作需求(界面),并给出对硬件和软件系统的约束.
在设计过程中,效率问题的考虑只能在各种约束得到满足且确定方案可行之后进行.
2.
物理设计的性能多性能测量使设计者灵活地对初始设计过程和未来的修正作出决策.
假设数据库性能用"开销(cost)",即时间、空间及可能的费用来衡量,则在数据库应用系统生存期中,总的开销包括:规划开销,设计开销,实施和测试开销,操作开销,运行维护开销.
对物理设计者来说,主要考虑操作开销,即为使用户获得及时、准确的数据所需开销和计算机资源的开销.
可分为如下几类:(1)查询和响应时间响应时间定义为从查询开始到查询结果开始显示之间所经历的时间,它包括CPU服务时间、CPU排队等待时间、I/O服务时间,例如,如果有效地使用数据压缩技术,选择好的访问路径和合理安排记录的存储等,都可以减少服务时间.
(2)更新事务的开销更新事务的开销主要包括修改索引、重写物理块或文件、写校验等方面的开销.
(3)报告生成的开销报告生成的开销主要包括检索、重组、排序和结果显示方面的开销.
(4)主存储空间开销28Oracle8i数据库开发与专业应用这方面的开销包括程序和数据所占有的空间的开销.
一般对数据库设计者来说,可以对缓冲区分配(包括缓冲区个数和大小)作适当的控制,以减少空间开销.
(5)辅助存储空间辅助存储空间分为数据块和索引块两种空间.
设计者可以控制索引块的大小、装载因子、指针选择项和数据冗余等.
实际上,数据库设计者能有效控制I/O服务和辅助空间;有限地封锁延迟,CPU时间和主存空间;而完全不能控制CPU和I/O队列等待时间、数据通信延迟时间.
2.
1.
7实现和维护1.
数据库的实现根据逻辑设计和物理设计的结果,在计算机上建立起实际数据库结构、装入数据、测试和运行的过程称为数据库的实现.
(1)建立实际的数据库结构.
(2)装入试验数据对应用程序进行测试,以确认其功能和性能是否满足设计要求,并检查其空间的占有情况.
(3)装入实际数据,即数据库加载,建立起实际的数据库.
2.
其他设计其他设计工作包括数据库的安全性、完整性、一致性和可恢复性等的设计.
这些设计总是以牺牲效率为代价的.
设计人员的任务就是要在效率和尽可能多的功能之间进行合理权衡.
(1)数据库的再组织设计对数据库的概念、逻辑和物理结构的改变称为再组织(reorganization),其中改变概念或逻辑又称为再构造(restructuring),改变物理结构称为再格式化(reformatting).
再组织通常是由于环境需求的变化或性能原因而引起的.
一般DBMS特别是RDBMS都提供数据库的再组织实用程序.
(2)故障恢复方案设计数据库中考虑的故障恢复方案,一般都是基于DBMS系统提供的故障恢复手段.
如果DBMS已提供了完善的软硬件故障恢复和存储介质的故障恢复手段,那么设计阶段的任务就简化为确定系统登录的物理参数,如缓冲区个数、大小,逻辑块的长度,物理设备等.
否则,就要制订人工备份方案.
(3)安全性考虑许多DBMS都有描述各种对象(如记录,数据项)的存取权限的成分.
在设计时,根据对用户需求分析,规定相应的存取权限.
子模式是实现安全性要求的一个重要手段.
也可在应用程序中设置密码,对不同的使用者给予一定的密码,以密码控制使用级别.
(4)事务控制大多数DBMS都支持事务概念,以保证多用户环境下的数据完整性和一致性.
有人工和系统两种控制方法,系统控制以数据操作语句为单位,人工控制则由程序员以事务的开始和结束语句显示实现.
大多数DBMS提供封锁粒度的选择,封锁粒度一般都有表级、页面级、记录级和数据项级.
粒度越大控制越简单,并发性能越差,这些在设计中都要统筹考虑.
第2章逻辑数据库的设计与实现293.
运行与维护数据库投入正式运行,标志着数据库设计和应用开发工作的结束和运行维护阶段的开始.
本阶段的主要工作是:(1)维护数据库的安全性和完整性:及时调整授权和密码,转储及恢复数据库;(2)检测并改善数据库性能:分析评估存储空间和响应时间,必要时进行再组织;(3)增加新的功能:对现有功能按用户需要进行扩充;(4)修改错误:包括程序和数据.
目前,随着DBMS功能和性能的提高,特别是在关系型DBMS中,物理设计的大部分功能和性能可由RDBMS来承担,所以选择一个合适的DBMS,能使数据库物理设计变得十分简单.
2.
2关系模型和规范化关系模型之所以重要,有两个原因.
首先,关系模型的构件是广泛通用的,它可用来表达独立于DBMS的设计.
其次,关系模型是一类重要的DBMS产品的基础,熟悉这些模型将有助于使用这些产品之一来完成数据库.
本节介绍关系模型的基础,解释规范化的基本概念.
我们从这样一个事实出发,即并非所有的关系都是一样的,有些关系比其他关系好.
规范化是把有问题的关系转化成为两个或多个没有这些问题的关系的过程.
更重要的是,规范化可用作检查关系合乎需要的程度和正确性的指南.
在什么是结构好的关系这一问题上已经作了很多理论工作,这种工作称作规范化,因为数据库技术的一个先驱E.
F.
Codd定义了关系的不同规范形式.
2.
2.
1关系模型一个关系是一个二维表,表中的每一行保存属于某些事物或某些事物的一部分的数据,表的每一列包含关于属性的数据.
有时行也称作元组,列称作属性.
关系、元组和属性这些术语来自关系数学,即该模型的数学基础.
MIS专家发现文件、记录和域这些类似的属于更好些,大多数用户则会发现表、行和列这些术语更实用.
一个表要想成为关系,它必须满足某些约束.
首先,表中的每一格必须是单值的,重复的组和数组都不能作为值.
每一列的所有条目都必须是同一类型的,例如,如果某一列包含雇员的编号,那么对于表的每一行它都必须有雇员编号.
每一列都有唯一的名字,列在表中的顺序不重要.
最后,表中任意两行不能相同,行在表中的顺序也不重要.
为了理解关系模型和规范化,首先应该理解函数依赖和关键字这样两个术语.
这两个术语是关于关系中的属性之间的关系的.
1.
函数依赖函数依赖是属性之间的一种关系.
它意味着,如果我们给定了一个属性的值,我们就可以获得另一个属性的值.
例如,如果我们知道CustomerAccountNumber的值,我们就可以得出CustomerBalance的值.
如果这种情况成立,我们就可以说CustomerBalance函数依赖于CustomerAccountNumber.
更一般的形式表达为,如果属性X的值决定属性Y的值,那么属性Y函数依赖于属性X.
30Oracle8i数据库开发与专业应用等式可以表示函数依赖.
例如,如果我们知道一个物品的价格和所购买的物品的数量,我们就可以计算出这些物品的总价.
计算方式如下:TotalPrice=ItemPrice*Quantity这时我们就说TotalPrice函数依赖于ItemPrice和Quantity.
关系中的属性之间的函数依赖通常不包含等式.
例如,假定学生有一个唯一的标志号SID,每个学生有且只有一个专业,给定SID的值,我们就能弄清该学生的专业,因此,Major函数依赖于SID.
函数依赖不像等式,它是不能用算术计算出来的,而是由数据库中的表列出.
事实上,函数依赖表示法是我们需要数据库的原因之一.
函数依赖可表示成下面的形式:SIDMajor读作"SID函数决定Major"或"Major函数依赖于SID".
2.
关键字关键字是由一个或多个属性组成的可唯一标识一行的属性组.
考虑图2-2中的关系ACTIVITY,其属性为SID和Fee,每行的意思是一个学生交纳一定的费用参加某项活动.
假定只允许学生一次参加一项活动,在这种情况下,SID的值决定唯一的一行,因此它就是一个关键字.
图2-2ACTIVITY关系关键字也可以是由一组属性合起来组成.
例如,如果允许学生同时参加多项活动,那么SID的值就可能出现在表中的两行或多行,因此,SID不能唯一地标识一行,这时也许就需要某些属性的组合,如(SID,Activity).
属性是否关键字和属性间是否存在函数依赖不是由一个抽象的规则集决定的,而是由假设、用户意识中的模型和开发数据库的组织的事务规则决定的.
在该例中,SID是否是关键字或(SID,Activity)是否是关键字,或某些其他组合是否是关键字完全由数据库的基本语义来决定,我们必须向用户咨询来解决这些问题.
在访问用户后,假定我们发现学生实际上是允许一次参加多项活动的,则该情形由图2-3中的关系ACTIVITY表示.
如前所述,SID不是该关系的关键字,例如,学生100同时参加了滑雪和高尔夫,SID的值100在两个不同的行出现.
事实上,对于这种关系,没有一个单独的属性是关键字,因此,关键字必须是两个或多个属性的组合.
考虑该表中两个属性的组合,有三种可能:(SID,Activity)、(SID,Fee)和(Activity、Fee).
这些组合中的任意一个都是关键字吗要想成为关键字,它必须唯一地标识一行.
同样,要回答这样的一个问题,我们必须咨询用户.
我们不能简单地依靠图2-3中的样本数据或凭自己的假设来作出决定.
)第2章逻辑数据库的设计与实现31图2-3关键字为两个属性的关系与用户交谈后,假定我们发现几个活动可以收费相同.
由于这种情况(SID,Fee)组合不能唯一地决定一行.
例如,学生100参加两个不同的活动,两者收费都是200美元,这就意味着(100,$200)组合在表中出现两次.
因此,这种组合不能称为关键字.
因为有许多学生参加滑雪,(Activity、Fee)不能唯一地决定一行,所以它不能作为关键字.
只要我们不需要记录学生参加给定活动的不同情况,(SID,Activity)就可以成为唯一标识.
同样,我们必须向用户咨询这个问题.
假定我们知道只需要记录当前的活动,那么(SID,Activity)组合可以决定唯一的一行,因此,(SID,Activity)是该关系的关键字.
如果用户指定要记录当前活动和过去活动,则图2-3中的关系就会有重复行.
因为这是关系的定义所禁止的,我们需要增加其他属性,如Data.
每个关系都至少有一个关键字,作为一个极端情况,关键字包含关系中的所有属性.
2.
2.
2规范化不幸的是,并非所有的关系都同样合乎期望的.
只是最小程度地满足关系定义的表结构不一定有效和合适.
对于某些关系,改变数据可能导致不希望的后果,称作更新异常.
异常可以通过把关系重新定义为两个或多个关系来消除.
大多数情况下,重新定义或规范化的关系是优先选用的.
1.
更新异常再考虑图2-2中的关系ACTIVITY.
如果我们删除学生100的元组,我们将不仅丢掉学生100是滑雪者的事实,还丢掉了滑雪的费用是200美元的事实,这就叫做更新异常.
就是说,删除关于一个实体的事实(学生100是滑雪者)的同时,我们随意地删除了关于另外一个实体的事实(滑雪活动的费用是200美元).
在一个删除中,我们丢掉了两个实体的事实.
同样的关系可以用来说明插入异常.
假定我们潜水活动的费用为175美元,但我们不能在ACTIVITY关系中输入这些数据,直到有一个同学参加了潜水活动才可以,这种约束称作插入异常,它意味着直到我们有了关于另外一个实体的事实,我们才能插入某个实体的事实.
图2-2中的关系可用于某些应用,但它明显有问题.
通过把ACTIVITY关系分解成两个关系,每个关系处理一个不同的主题,我们就可以消除删除差异和插入差异.
例如,我们可以把SID和Activity放在一个关系中(我们称新关系为学生活动,用STU-ACT表示),把Activity和Fee放在一个称作ACT-COST(表示活动费用)的关系中,图2-4显示了同样的样本数据存储在两个新关系中.
32Oracle8i数据库开发与专业应用图2-4把ACTIVITY分解成两个关系现在如果我们从STU-ACT中删除学生100,我们没有丢失滑雪活动费用为200美元这一事实.
此外,即使没有任何人参加潜水,我们也可以在ACT-COST中增加潜水活动及其费用.
这样,删除异常和插入异常就消除了.
但是,把一个关系分解成两个关系有一个缺点.
假定一个学生试图报名参加一项不存在的活动,例如,学生250要参加网球活动.
可以在STU-ACT中插入一个新元组(该元组包括250,RACKETBALL),但是否该这样做呢可以允许学生参加关系ACT-COST中不存在的活动吗换个方式讲,如果某ACTIVITY的值在表ACT-COST中并不存在,数据库应用是否应该以某种方式阻止选择参加该活动的学生加入到表STU-ACT中.
这个问题的答案在于用户的需求,这种约束称作参照完整性约束.
如果这种行为应该禁止,则这种约束必须作为模式设计的一部分记入文档.
以后在实现时,如果使用的DBMS产品提供这种约束检查,那么就可以把这种约束定义到DBMS中.
如果所使用的DBMS产品不提供这种检查,那么这种约束必须由应用程序强制实行.
假定用户指定活动可以在学生参加之前存在,但学生不会参加还没有指定费用的活动(就是说ACT-COST表中还没有该活动).
我们可以通过多种方式在数据库设计中表达这种约束:STU-ACT中的Activity是ACT-COST中的Activity的子集,或者STU-ACT[Activity]是ACT-COST[Activity]的子集.
根据这种标记,[]表示从关系提取的一系列数据.
这些表达式仅仅表明,STU-ACT中的Activity属性必须存在于ACT-COST中的Activity属性中.
它还意味着,在我们允许一个Activity进入STU-ACT之前,我们必须确信它已经在ACT-COST中存在.
2.
规范化的本质图2-2中的ACTIVITY关系中的异常可以直观地描述如下.
问题发生的原因在于ACTIVITY包含关于两个不同问题的事实:哪个学生参加哪项活动和每项活动的费用.
当我们新增加一行时,我们必须同时增加关于两个主题的数据;当我们删除一行时,我们必须同时删除关于两个主题的数据.
每个规范化的关系只有一个主题,如果某个关系有两个或多个主题,它就应该分解为多个关系,每个关系只能有一个主题.
但是,每当我们分解关系时候,我们应该建立对关联约束的要求,这一过程就是规范化的实质.
当我们发现一个关系存在更新异常时,通过把关系分解为两个或多个单独的关系,每个关系只有一个主题,我们就可以消除这种异常.
3.
关系的分类关系可以根据其中易出现的更新异常的类型进行分类.
20世纪70年代,关系理论家各自研究了这些类型的一部分.
某个人发现异常,就加以分类并考虑防止这种异常的方法.
第2章逻辑数据库的设计与实现33每次发生这种情况时,设计关系的准则都得到了改进.
这些用以防止异常的关系和技术称作范式.
根据关系的结构,某个关系可以在第一范式、第二范式中,或在其他范式中.
E.
F.
Codd在其1970年的里程碑性的文章中,定义了第一、第二和第三范式(1NF,2NF,3NF).
后来,又有了Boyce-Codd范式(BCNF),接着,第四和第五范式也定义出来了.
如图2-5所示,这些范式是嵌套的.
就是说,第二范式中的关系也是第一范式中的,5NF(第五范式)中的关系也是4NF、BCNF、3NF、2NF和1NF中的关系.
图2-5各范式中的关系这些范式是很有帮助的,但它们有严格的限制.
没有理论能够保证任何一种范式能消除所有的异常,每种范式只能消除一种异常.
1981年,R.
Fagin定义了一种新的范式,称作域/关键字范式(DK/NF),此后情况有了变化.
在他的一篇重要文章中,证明DK/NF中的关系不会出现任何类型的更新异常,他还证明了任何不会出现更新异常的关系都是在DK/NF关系中.
在DK/NF关系被定义之前,数据库设计者需要不停地寻找越来越多的异常和越来越多的范式.
但是,R.
Fagin的证明简化了这种情形.
如果我们能把一个关系置于DK/NF中,那么我们就可以确信它不会有更新异常,问题在于,如何把关系置于DK/NF中.
2.
2.
3第一范式到第五范式任何符合关系定义的关系都在第一范式中.
一个表要成为关系必须遵守以下规则:表的每一格必须是单值的,数组和重复的组都不能作为值;任意一列的所有条目都必须是同一类型的,每一列都有唯一的名字,但列在表中的顺序是没有意义的;表中任意两行不能相同,行的顺序也是没有意义的.
图2-2中的关系在第一范式中.
正如我们所看到的,第一范式中的关系可以使用,但会有更新异常.
当然,通过改变关系的格式,把关系分解成两个或多个关系,就可以消除异常.
当我们这样做时,新的关系就处于某些其他范式中,这具体取决于我们所消除的异常和新关系容易发生的更新异常.
1.
理解第二范式为了理解第二范式,考虑图2-3中的ACTIVITY关系.
该关系有类似于前面讨论过的更新异常.
如果我们删除学生175元组,我们将丢失壁球活动的费用50美元这一事实.
同样,在某个学生参加这一项活动之前,我们不能输入该活动.
因此,该关系存在删除异常和插入异常.
该关系的问题在于它有一个只包含关键字的一部分的依赖关系.
这里,关键字是34Oracle8i数据库开发与专业应用(SID,Activity),但关系包含一个依赖关系,即Activity-Fee,该依赖关系的决定因素(Activity)只是关键字(SID,Activity)的一部分.
在这种情况下,我们说Fee部分依赖于该表的关键字.
如果Fee依赖于整个关键字,那么就不会有更新异常.
因此,要消除更新异常,我们必须把该关系分解成两个关系.
这种情形导致了第二范式的定义:如果一个关系的所有非关键字属性都依赖于该表的关键字,那么该关系就属于第二范式.
根据这一定义,每个以单个属性作为关键字的关系自动进入第二范式.
因为关键字是一个属性,所以按缺省约定,每个非关键字属性都依赖于整个关键字,不存在部分依赖关系.
第二范式只是关于有组合关键字的关系.
ACTIVITY可以分解成两个在第二范式中的关系.
该关系和图2-4中的相同,即STU-ACT和ACT-COST,这些关系都在第二范式中,因为它们都有单属性的关键字.
2.
第三范式第二范式中的关系也有异常.
考虑图2-6(a)中的关系HOUSING,它的关键字是SID,函数依赖是SID-Building,Building-Fee.
这些依赖之所以存在是因为一个学生只住在一个大楼内,一个大楼只收一种费用.
例如,每个住在Randolph楼的人每季度支付1100美元.
因为SID决定Building,Building决定Fee,所以间接地有SID-Fee.
这种函数依赖称为传递依赖,因为SID通过Building属性决定Fee.
由于这种传递依赖,虽然SID是单个属性,而且是关键字,关系也是在第二范式中(Building和Fee都由SID决定),但HOUSING仍然有异常.
如果我们删除图2-6(a)中的第二个元组,会发生什么我们不仅会丢失学生150住在Ingersoll楼这一事实,还丢掉了住在那里的费用为1100美元这个事实,这是一个删除异常.
我们怎样才能记录Carrigg楼的费用是500美元这一事实直到学生搬进来,我们才能记录这个事实,这是一个插入异常.
图2-6消除传递依赖(a)有传递依赖的关系;(b)消除传递依赖的关系.
要想从第二范式关系中消除异常,必须消除传递依赖.
这就导致了第三范式的定义:一个关系如果在第二范式关系中,且没有传递依赖,则该关系式在第三范式中.
HOUSING关系可以分解成两个第三范式的关系.
图2-6(b)中的关系STU-HOUSING(SID,Building)和关系BLDG-FEE(Building,Fee)就是例子.
图2-2中的ACTIVITY关系也有传递依赖.
在ACTIVITY中,SID决定Ativicty,Activity第2章逻辑数据库的设计与实现35决定Fee,因此,ACTIVITY不在第三范式中.
把ACTIVITY分解为STU-ACT(SID,Ativicty)和ACT-COST(Ativicty,Fee),就可以消除异常.
3.
Boyce-Codd范式不幸的是,即使关系在第三范式中,也可能有异常.
考虑图2-7(a)中的ADVISER关系.
假定这一关系的基本需求是学生(SID)可以有一个或多个专业(Major),一个专业学生可以有多个教师(Fname)作为导师,一个教师只指导一个专业领域.
图2-7Boyce-Codd范式因为学生可以有多个专业,所以SID不能决定Major.
此外,因为学生可以有几个导师,所以SID不能决定Fname.
因此,SID本身不能成为关键字.
(SID,Major)组合决定Fname,(SID,Fname)组合决定Major.
这样,两个组合都可以作为关键字.
两个或多个可作关键字的属性或属性结合称作候选关键字.
任意一个选作关键字的候选关键字称作主关键字.
除了候选关键字外,还有一种函数依赖需要考虑:Fname决定Major.
因此,Fname是一个决定因素.
根据定义,ADVISER在第一范式中,它也在第二范式中,因为任何非关键字属性都依赖于整个关键字.
由于没有传递依赖,所以ADVISER关系也在第三范式中.
尽管如此,它仍然有更新异常.
假定学生300退学.
如我们删除学生300的元组,我们将丢失Perls指导心理学的事实,这是一个删除异常.
类似地,我们怎样才能存储Keynes指导经济学的事实直到有学生选修该专业,我们才能存储,这是一个插入异常.
类似这种情形,导致了Boyce-Codd范式(BCNF)的定义:如果一个关系的每个决定因素都是候选关键字,则该关系在BCNF范式中.
ADVISER不在BCNF中,因为,Fname是一个决定因素,但却不是候选关键字.
BCNF中的关系对于函数依赖不存在异常,这好像解决了更新异常的问题.
但是,不久又发现,异常可以在函数依赖之外的情况下出现.
4.
第四范式考虑图2-8中的关系STUDENT,它表明了学生、专业和活动之间的关系.
假定学生可以选修几个不同的专业,也可以参加几个不同的活动.
因此,唯一的关键字就是属性组合(SID,Major,Activity).
学生100的专业为音乐和会计,他还参加了游泳和网球活动.
学生36Oracle8i数据库开发与专业应用150的专业为数学,只参加慢跑活动.
SID和Major之间的关系是什么因为学生可以有几个专业,所以不是函数依赖.
一个SID的值可以有多个Major的值.
SID和Activity之间的关系也是同样.
这种属性依赖称作多值依赖,多值依赖会导致更新异常.
首先,请注意图2-8中的数据冗余.
学生100有四个记录,每个记录表示她的一个专业和一项活动的配对.
如果数据用较少的行存储,假定只有两个元组,一个对应音乐和游泳,一个对应会计和网球,这就容易导致误解.
好像学生100只有在专业为音乐的时候才能游泳,只有在专业为会计的时候才能打网球,而这种解释是不符合逻辑的.
她的专业和活动是完全相互独立的.
因此,要想防止这样一种错误的结论,我们需要存储所有的专业和活动的组合.
图2-8有多值依赖的关系假定由于学生报名参加滑雪,我们增加如图2-9(a)所示的元组[100,MUSIC,SKIING].
这里表明,学生100在专业是音乐而不是会计时参加滑雪活动.
为了保持数据的一致性,我们为她的每一个专业和滑雪活动的配对增加一行,这样,我们必须增加如图2-9(a)所示的[100,ACCOUNTING,SKIING]行.
这是一种更新异常,即为了一个简单的数据变化,需要进行太多的修改.
一般地讲,当关系至少有三个属性,其中的两个是多值时,且它们的值只依赖于第三个属性时,才会有多值依赖.
换句话说,对于关系R(A,B,C),如果A决定B的多值,A决定C的多值,B和C相互独立,这才是存在多值依赖.
正如我们在前面的例子中所看到的那样,SID决定Major的多值,SID决定Activity的多值,但Major和Activity相互独立.
再看图2-8,注意多值依赖是如何表示的:SID-Major和SID-Activity,读作"SID多值决定Major和SID多值决定Activity".
这个关系在BCNF中(在2NF中,是因为SID是整个关键字;在3NF中是因为没有传递依赖;在BCNF中,是因为没有非关键字决定因素).
但是,正如我们已看到的,它还是有异常.
如果某学生增加一个专业,我们必须为该新专业输入与该学生的每一项活动配对的所有元组,如果学生报名参加一项新的活动,也存在同样的问题.
如果一个学生放弃一个专业,我们必须删除他的所有包含该专业的记录.
如果一个学生参加四项活动,就会有四个元组包含他所放弃的专业,每个元组都必须删除.
第2章逻辑数据库的设计与实现37图2-9有插入异常的STUDENT关系(a)插入单个元组;(b)插入两个元组.
要删除这些异常,我们必须消除多值依赖.
通过建立两个关系,每个关系只存储一个多值属性的数据,就可以消除异常.
最后所得的关系没有异常,它们是STU-MAJOR(SID,Major)和STU-ACT(SID,Activity),如图2-10所示.
图2-10多值依赖的消除从这些讨论出发,我们定义了第四范式:一个关系如果在BCNF中,且没有多值依赖,则该关系在第四范式中.
5.
第五范式第五范式所讨论的依赖非常模糊,它与可以分解为子关系的关系有关,这和我们前面所做的类似,但分解后的关系却不能重构.
这种情况发生的条件目前尚没有清楚直观的意义,我们不知道这种依赖的后果,甚至不知道它们是否有实际的后果.
我们所讨论的每一种范式,都是由在低级范式的某些关系中发现异常的研究人员发现的.
尽管每一种范式都解决了前一种范式中存在的一些问题,但没有人知道还有什么问题没有发现.
每走一步,数据库定义都向结构更好前进了一步,但没有人能保证不会再发生异常.
下面,我们将研究一个可以保证没有任何类型的异常的范式,当我们把一个关系置于该范式中时,我们知道即便是第五范式中的那种模糊的异常也不会发生.
2.
2.
4域/关键字范式1981年,R.
Fagin定义了域/关键字范式(DK/NF).
他证明,域/关键字范式中的关系没有更新异常,没有更新异常的关系必定在域/关键字范式中.
该发现建立了范式定义的范围,至少为了消除更新异常,不需要再定义更高的范式.
同样重要的是,DK/NF只包括域/关键字范式的概念,这些概念对数据库实践者来说都是非常基础和非常接近的.
DBMS产品非常愿意支持这些新概念.
从某种意义上讲,Fagin38Oracle8i数据库开发与专业应用的工作形式化了和证明了很多实践者认为很直观但又不能形式化的东西.
1.
定义DK/NF概念是非常简单的:如果一个关系中的每个约束都是关键字和域的定义的逻辑结果,则该关系在DK/NF中.
考虑该定义中的重要术语:约束、关键字和域.
该定义中的约束的意义是非常广泛的.
Fagin定义约束是一切制约属性的静态值,且精确程度足以判断属性的真假的规则.
因此,就该定义而言,编辑规则、外关联和内关联规则、函数依赖和多值依赖都是约束的例子.
Fagin特意排除了关于数据值变化的约束或依赖于时间值的约束,例如,"销售员目前的薪水不能少于以前的薪水"这样的规则就被排除在Fagin关于约束的定义之外.
除了依赖时间的约束,Fagin的定义是广泛和无所不包的.
关键字,就像我们前面定义的那样,是元组的唯一标识符.
DK/NF定义中所包含的第三个比较重要的是域,它是属性所允许的值的描述.
它有两个部分:物理描述和语义或逻辑描述.
其中,物理描述是指属性可以具有的值的集合,逻辑描述指属性的意义.
非正式地讲,在一个关系中,如果所要满足的约束都强制性地有关键字和域的约束产生,则该关系在DK/NF中.
此外,DK/NF中的关系不会有更新异常,因为DBMS产品可以实施关键字和域的约束来防止异常.
不幸的是,目前尚没有什么算法可以把关系转化到DK/NF中,甚至不知道哪种关系可以转化到DK/NF中.
发现或设计DK/NF关系的艺术成分多于科学成分,尽管如此,DK/NF对数据库设计仍是非常有用的.
事实上,DK/NF是一个设计目标.
我们希望把自己的关系定义成这样一种形式,即所有约束都是域和关键字的逻辑结果.
对于很多设计来说,这一目标是可以达到的.
如果不能达到,则必须在处理数据库的应用程序中建立约束.
2.
DK/NF的一个例子考虑图2-11中的STUDENT关系,它包含SID、GradeLevel、Building和Fee.
Building是指学生住的大楼,Fee是指在大楼内住宿所支付的费用.
STUDENT(SID,GradeLevel,Building,Fee)Key:SIDContraints:Building→FeeSIDmustnotbeginwithdigit1图2-11DK/NF的一个例子SID函数决定其他三个属性,因此,SID是关键字.
假定我们还从需求定义中知道,Building-Fee,根据Fagin的定理,我们就能确定该关系没有更新异常.
对于这个例子,这是很容易的.
为了实现学生编号不以1作首位这一约束,我们只需把该约束与学生编号域结合(图2-12).
实施这个域约束可以保障学生编号不以1作首位的约束得到满足.
下面我们需要把函数依赖Building-Fee转化成关键字的逻辑结果.
如果Building是一个关键字属性,则Building-Fee就是关键字的逻辑结果.
因此,问题就变成了如何把Building变成关键字,它在STUDENT中不能成为关键字,因为有多于一个学生住在同样的大楼里,但是,它可以成为它自己的关系的关键字.
为此,我们定义了BLDG-FEE关第2章逻辑数据库的设计与实现39系,以Building和Fee作为它的属性,Building是该关系的关键字.
定义了这个新关系后,我们就可以从STUDENT中消除Fee.
该例的域和关系的最终定义如图2-12所示.
DomainDefinitionsSIDinCDDD,whereCisdecimaldigitnot=1;D=decimaldigitGradeLevelin('FR','SO','JR','SN','GR')BuildinginCHAR(4)FeeinDEC(4)KeyDefinitionsSTUDENT(SID,GradeLevel,Building)Key:SIDBLDG-FEE(Building,Fee)Key:Building图2-12例中的域/关键字定义这个结果和我们把关系从2NF转化到3NF消除传递依赖所得到的结果相同.
但是,在这种情况下,过程更简单,结果更可靠.
过程之所以简单,是因为我们不需要知道我们在消除传递依赖,我们只需找到创造性的方法来把所有约束都变成域和关键字定义的逻辑结果.
结果之所以可靠,是因为把关系转化成3NF时,我们只知道异常比2NF时少了,但是,把关系转化成DK/NF,我们知道无论如何不会再有更新异常了.
2.
2.
5关系综合我们从一个不同的角度,即综合的角度,考虑关系设计.
从这个角度出发,我们的问题是,给定一个有某些函数依赖的属性集合,我们应该构成什么样的关系首先看两个属性,假设A和B,他们可以有三种关联方式:(1)它们互相决定:A→B和B→A.
因此A和B之间有1对1的关系;(2)一个决定另一个:A→B,但B→A不成立.
因此,A和B之间有多对1的关系;(3)它们函数无关:A→B和B→A都不成立.
因此,A和B之间有多对多属性关系.
1.
1对1属性关系如果A决定B,且B决定A,则这两个属性值之间有1对1关系.
情况肯定是这样的,因为如果A决定B,则A和B之间的关系是多对1;同样,如果B决定A,则B和A之间的关系也是多对1.
这两个陈述同时成立,则A和B之间的关系实际上必定为1对1(这就是多对1情况的一个特例),B和A之间的关系也是1对1.
因此,两者之间的关系是1对1.
由此,我们可以得到以下等效的陈述:(1)如果两个属性相互函数决定,则它们的数值之间的关系是1对1;(2)如果两个属性唯一地标识相同的事物(实体或对象),它们的数值之间的关系是1对1;(3)如果两个属性的关系是1对1,则它们互相函数决定.
当使用1对1关系的属性建立数据库时,两个属性至少必须在一个关系中同时出现一次,由它们决定的其他属性(由两个属性中的一个函数决定的属性也由另外一个函数决定)也可以在该关系中.
40Oracle8i数据库开发与专业应用这些陈述在图2-13中的第一栏进行了总结,记录定义规则显示在图2-14中.
如果A和B之间的关系是1对1,它们会位于同一个关系中,例如R.
A决定B,B决定A,关系的关键字可以是A或B中的任意一个.
对于一个新关系C,如果它由A或B函数决定,则它可以加入到关系R中.
有1对1关系的属性至少在一个关系中出现一次,这是为了建立它们的等效关系.
图2-13三种类型的属性关系的总结2.
多对1属性关系如果属性A决定属性B,但属性B不决定属性A,则它们的数据值之间的关系为多对1.
一个关系要想在DK/NF中,其所有约束都必须为关键字和域所蕴涵,因此每个决定因素都必须是关键字.
如果A、B、C在同一关系中,且A决定B,则A必须是关键字(意味着它也决定C).
反过来,如果(A、B)决定C,则(A、B)必须是关键字.
在后一种情况下,不允许有其他函数依赖,如A决定B.
可以通过下述方式把这些陈述应用到数据库设计中:在构造关系时,如果A决定B,你能添加到该关系中的属性必须是由A决定的.
例如,把SID和Building放到一个称作STUDENT的关系中,就可以向该关系添加其他由SID决定的属性,如Sname.
但如果属性Fee由Building决定,就不能添加到该关系中.
只有当SIDFee(表示SID决定Fee)成立时,才能添加Fee.
这些陈述在图2-13的中间栏进行了总结.
如果C和D的关系为N∶1,它们在同一关系中,比如说S,则C决定D,但D不决定C.
S的关键字是C,其他属性如E,只有当C决定E时,才能添加到S中.
3.
多对多属性关系如果A不决定B,且B不决定A,则它们的数据值之间的关系是多对多.
这些在图2-13的右边一栏进行了总结.
如果E和F的关系为M∶N,E不决定F,F也不决定E.
E和F都可以置于关系T中,如果这样做,则关系T的关键字为(E,F)组合.
对于一个新的关系G,如果它依赖于整个(E,F),则它可以添加到关系T中,如它只是由E或F中的一个决定,则不能添加到关系T中.
4.
再论多值依赖关于多对多属性值关系的讨论使得多值依赖概念更容易理解.
图2-8中的STUDENT(SID,Major,Activity)的问题在于,它有两个不同的多对多关系.
一个是在SID和Major之间,另一个是在SID和Activity之间.
很显然,学生的不同专业和他或她的不同活动是没有关系的.
但是,把这两个不同的多对的多关系放在同一个关系中,看起来好像它们之间有某种联系.
第2章逻辑数据库的设计与实现41关于1∶1关系·有1∶1关系的属性必须至少同时在一个关系中出现.
回忆一下关系R和属性A与B.
·A和B中至少有一个是R的键.
·一个属性如果由A或B函数式决定,该属性就可加入到R中.
·一个属性如果不是由A或B函数式决定,则该属性不能加入到R中.
·A和B必须同时在R中出现,但不应在其他关系中同时出现.
·在除R以外的关系中,A或B应可以互相代表.
关于多对1关系·具有多对1关系的属性可以同时在一个关系中存在.
假定在关系S中C决定D.
·C必须是S的键.
·由C决定的属性可以加入到S中.
·不由C决定的属性不能加入到S中.
关于多对多关系·具有多对多关系的属性可以同时在一个关系中存在.
假定两个这样的属性E和F同时在关系T中存在.
·T的键必定是(E,F).
·由组合(E,F)决定的属性可以加入到T中.
·不是由组合(E,F)决定的属性不能加入到T中.
·如果加入新属性G,使键扩展为(E,F,G),那么关系的主题就发生了变化.
或者是G不属于T,或者是应改变T的名字以反映新的主题.
图2-14构造关系的规则的总结Major和Activity是相互独立的.
如果学生在这两者中都是只参加一个,就不会有什么问题,SID函数会决定Major和Activity,关系也就在DK/NF中.
在这种情况下,Major和Activity之间的关系以及Activity和SID之间的关系都是多对1关系.
另外一种理解困难的方法是考察关键字(SID,Major,Activity).
因为学生有多对多关系,所以所有的属性都应该是关键字的一部分.
这样一来,这个关键字标识什么主题我们可以说是学生的学习和活动的组合.
但这并不是一件事,它是复合的,关系的每一行只能描述该组合的一部分.
为了获得关于某个特定学生的全部情况,我们就需要关于该学生的所有行.
一般地讲,一行应该包含关系主题的一个实例的所有数据.
2.
2.
6设计折中本节考察了规范化的概念,并说明了如何在域/关键字范式中创建表.
我们所使用的过程一般是合适的,但有时规范化的结果却不值我们的花费.
下面我们将讨论这种情况发生的方式.
1.
反规范化正如你所知道的那样,规范化的关系避免了更新异常,因此它们更可取.
但是,根据其他理由来考察,规范化有时却不值得.
考虑关系CUSTOMER(CustNumber,CustName,City,State,Zip),其中,CustNumber是关键字.
该关系不在DK/NF中,因为它所包含函数依赖Zip-(City,State),它不被关键字CustNumber蕴涵.
因此,存在一个不被关键字的定义所蕴涵的约束.
42Oracle8i数据库开发与专业应用该关系可以转化为以下两个在DK/NF中的关系:CUSTOMER(CustNumber,CustName,Zip),其中,CustNumber是关键字.
CODE(Zip,City,State),其中,Zip是关键字.
这两个表在域/关键字范式中,但它们很可能并不是好的设计.
非规范化的表可能更好,因为它容易处理,而且City和State数据重复这一缺点也不严重.
总之,关系有时故意保留成非规范化的,或者规范化以后又反规范化了,这样做通常是为了改进性能.
无论何时,当数据必须从两个单独的表中组合起来时,DBMS就要做额外的工作.
大多数情况下,至少需要读两次,而不是一次.
2.
优化典型地方法是,我们通过把非规范化的表分解两个或多个表来创建规范化的表.
有些情况下,还有更好的方法可以获取规范化的设计.
例如,考虑关系COLLEGE(CollegeName,Dean,AssitantDean).
假定一个学院只有一个院长,有1~3个主力院长.
此时,该表的关键字是(CollegeName,AssitantDean),且不在域/关键字范式中,因为约束CollegeNameDean不是该表的关键字的逻辑结果.
COLLEGE可以规范化成DEAN(CollegeName,Dean)和ASSISTANT-DEAN(College-Name,AssitantDean).
但是,现在无论何时,当数据库需要获取关于学院的信息时,它至少要读两行数据,也可能是四行数据.
这个设计的一个替换方案就是在COLLEGE表中放置三个AssistantDean,每个都是一个单独的属性.
这样,表就变成了COLLEGE1(College,Dean,AssistantDean1,AssistantDean2,AssistantDean3).
COLLEGE1在域/关键字范式中,因为它的所有属性都函数依赖于关键字CollegeName,但却丢失了一些信息.
为了知道丢失了什么信息,假定你想确定一个助理院长叫"MaryAbernathy"的COLLEGE的名字.
为此,你需要在三个AssistantDean栏中寻找这个值,你的查询将是这样:SELECTCollegeNameFROMCOLLEGE1WHEREAssistant1='MaryAbernathy'ORAssistant2='MaryAbernathy'ORAssistant3='MaryAbernathy'OR使用有ASSISTANT-DEAN的规范化设计,你只需说明:SELECTCollegeNameFROMASSISTANT-DEANWHEREAssistantDean='MaryAbernathy'在这个例子中,有三种可能的方案,每种都有优点和缺点.
在它们之间作出选择是非常有艺术性的,没有什么牢固可靠的准则表明如何在它们之间作出抉择.
最好的选择取决于使用该数据库的应用的处理特点.
2.
3用实体联系模型设计数据库本节说明如何把用实体联系模型表示的用户需求转化成关系数据库设计,这种设计独第2章逻辑数据库的设计与实现43立于任何特定的DBMS.
主要有两个部分,第一部分讨论如何把实体联系数据模型转化为关系设计.
规范化对这一过程是非常重要的,因为实体可以包含一个语义主题.
在说明如何表示实体后,我们考察使用关系模型对关系的表示.
第二部分应用第一部分描述的概念,阐述如何把实体联系模型转化为四个公共数据库结构的表示.
这些结构是E-R构件的特例,第一部分中的技术和关系一起可用来表示它们.
我们之所以给这些结构以特别的注意,只是因为它们作为实体和关系的公共模式经常出现.
2.
3.
1实体联系模型到数据库设计的转换在第一章中我们说明了如何在实体联系模型中表达用户需求.
使用这个模型,用户需要跟踪的事物用实体表示,实体之间的关系由明确定义的关系来表示.
正如在E-R模型中所定义的那样,关系的元可以是任意的,但我们同时又指出,实际数据库管理中经常遇到的关系的元为2,或称作二元关系.
本小节讨论如何把实体和二元关系转化为关系模型的术语.
1.
使用关系模型表示实体一般地讲,使用关系模型表示实体是很直接的.
首先,我们把每个实体定义为一个关系,关系的名字就是实体的名字,关系的属性就是实体的属性.
然后,我们根据前面所讨论的规范化准则检查每个关系,初始的设计可能需要改变,也可能不需要改变.
如图2-15所示的例子.
CUSTOMER实体包含以下属性:CustNumber、CustName、Address、City、State、Zip、ContactName和PhoneNumber.
为了用关系表示该实体,我们为该实体定义一个关系,并把实体的属性作为关系的各列.
如果我们从数据模型知道哪个属性标识该实体,则该属性就是关系的关键字.
否则,我们必须询问用户或调查需求来确定哪个属性或哪些属性可以标识一个实体.
这里,我们假定CustNumber是关键字,在本图和以后的各个图中,关系的关键字是有下划线的.
(1)规范化的作用在需求阶段,对实体的唯一约定就是它对用户是重要的,没有做任何尝试来确定该实体是否符合前面所讨论的规范化准则.
因此,一旦为一个实体定义了关系,就应该根据规范化准则对该关系的关键字进行检查.
例如,考虑图2-15(b)中的CUSTOMER关系.
它在DK/NF中吗为了弄清这个问题,我们需要知道该关系的约束.
没有一个基本需求的完整描述,我们无法知道所有的约束,如所有的域约束.
但我们可以从属性名和关于事务特点的知识中发现一些需求.
CUSTOMERentitycontainsCustNumberCustNameAddressCityStateZipContactNamePhoneNumber(a)(b)图2-15用关系表示实体(a)CUSTOMER实体;(b)表示实体CUSTOMER的关系.
CUSTOMER(CustNumber,Address,City,State,Zip,ContactName,PhoneNumber)44Oracle8i数据库开发与专业应用首先,CustNumber决定所有其他属性,因为从一个给定的CustNumber值,我们可以确定唯一的CustName、Address、City、State、Zip、ContactName和PhoneNumber值.
但是,还有其他一些来自其他函数依赖的约束,Zip决定City和State,ContactName决定PhoneNumber.
如前面所述,要建立在DK/NF中的关系,我们必须使其他的函数依赖成为域或关键字的逻辑结果.
通过定义如图2-16所示的三个关系,可以达到一个目标,其中,CUSTOMER的关键字是CustNumber,ZIP-TABLE的关键字是ContactName.
CUSTOMER(CustomerNumber,Address,Zip,ContactName)ZIP-TABLE(Zip,City,State)CONTACT(ContactName,PhoneNumber)Interrelationconstraints:ZipinCUSTOMERmustexistinZipinZIP-TABLEContactNameinCUSTOMERmust=aContactNameinCONTACT图2-16使用在域/关键字范式中的关系表示客户实体图2-16中的设计在DK/NF中,因此没有修改异常.
就是说,我们在增加一个新的邮政编码和新的接洽对象时,不必增加一个含有新邮政编码或接洽对象的客户;此外,当删除一个给定的邮政编码对应的最后一个客户时,我们并没有因此而丢失该邮政编码所对应的城市和州.
但正如我们前面所指出的,这个设计太纯、太零碎了,以至于很难使用.
在这个例子中,初始的CUSTOMER关系更可取.
尽管它包含修改异常,但这并不很重要.
例如,如果某公司不是CUSTOMER,可能就不需要保留该公司的接洽对象的电话号码.
就是说,如果Jones所在的公司不是客户,我们就不需要知道Jones的电话号码是5551234.
但是,在另外一些例子中,很明显DK/NF设计更可取.
考虑图2-17中SALES-COMMISSION实体,如果我们如图2-17(b)中那样试图用一个关系表示该实体,结果就是一堆乱糟糟的有很多修改异常的属性.
SALES-COMMISSION(SalespersonNumber,SalespersonName,Phone,CheckNumber,CheckDate,CommissionPeriod,TotalCommissionSales,CommissionAmount,BudgetCategory)Functionaldependencies:CheckNumberiskeySalespresonNumberdeterminesSalespersonName,Phone,BudgetCategory(SalespresonNumber,CommissionPeriod)determinesTotalCommissionSales,CommissionAmount(b)SALESPERSON(SalespersonNumber,SalespersonName,Phone,BudgetCategory)SALES(SalespersonNumber,CommissionPeriod,TotalCommissionSales,CommissionAmount)COMMISSION-CHECK(CheckNumber,CheckData,SalespersonNumber,CommissionPeriod)(c)图2-17规范化得比较好的实体(a)实体SALES-COMMISSION;(b)使用单个关系表示SALES-COMMISSION;(c)使用域/关键字范式中的关系表示SALES-COMMISSION.
SALES-COMMISSIONentitycontainsSalespersonNumberSalespersonNamePhoneCheckNumberCheckDateCommissionPeriodTotalCommissionSalesCommissionAmountBudgetCategory(a)第2章逻辑数据库的设计与实现45这个关系明显包含多个主题.
检查以下就会发现,它所包含的一个关于销售员的主题、一个关于某一段时间内销售情况的主题和一个关于销售委托检查的主题.
表示该实体的在DK/NF中的关系如图2-17(c)所示.
从直观上看,该设计优于图2-17(b)中的设计,它更直观、更合适.
总结一下到目前为止的讨论,使用关系模型表示实体时,第一步是建立以实体的所有属性作为关系的属性列的关系,然后根据规范化准则对关系进行检查.
在很多情况下,可以通过开发一个在DK/NF中的关系集来改进设计.
但是,DK/NF关系并不总是可取.
如果关系是发明出来的,且难以使用,这时非DK/NF关系可能更好.
性能也是一个考虑因素,访问两个或三个关系来获取所需要的客户数据,所花费的时间可以承受.
不管关于是否规范化的最终决定如何,我们都应该根据规范化准则来检查实体转化成的关系.
就是说,无论我们如何做,都应该为此作出一个明确的情形的决定.
在这个过程中,我们可以了解到关系容易遇到的各种类型的修改异常.
(2)弱实体的表示在讨论E-R模型的关系的表示以前,考虑一下弱实体的表示.
弱实体的存在依赖于其他实体.
如果弱实体不是ID(名字)依赖的,则它可以用前面所描述的技术来表示.
但是这种存在依赖需要在关系设计中进行记录,以防止应用产生没有合适父实体(弱实体所依赖的实体).
此外,需要实现一个处理约束,使得在父实体被删除时,弱实体也被删除.
这些规则应该在设计中进行描述.
如果弱实体是ID依赖的,情况就略有不同.
在图2-18(a)中,LINE-ITEM是一个ID依赖的弱实体.
它之所以是弱的,是因为它的存在依赖于INVOICE,是没有从INVOICE分离开的名字.
如果我们为LINE-ITEM建立一个关系,关系的属性和实体的属性相同,考虑一下,会发生什么情况这个关系如果2-18(b)所示.
由于弱实体依赖于其他实体,所以没有完整的关键字.
实际上,这个关系肯定会有重复行(如果两张发票在相同的行有相同数量的相同物品,这种情况就出现了).
问题在于图2-18(b)中的关系没有唯一的标识符.
(a)LINE-ITEM(LineNumber,Qty,ItemNumbre,Description,Price,Extprice)(b)LINE-ITEM(invoiceNumber,LineNumber,Qty,ItemNumber,Description,Price,ExtPrice)(c)图2-18弱实体的关系表示(a)弱实体的例子;(b)没有关键字的LINE-ITEM关系表示;(c)有正确的关键字(一部分来自INVOICE)的LINE-ITEM的关系表示.
对于ID依赖的弱实体,需要在对应弱实体的关系中增加父实体的关键字,这个增加的属性就成了弱实体的关键字的一部分.
因此,在图2-18(c)中,我们把INVOICE的关键字InvoiceNumber增加到LINE-ITEM的属性中,则LINE-ITEM的关键字为(InvoiceNumber,INVOICELINE-ITEM1∶N46Oracle8i数据库开发与专业应用LineNumber).
对于表示ID依赖的弱实体的关系,其关键字总是组合的.
下面考虑E-R模型中的关系表示.
2.
表示二元HAS-A关系E-R模型中有两种类型的关系:不同逻辑类型的实体之间的HAS-A关系和公共逻辑类型的子类实体之间的IS-A关系.
(1)表示1对1关系二元关系的最简单的形式是1对1,它表示一种类型的实体和不超过一个的其他类型的实体的关联.
在EMPLOYEE和AUTO例子中,假定一个雇员刚好分配一辆汽车,一辆汽车刚好分配给一个雇员,则这个关系的E-R图如图2-19所示.
图2-191:1关系的例子使用关系模型表示1对1关系是非常直观的,首先,每个实体用一个关系表示,然后将一个关系的关键字置于另外一个实体中.
在图2-20(a)中,EMPLOYEE的关键字存储在AUTO中,在图2-20(b)中,AUTO的关键字存储在EMPLOYEE中.
一个关系的关键字存储在另一个关系中时,称作另一个关系的外键.
在图2-20(a)中,EmployeeNumber是AUTO中的外键,在2-20(b)中,LicenseNumber是EMPLOYEE中的外键.
在该图中,外键用斜体字表示,但有时也会看到用下划虚线表示的外键.
还有一些情况下,外键不特殊指明.
对于1:1关系,任意一个表的关键字都可作为另一个表的外键.
在图2-20(a)中,外键EmployeeNumber置于AUTO中.
通过这个设计,我们可以从EMPLOYEE向AUTO导航或从AUTO向EMPLOYEE导航.
在第一种情况下,有一雇员,需要查找分配给该雇员的汽车.
为了获取雇员的数据,我们使用EmployeeNumber在EMPLOYEE中找到对应该雇员的行,从该行中,我们获取分配给该雇员的汽车的LicenseNumber.
然后,使用这个标号在AUTO中查找汽车数据.
EMPLYEE(EmployeeNumber,EmployeeName,Phone,…)AUTO(LicenseNumber,SerialNumber,Color,Make,Model,…EmployeeNumber)(a)EMPLOYEE(EmployeeNumber,EmployeeName,Phone,…LicenseNumber)AUTO(LicenseNumber,SerialNumber,Color,Make,Model,…)(b)图2-20表示1:1关系的两种可替换的方式(a)把EMPLOYEE的关键字置于AUTO中;(b)把AUTO的关键字置于EMPLOYEE中.
现在来看另一个方向.
假定我们有一辆汽车,需要查找所分配的雇员.
使用图2-20(a)中的设计,我们访问EMOLPYEE表,并查找所有给定汽车执照号的行,该汽车所分配的雇员的数据就在这一行中.
对于另外一种外键LicenseNumber置于EMPLOYEE中的设计,我们可以采用类似的行为在任意一个方向上导航.
对于使用这个设计从EMPLOYEE向AUTO导航,我们直接EMPLOYEEAUTO1∶1第2章逻辑数据库的设计与实现47在AUTO关系中查找以给定EmployeeNumber作为雇员编号值的行.
对于从AUTO向EMPLOYEE导航,我们在AUTO中查找给定LicenseNumber的行.
在该行中,我们取出EmployerNumber,并用它来访问EMPLOYEE中的雇员数据.
这里,我们使用"查找"这个术语意味着"给定一列的值,在表中查找一行".
尽管图2-20的两个设计在概念上是等效的,但它们在性能上可能是不同的.
例如,如果某一方向的查询比另一方向更经常发生,那么我们会喜欢这种设计,而不喜欢另一种设计.
同样,如果DBMS产品按主关键字查找比按外键查找更快,我们也会喜欢这种设计,而不喜欢另一种设计.
图2-21显示了另一个1:1关系.
其中,每个EMPLOYEE有一个JOB-EVALUATION,每个JOB-EVALUATION对应一个特定的EMPLOYEE.
从图中的脉冲符号可以看到,两个方向的关系都是强制性的.
当一个1:1关系的两个方向都是强制性的时,记录很可能是描述同一实体的不同方面.
特别是,如果像图2-21那样,两个实体的关键字相同,则这些记录应该置于一个关系中.
试着用怀疑的态度来考虑这种1:1强制性关系.
图2-21有疑问的1:1关系把一个关系分解成两个关系有时是正当的.
一个正当理由是关于性能的考虑,例如,假定JOB-EVALUATION数据很长,且使用频率比其他雇员数据低得多,这种情况下,把JOB-EVALUATION存储在一个单独的表中,使得关于雇员数据更频繁的请求处理得更快,就是一个合适的方案.
把两个记录分开的第二个理由是更好的安全性保障.
如DBMS不支持数据项级的安全保障,JOB-EVALUATION数据就需要分开存储,以防止非法用户的访问.
也可能希望把JOB-EVALUATION置于一个单独的表中,使得该表能够置于磁盘介质上,然后将该磁盘介质保存在特殊的上锁的设备中.
不要从这些讨论中得出所有1:1关系都不合适的结论,只有那些描述同一实体的不同方面的关系有问题.
例如,EMPLOYEE和AUTO之间的1:1强制关系是非常合适的,因为每个关系描述不同的实体.
(2)表示1对多关系第二种类型的二元关系是1对多关系,它表示一种类型的一个实体和多个其他类型的实体的关联.
图2-22是教授和学生之间的1对多关系的E-R图.
在该关系中,一个PROFESSOR和多个他所指导的STUDENT相关联.
椭圆表示PROFESSOR和STUDENT之间的关系是可选的,就是说,教授不一定指导学生.
另一端穿越横线的线表示一个STUDENT行必须对应一个PROFESSOR行.
父节点和子节点这两个术语有时用于1对多关系,父关系在"1"那一侧,子关系在"多"那一侧.
在图2-22(a)中,PROFESSOR是父节点实体,STUDENT是子节点实体.
图2-22还显示了两个其他的1对多关系,在图2-22(b)中一个DORMITORY实体对应多个STUDENT实体,但一个STUDENT实体只对应一个DORMITORY实体.
此外,DORMITORY不一定分配STUDENT,STUDENT也不一定非要住在DORMITORY中.
在图2-22(c)中,一个CUSTOMER和多个APPOINTMENT关联,一个APPOINTMENTEMPLOYEEJOB-EVALUATION1∶148Oracle8i数据库开发与专业应用只对应于一个CUSTOMER.
此外,CUSTOMER不一定有APPOINTMENT,但每个APPOINTMENT必须对应一个STUDENT.
(a)(b)(c)图2-221对多关系的例子(a)一端可选对一端强制的1:N关系;(b)两端都为可选的1:N关系;(c)有弱实体的1:N关系.
1:N关系的表示是简单而又直观的.
首先,一个实体由一个关系表示,然后将代表父实体的关系的关键字置于代表子实体的关系中.
因此,为了表明图2-22(a)中的ADVISES关系,我们将PROFESSOR的关键字ProfessorName置于STUDENT关系中,如图2-23所示.
图2-23有时称作数据结构图,其中,关系显示在长方形内,用线表示关系,关键字属性有下划线.
关系线上的"叉"或"鸡爪"表示"多"关系.
在图2-23中,关系线的STUDENT一端的叉,表示对于一个PROFESSOR,可以有多个STUDENT.
另一端没有叉表示一个STUDENT至多由一个PROFESSOR指导.
和E-R图一样,脉冲线用来表示强制关系,椭圆表示可选关系.
图2-23图2-22(a)中的PROFESSOR和STUDENT实体的关系表示注意,通过把ProfessorName作为外键存储在STUDENT中,我们在两个方向上处理关系.
给定一个StudentNumber,我们可以在STUDENT中查找合适的行,从该行中取出他或他的导师.
要获得其余的PROFESSOR数据,我们使用从STUDENT中获得的教授姓名在PROFESSOR中查找合适的行.
要想确定某个特定的教授指导的所有学生,我们首先在表STUDENT中查找以该教授的姓名作为ProfessorName值的行,然后从这些行中可取得学生的数据.
这种情况和1:1关系的表示相比较,在两种情况下,我们都把一个关系的关键字存储在第二个关系中作为外键.
在1:1关系中,把哪个关系的关键字移到第二个关系中无关紧要.
但在1:N关系中,这一点则很重要,必须把父关系的关键字置于子关系中.
为了更好地理解这一点,注意一下如果我们把子关系的关键字置于父关系中将会发生PROFESSORSTUDENT1:NDORMITORYSTUDENT1:NCUSTOMERAPPOINTMENT1:N第2章逻辑数据库的设计与实现49什么.
因为关系的属性只能有单个值,所以在任意一个教授记录中只能有一个学生,因此,这种结构不能用来表示1:N关系中的"多"的一侧.
这再一次表明,要表示1:N关系,我们需要把父关系的关键字置于子关系中.
图2-24显示了CUSTOMER和APPOINTMENT实体的表示.
这里,每个实体用一个关系表示.
如前所述,APPOINTMENT是一个ID依赖的弱实体,因此它的关键字是组合关键字,包含它所依赖的实体的关键字和它自己的一个或多个属性.
这里,关键字是(CustomerNumber,Date,Time).
现在,我们来表示1:N关系.
通常是把父关系的关键字添加到关系中,但是,此时父关系的关键字(CustomerNumber)已经是子关系的一部分了,因此我们不需要再添加,关系也已经表示出来了.
图2-24图2-22(c)中的弱实体的关系表示(3)表示多对多关系第三种或最后一种类型的二元关系是多对多关系.
该关系表示一种类型的一个实体对应于第二种类型的多个实体,且第二种类型的实体也对应于第一种类型的多个实体.
图2-25(a)显示了学生和课程之间的多对多关系的E-R图.
一个STUDENT实体可对应多个CLASS实体,一个CLASS实体可对应于多个STUDENT实体.
注意,关系的两个参与者都是可选的:学生不一定选某门课,某门课也不一定有学生选.
图2-25(b)给出了样本数据.
图2-25M:N关系的例子(a)STUDENT对CLASS关系的E-R图;(b)STUDENT对CLASS的样本数据.
多对多关系不能像1对1和1对多关系那样直接用关系表示.
要理解其原因,可以试着像处理1:1关系和1:N关系一样,把一个关系的关键字置于另一个关系中.
首先,为每50Oracle8i数据库开发与专业应用个实体定义一个关系,称作STUDENT和CLASS.
现在试着把STUDENT的关键字(StudentNumber)置于CLASS中.
因为关系的单元格中不允许多值,所以我们只能放置一个StudentNumber,这样,我们无法处理选该课的第二个学生.
如果我们试图把CLASS的关键字(ClassNumber)置于STUDENT中,就会发生同样的问题.
我们可以很容易地存储一个学生选修的第一门课的标识,但却无法存储第二门课的标识符和其他课的标识符.
图2-26显示了另一种(但不正确)策略.
在这种情况下,我们在CLASS关系中为每个参加某课程的学生存储了一行,因此,课程10和课程30各有两条记录.
这种模式的问题在于,我们重复了课程数据,因而产生了修改异常.
图2-26一个M∶N关系的不正确表示如果课程10的计划修改了,那么许多行需要变化.
同样,考虑一下插入异常和修改异常:我们无法在有学生选某课程之前排定该课程的计划;如果学生300退出课程40,会导致课程40信息的丢失.
解决这种困境的方法是建立第三个关系,它是用来表示多对多关系本身的.
这种关系的一个实例如图2-27所示,即学生和课程之间的对应关系.
这种关系称作交叉关系,因为关系的每一行记录了一个特定学生和一个特定课程的交叉.
注意,对应图2-25(b)中的STUDENT和CLASS关系的每条线,在图2-27(b)中,就有一行交叉关系.
图2-27M:N关系的表示(a)用来表示STUDENT对CLASS关系的关系;(b)STUDENT对CLASS关系的例子数据.
第2章逻辑数据库的设计与实现51STUDENT-CLASS关系的数据结构图如图2-28所示,从CLASS到STU-CLASS的关系是1:N,从STUDENT到STU-CLASS的关系也是1:N.
实际上,我们是把M:N关系分解成了两个1:N关系.
STU-CLASS的关键字是它的两个父关系的关键字的组合,即(StudentNumber,ClassNumber).
交叉关系的关键字总是其父的关键字的组合.
图2-28STUDENT对CLASS关系的数据结构图3.
表示递归关系递归关系是指同一类实体之间的关系.
递归关系和HAS-A关系并没有本质的不同,可以使用同样的技术来表示.
唯一复杂之处在于递归关系中的实体是和自己类中的实体发生关联.
和非递归HAS-A关系一样,递归关系有三种类型:1:1、1:N和M:N.
图2-29显示每种类型的一个例子.
图2-29递归关系的例子(a)1∶1递归关系;(b)1∶N递归关系;(c)M∶N递归关系.
首先考虑图2-29(a)中的SPONSOR关系,和1:1关系一样,一个人资助其他人,每个人由不多于一个人资助.
图2-30(a)显示了该关系的样本数据.
为了表示1:1递归关系,我们采用一个和1:1规则关系近似相同的方法.
我们可以把被资助的人的关键字置于资助者的行中,或者把资助者的关键字置于被资助者的行中,图2-30(b)显示了第一种选择,2-30(c)显示了第二种选择.
两种选择都可以,最终的选择取决于性能之类的问题.
图2-301:1递归关系的例子(a)1:1递归关系的样本数据;(b)表示1:1递归关系的第一种选择;(c)表示1:1递归关系的第二种选择.
52Oracle8i数据库开发与专业应用除了父关系的行和子关系的行在同一个关系中外,这个技术和非递归1:1关系是相同的.
可以这样考虑该过程:假定关联是在两个不同的关系之间,确定关键字的走向,然后把两个关系组合成一个关系.
为了说明问题,考虑图2-29(b)所示的REFERRED-BY关系.
如图2-31(a)中的样本数据所示,这是一个1:N关系.
当这些数据置于一个关系中时,一行表示参照者,其他行表示被参照者.
参照者扮演父关系的角色,被参照者扮演子关系的角色.
和所有的1:1关系一样,我们把父关系的关键字置于子关系中.
在图2-31(b)中,我们把参照者的名字置于所有被参照行中.
图2-311:N递归关系的例子(a)关系REFERRED-BY的样本数据;(b)用关系表示1:1递归关系.
现在考虑M:N递归关系,考察图2-29(c)所示的TREATED-BY关系,其样本数据显示在图2-32(a)中.
和其他M:N关系一样,我们必须建立显示所有的医生配对的交叉关系表.
第一列中的医生名字是提供治疗的医生名字,第二列中的病人名字是接受治疗的病人的名字,该结构如图2-32(b)所示.
递归关系和其他关系的表示方式相同,但是,表的行可以扮演两种不同的角色.
某些是父关系行,其他是子关系行.
如果关键字被假定为父关系的关键字,且某行没有父亲,则它的值为空.
如果关键字被假定为子关系的关键字,且某行没有子女,则其值为空.
图2-32M∶N递归关系的例子(a)关系TREATED-BY的样本数据;(b)用关系表示M∶N递归关系.
4.
表示IS-A关系(子类)表示子类或IS-A关系的策略与表示HAS-A关系的策略有所不同.
考虑例子CLIENT,其属性为ClientNumber、ClientName和AmountDue.
假定CLIENT有三个子类,即INDIVIDUAL-CLIENT、PARTNERSHIP-CLIENT和CORPORATE-CLIENT,其属性分别如下:第2章逻辑数据库的设计与实现53INDIVIDUAL-CLIENT:Address,SocialSecurityNumberPARTNERSHIP-CLIENT:ManagingPartnerName,Address,TaxIdentificationNumberCORPORATE-CLIENT:ContactPerson,Phone,TaxIdentificationNumber为了用关系表示这个结构,我们为超类(CLIENT)和每个子类各定义一个关系,然后把超类的属性和子类的属性都分别置于表示它们的关系中.
这里,子类没有关键字,为了创建一个关键字,把超类的关键字(ClientNumber)添加到子类中.
最终的关系表如下:CLIENT(ClientNumber,ClientName,AmountDue)INDIVIDUAL-CLIENT(ClientNumber,Address,SocialSecurityNumber)PARTNERSHIP-CLIENT(ClientNumber,ManagingPartnerName,Address,TaxIdentificationNumber)CORPORATE-CLIENT(ClientNumber,ContactPerson,Phone,TaxIdentificationNumber)注意,在该结构中,CLIENT中的行和子类中的行之间的对应关系是1:1,任何客户在子类关系中都不超过一行,每个子类都唯一地对应超类中的一行.
应用的约束情况不同,CLIENT中的一行也有可能对应多行,每一行属于一个不同的子类.
但是,CLIENT的一行不可能对应同一子类关系中的多行.
子类也可能有自己的关键字.
例如,应用可能要求一个区别于ClientNumber的CorporateClientNumber.
此时,CORPORATE-CLIENT的关键字就是CorporateClient-Number.
因为CLIENT和CORPORATE-CLIENT之间的关系为1:1,所以通过把其中一个关系的关键字置于另一个关系中,即可完成其关系的表示.
从审美学的角度来看,通常认为把超类关系的关键字置于子类关系中更好.
对于本例,CORPORATE-CLIENT的结构为:CORPORATE-CLIENT(CorporateClientNumber,ClientNumber,ContactPerson,Phone,TaxIdentificationNumber)下面我们看一个例子.
如图2-33(a)所示,它包含E-R图使用的所有基本要素.
为了用关系表示该图,我们首先为每个实体建立一个关系.
假定各个关系的关键字如下:关系关键字EMPLOYEEEmployeeNumberENGINEEREmployeeNumberTRUCKLicenseNumberSERVICEInvoiceNumberCLIENTClientNumberENGINEER-CERTIFICATION(EmployeeNumber,CertificationName)CERTIFICATIONCentificationName下一步是根据规范化准则来检查各个关系.
这个例子并没有告诉我们什么属性必须表示,因此我们无法确定约束.
我们假定所有的关系都在DK/NF中,尽管在实际情况下,我们还需要根据属性列表和约束考证假设.
现在,我们集中讨论关系的表示,得到的关系和关键字属性(包括外键)如图2-33(b)所示.
EMPLOYEE和ENGINEER两个关系都有相同的关键字EmployeeNumber,所以它们之54Oracle8i数据库开发与专业应用EMPLOYEE(EmployeeNumber,othernonkeyEMPLOYEEattributes…)ENGINEER(EmployeeNumber,othernonkeyENGINEERattributes…)TRUCK(LicenseNumber,othernonkeyTRUCKattributes,EmployeeNumber)CLIENT(ClientNumber,othernonkeyCLIENTattributes,ReferredBy)SERVICE-CLIENT(InvoiceNumber,ClientNumber,Fee)ENGINEER-CERTIFICATION(EmployeeNumber,CertificationName,othernonkeyENGINEER-CERTIFICATIONattributes)CERTIFICATION(CertificationNumber,othernonkeyCERTIFICATIONattributes)(b)图2-33一个E-R图例子的关系表示(a)一个E-R图;(b)表示该E-R图需要的关系.
间的关系已经表示出来了.
ENGINEER和TRUCK之间的关系为1:1,因此,可以通过把一个关系的关键字置于另一个关系中来表示关系.
因为一辆卡车必须分配给一个雇员,所以我们将EmployeeNumber置于TRUCK中,不会有空值出现.
对于ENGINEER和SERVICE之间的1:N关系,我们将ENGINEER(父关系)的关键字置于SERVICE(子关系)中.
SERVICE和CLIENT之间的关系为M:N,所以我们必须建立一个交叉关系,因为这个多对多关系有一个属性Fee,所以我们将该属性添加到交叉关系中.
对于1∶N递归关系REFERRED-BY,我们把属性ReferredBy添加到CLIENT中.
ReferredBy的正确意思是父关系(进行参照的客户)的关键字被置于该关系中.
因为ENGINEER-CENTIFICATION是ID依赖于ENGINEER,所以我们知道EmployeeNumber必须是它的关键字的一部分,因此它的关键字是(EmployeeNumber,CertificationName)组合.
由于依赖关系是1:N,所以主要取决于EmployeeNumber.
最后,CERTIFICATION和ENGINEER-CENTIFICATION之间的关系是1:N,因此通常要把CENTIFICATION(父关系)的关键字添加到ENGINEER-CENTIFICATION中,但父关系的关键字已经是关系的一部分了,所以我们不需要这样做.
E-R模型的所有要素都显示在该图中了,通过仔细研究这个例子,我们可以理解不同第2章逻辑数据库的设计与实现55类型的关系和它们是如何用关系表示的.
2.
3.
2树、网络和材料单尽管E-R模型没有对实体之间的关系模式作任何假设,但其中的某些关系模式出现得非常频繁,所以人们就给它们取了一些特殊的名字.
这些关系模式是树、简单网络、复杂网络和材料单.
这里,我们把这些模式的概念和E-R模型一起介绍.
1.
树树有时又称作层次.
它是一种数据结构,结构中的元素之间只有1对多关系,每个元素至多有一个父节点.
图2-34是一个树的例子.
根据标准术语,每个元素称作一个节点,元素之间的关系称作树枝,树顶的节点称作树根,图2-34中,节点1是树根.
图2-34树的例子除了根以外,树的每个节点都有父节点,它就是紧靠该节点上部的节点.
因此,节点2是节点5的父节点,节点4是节点8的父节点等等.
如前所述,树和其他数据结构的区别在于树的每个节点最多只有一个父节点.
节点的后代称作子节点.
一般地讲,一个节点可有的子节点个数是没有限制的.
节点2有两个子节点5和6,节点3没有子节点,节点4有三个子节点7、8和9.
父节点相同的节点称作孪生子或兄弟,例如节点5和6.
图2-35显示了一个大学系统中的实体树,从中可以看到实体之间的几个1对多关系.
一个学院包含多个系,一个系有多个教授和多个管理人员.
最后,一个教授指导多个已经获得学分的学生.
该结构虽然有六种不同的实体类型,但所有的关系都是1:N.
要使用关系模型表示实体树,我们只需应用前面讨论的概念即可.
首先,我们把每个实体转化为关系,然后根据规范化准则检查所产生的每个关系,如果需要,则将关系分解.
通过把父关系的关键字置于子关系中,我们就把1:N关系表示出来了.
图2-35(b)是对应图2-35(a)的树的数据结构图.
总之,层次或树是按照1:N关系组织起来的记录的集合,除了根以外,所有记录都恰好有一个父节点.
使用前面定义的方法,可以用一个关系集合来表示层次.
层次结构在事务中经常使用,特别是在制造业的应用中.
2.
简单网络简单网络也是一种其中元素只有1对多关系的数据结构.
但是,在简单网络中,只要父节点的类型不同,一个元素就可以有多于一个的父节点.
例如,在图2-36所示的简单网络中,每个STUDENT有两个父节点,即一个ADVISER实体和一个MAJOR实体.
图2-35中的数据结构之所以不是树,是因为STUDENT实体有多于一个的父节点.
56Oracle8i数据库开发与专业应用图2-35用关系表示树(a)由实体组成的树;(b)用关系表示该树.
图2-36简单网络的例子图2-37(a)是这个简单网络的一般结构.
注意,所有的关系都是1对多,但STUDENT有两个父节点.
在这个图中,父节点记录在上部,子节点记录在它们的下面.
这种安排很方便,但却不是必须的,你可能会看到父节点在子节点的侧面或下面的简单网络.
对于这样的安排,根据有一个记录类型作为子节点参加两个(或多个)1对多关系的事实,我们就可以识别一个简单网络.
要用关系表示简单网络,我们可以遵循前面的过程来进行.
首先,把每个实体都转换为关系,如果需要,就对关系进行规范化.
然后,通过把父关系的关键字置于子关系中来表示每个1:N关系.
对图2-37(a)进行这一过程的结果如图2-37(b)所示.
图2-37用关系表示简单网络(a)由实体组成的简单网络;(b)用关系表示该简单网络.
第2章逻辑数据库的设计与实现573.
复杂网络复杂网络是其中至少有一个多对多关系的数据结构.
图2-38(a)中的复杂网络说明了发票、各行条目、部件和供货商之间的关系,三个关系中有两个是1:N关系,第三个是M:N关系.
因为至少有一个多对多关系,所以该结构是复杂网络.
正如我们刚刚指出的,M:N关系在关系模型中没有直接表示.
在以关系的形式存储这种结构之前,我们需要定义一个交叉关系.
在图2-38(b)中,交叉关系是PART-SUPPLIER.
图2-38用关系表示复杂网络(a)由实体组成的复杂网络;(b)用关系表示复杂网络.
4.
材料单材料单是一种经常在制造业的应用中出现的数据结构.
实际上,20世纪60年代,这种结构为数据库技术的开发提供了主要动力.
图2-39是一个材料单的例子,它显示了构成产品的部件.
当从一个给定产品的角度来看时,比如说是产品A,该结构是一个层次.
但是,由于一个部件可以用于一个以上的产品,所以这种结构实际上是网络.
例如,部件ABC100有两个父节点,即产品A和B.
图2-39材料单的例子58Oracle8i数据库开发与专业应用用关系表示材料单有几种方式,最经常的是把它看作M:N递归关系.
一个部件(或产品,或组件,或子组件,或任何其他东西)包含许多元素,同时,又有许多元素包含它.
图2-40(a)显示了M:N递归关系的一般数据结构,图2-40(b)显示了为表示该材料单而建立的交叉关系的一个实例.
综上所述归纳如下:为了转化实体联系模型,我们把每个实体都表示为关系,实体的属性也称为关系的属性.
关系一旦建立,就必须根据规范化准则进行检查,如果需要,就将一个关系分解成两个或多个关系.
图2-40用关系表示材料单(a)表示材料单的关系;(b)ELEMENT-RELATIONSHIP交叉关系的数据.
E-R模型中有三种类型的HAS-A关系:1:1、1:N和M:N.
为了表示M:N关系,我们建立一个包含两个关系的关键字的交叉体系.
递归关系的参与者来自同一实体,它包含1:1、1:N和M:N三种类型.
各种类型的表示方法与非递归关系相同.
对于1:1关系和1:N关系,我们在表示实体的关系中添加一个外键.
对于M:N递归关系,我们建立一个表示M:N关系的交叉表.
超类和子类实体(IS-A关系)也可以用关系表示.
一个关系是为超类定义的,其他关系是为各个子类定义的.
通常各关系的关键字相同,各个关系的行之间的关系是通过这些关键字来定义的.
如果关键字不同,则可以把超类关系的关键字置于子类关系中,或把子类关系的关键字置于超类关系中.
但通常是把超类关系的关键字置于子类关系中.
二元关系可以组合起来变成三种更复杂的结构.
树是记录类型的结合,其中,除了根没有父节点以外,每个记录恰好有一个父节点.
在简单网络中,记录可以有多个父节点,但父节点必须是不同类型的.
在复杂网络中,记录可以有多个同一类型的父节点.
材料单是一种在制造业应用中经常看到的数据结构,这种结构可以用M:N递归关系表示.
2.
4逻辑数据库的实现:物理数据库的设计2.
4.
1关于应用类型在学习物理数据库设计以及以后进行的性能调整之前,了解主要的应用类型是很重要第2章逻辑数据库的设计与实现59的.
首先,考虑术语"事务"和"查询".
在数据库理论中,广义地讲,事务(transaction)就是一个单一的、原子的SELECT、INSERT、UPDATE或DELETE语句.
但是,考虑到应用类型,事务被更为宽松地定义为一个业务处理过程,可能会包含多条INSERT、UPDATE或DELETE语句.
另外,DML实际指的就是SELECT、INSERT、UPDATE或DELETE语句.
然而,像文中的事务一样,DML通常只被用于表示INSERT、UPDATE或DELETE操作.
总的来说,DML和事务通常意味着只写或只修改.
为区分作为只读的SELECT操作,要用到术语"查询(query)".
看一下下面这些工业约定,尽管它们十分容易引起混淆,并且实际上和它们真实的定义相冲突.
在数据库系统应用领域有以下主要的应用类型:(1)OLTP(联机事务处理):OLTP系统是一个包含繁重DML的应用,其面向事务的活动主要包括更新,但也包括一些插入和删除.
经典的例子是预定系统,例如那些用于航空公司和旅馆的系统.
OLTP系统可以允许有很高的并发性(在这种情况下,高并发性通常表示许多用户可以同时使用一个数据库系统).
(2)DSS(决策支持系统):DSS系统通常是一个大型的、包含历史性内容的只读数据库,通常用于简单的固定查询或特别查询.
DSS常常按某种方式变成一个VLDB、DM或DW.
DSS一个很好的例子是某个组织的局域网后面的数据库.
(3)批作业处理:批作业处理系统是作用于数据库的非数据库的非交互性的自动应用.
它通常含有繁忙DML语句并有较低的并发性(在这种情况下,较低的并发性通常表示少数几个用户能够同时使用一个数据库系统).
事务查询的比率决定了如何物理地设计它,经典的例子是与DW有关的成品数据库和可操作数据库.
一些不太常用的应用类型包括如下:(1)OLAP(联机分析处理):OLAP系统可提供分析服务.
这意味着数学、统计学、集合以及大量的计算,一个OLAP系统并不永远适合OLTP或DSS模型,有时它是两者之间的交叉.
另外,有些人简单地把OLAP看作是在OLTP系统或DSS之上的一个扩展或一个附加的功能层次.
ROLAP代表关系型OLAP,尽管这个术语在分类方法上并不能真正增加什么.
一个OLAP工具通常被严格地和一个MDD配对使用,有时它只是简单地放在一个修改的RDBMS上.
通常,地理信息系统(GeographicInformationSystem,GIS)或有关空间的数据库和OLAP数据库相集成,提供图表的映射能力.
用于社会统计的人口数据库就是一个很好的例子.
(2)VCDB(可变基数数据库):这种类型的数据库通常被用作一个处理系统的数据库后端,这样就会导致在数据处理期间,数据库中的表显著地增长或收缩,其相反情况是保持不变或在一定的范围内变化,例如一个10%的变化.
基数是指在一个给定时间里一个表中的行的数目.
有些表可能是静态的查询表,但多数表的记录数目肯定是高度可变的,一个好的例子就是任何记录短期活动的数据库,例如一个安全授权数据库.
2.
4.
2定量评估的使用任何种类的定量评估都是试图量化或测量一些过程或产品,对于数据库来说,定量评估的两种主要类型是事务分析(volumeanalysis)和筛分分析(sizinganalysis).
1.
事务分析事务分析是简单地把数字放到数据库系统中.
不同的评估方法意味着不同的事情,并60Oracle8i数据库开发与专业应用应用于特定种类的数据库系统.
最典型的度量或尺度,包括下列项目的最小数.
平均数和最大数:(1)并发用户数目;(2)响应时间;(3)经过的时间;(4)事务数目;(5)并发程序的数目;(6)读写的字节数.
还有更多的尺度,例如受一个操作系统影响的行的数目.
如果这些评估是在一个给定的时间段或动作的背景下表达出来,那么它们通常有着更多的含义.
例如,知道每秒钟事务的最大数比知道事务的累积数更有用处.
后者只能告诉你很少的关于数据库通常的压力或负载情况.
这些数字在数据库为哪种应用服务的背景下也意味着更多的意义.
如果应用类型是一个OLTP系统,并发用户的数目、每秒钟的事务数目和响应时间尤其重要,因为并发是OLTP系统的首要问题.
如果有一个批量处理系统,经过的时间和并发的程序数也许最重要.
DSS可能要求除了知道其他项目外,还应知道每个时间单位内可读的字节数.
作为一名DBA,需要问这些问题并收集尽可能好的答案,因为这会影响到物理设计和运行性能.
另外,这些数字基本上就是用于衡量基准工作上的度量措施,那么,需要努力去做的就是在系统真正建立之前,收集估计的、原形的或典型的或实验的数字以帮助建立系统.
2.
筛分分析筛分分析也许是一种更广为人知的行为,甚至广泛地被所有的DBA采用.
在事务或量化分析中,考虑到处理和数据流量,你会问"多久一次"和"有多少";对于筛分分析,考虑到数据的存储,你会问"有多大".
基本情况是:如果一个表有n行,每行最多有b个字节,那么至少需要n*b个字节的存储空间.
当然,这没有考虑系统的开销,而且这种计算随着所选择的商品软件不同而有很明显的差异.
例如,像其他软件厂商一样,Oracle提供一套相当复杂的步骤,帮助测量一个表、索引或其他结构.
建议最好是一次把这个公式放入一个电子表格中.
每次需要测量其他的数据库对象时,需要做的就是取出它并插入相关的输入数字,如块的大小、块参数、行数、列大小等.
这样,就可以用表、表集合、索引和索引集合为整个数据库实现部分求和和分类汇总.
另外,一个经验丰富的DBA会在估算数值上加上一个裕量因子来对付任何低估错误、意外的疏忽以及未预料到的变化.
将有些项目(如估算后计值的大小)乘以120%是有道理的.
评估的数字通常是单独基于表和索引的.
如同所有的RDBMS商用软件一样,Oracle有许多更具结构性的因素增加了整个系统的大小.
不管最好得到的字节数是多少,这都是需要的可用空间,而不是裸盘的空间.
低级的硬件和一个高级的操作系统会消耗最初磁盘未格式化(裸盘)的大小,剩下的可用空间比认为得少.
例如,格式化可占用一个4GB磁盘中15%的空间,仅留下85%(即3.
4GB).
如果最第2章逻辑数据库的设计与实现61终的大小估算是20GB,并且没有考虑到这一点,只买了5*4GB的磁盘,然而实际上只有5*3.
4GB(即17GB)的可用空间,那么还需其他磁盘.
2.
4.
3出于性能的考虑使非标准化使非标准化是指由于物理设计、性能调整或其他原因,使表的标准化形式的级别在一定程度上降低.
一般情况下,除非有更好的理由,否则不要这样做.
没有根据地判定将会有一个不良性能,而不是实际存在不良性能,并不是一个好理由.
实际上,即使是不良性能本身,在逻辑设计上也不会立即表明有放弃的必要.
需要做的第一步工作是性能调整,非标准化一般是最后的办法.
假定在数据库中,有30个临时的表组成数据库的逻辑设计,这些表都是3NF或更高形式的.
然而,当使用的时候,这些表中的三个表实际上总是要联合到一起.
联合操作本身是资源密集的,并且只消耗很少的机器时间.
出于对性能改善的要求,又没有其他的性能调整的技术可用,为了长久地使用,希望把这三个表联合成一个表,这样就可避免将来访问时的联合.
把两个或多个标准化的表放回到一个表,实际上的确降低了标准化级别,甚至完全变成非标准化的.
当然,如果必须这样做,必须写入更多的过程化和应用级的数据完整性控制,来取代DBMS的自动控制.
例如,如果选择同时保留原始表和新的联合表,那么将面临一个不麻烦的任务:使它们保持同步.
然而如果更新非常频繁,并且要求联合数据的当前值,就不得不使用其他方法了.
另外一种方法就是在标准化的基表上创建一个非标准化的视图.
可是,这个方案的性能与简单地拥有三个原始表相同或更糟糕.
它唯一的好处就是用户接口简单.
尽管非标准化可能在一些静态的数据库事例中有帮助,但常常无法解决许多动态数据问题.
在这种情况下,如果非标准化不能工作,Oracle聚簇这样的方法可能就足够了.
最后,一个非常普通的非标准化例子DBA出现在必须处理时间序列时.
时间序列通常必须被非标准化的原因,是因为时间必须总是表的主键的一部分.
一个较好的例子是一个储存卫星反馈系统的数据库,这样的数据带有时间信息,它是数据库中大多数表的主键的一部分.
对于任何给定的包括时间信息成分的表,所有组成主键的其他列对于每个不同的时间来说是重复的.
换句话说,如果数据库每小时从一个卫星下载100行数据,那么在8h内,要毫无必要地重复800次存储800行数据以及其他的卫星信息,这是对存储的极大浪费,尤其是考虑到可能有多个卫星或更密集的取样频率.
典型的解决方法就是通过把数据从行方式转化为列方式,实行非标准化.
现在有100个带有时间信息的列,并且行数从800减少到8,或者使用一个取样间隔为100的因子.
存储的减少,尤其是行的减少,总能有助于提高搜索性能,因为在扫描一个表或一个索引时,扫描的行数减少了.
然而,这种类型的非标准化,尽管通常是必要的,结果却导致了一个不标准的表,因为时间信息被作为重复组列储存.
因此,在先前为主键组成部分的列上,不能用外键约束,相反,必须依赖于检查约束、过程、触发器以及可能的增补应用完整性来处理有关操作.
有时处于对性能的考虑,必须实行非标准化,那么在完整性管理上就必须付出代价.
62Oracle8i数据库开发与专业应用2.
4.
4理解存储分层结构数据库系统管理员能够学到的最重要的事情之一就是存储分层,以及与其相关的折中方案.
这比其他任何事情更能帮助解释许多关于物理设计和性能调整的问题.
存储分层背后的一个关键思想就是机电设备的不足(electromechanicaldisadvantage),即任何引擎和运动机件的东西肯定要比纯电子设备的速度慢.
图2-41表示了存储分层的现代解释.
沿这个金字塔向上,速度提高,费用增加,存储量降低.
图2-41存储分层示意图想储存得越多,必须付出得越多,尤其是希望能够得到更快的速度时更是如此.
但是,可以采取一些折中的方案.
对于一个历史数据系统,可以把比较旧的数据存放到联机光盘或至少较慢的磁盘上,而将更老的数据存放到联机或脱机磁带上.
如果特定的存储金字塔能让所有的存储介质自动联机或下载到磁带,并且有按照要求访问它的软件,那么这就是一个分层存储管理(HierarchicalStorageManagement,HSM)系统.
有专门研究这类硬件和软件的厂商.
历史数据系统能允许向金字塔底部移动,因为相对于数据流通,速度并不重要.
但是,对于实时系统(例如飞机导航),将存储加快是最优先的考虑因素.
许多商务应用的一个合理的方法就是把重要的和当前的数据存放在RAID或快速磁盘上,而将其他东西放在较慢的磁盘上.
第2章逻辑数据库的设计与实现632.
4.
5冗余廉价磁盘阵列RAID(冗余廉价磁盘阵列,RedundantArrayofIndexpensiveDisks)也许是一个误称.
从一开始,组成RAID的磁盘从未真正比普通的SCSI(小型就算机系统接口)盘便宜过.
另外,RAID需要特定的硬件、软件来工作,这都增加了成本.
所以RAID的廉价不十分确切.
RAID是一组能并行工作的磁盘,能够减少I/O时间,其效果主要取决于组成磁盘组的磁盘数量这一因素,对数据库来说这是件重要的事情.
RAID通过人们所熟知的数据条(srtiping)技术来实现并行工作,与普通磁盘存储有所区别,后者是串行工作的.
这只是以并行方式跨越多个磁盘使用数据条来写一个文件或文件块.
数据条是一个物理数据块的一定倍数,是磁盘I/O操作的最小单位.
通常,一个数据块由512字节组成,这对于大多数UNIX、VMS和DOS/NT系统来说都是正确的.
RAID还提供实时磁盘失效恢复,这是数据库的另外一件重要的事情.
RAID可以通过奇偶信息提供这一级别的可用性,这种信息也被写到一个或多个磁盘中.
奇偶校验、校验和以及错误纠正是通过一定的数学算法实现的,这些算法能重建在磁盘上的丢失数据.
RAID既支持大磁盘组也支持小磁盘组,可以有助于不同的数据库应用类型.
例如,DSS系统使用较大的磁盘通常运行得更好,而OLTP系统使用较小的磁盘运行得较好.
RAID分为很多形式,被称为级别.
当今在工业上最常用的RAID级是0、1、3和5.
所有其他的级别都没有被使用或只是这4个级别的一些变种.
供应商提供的RAID级达到7或更高,但在实际应用中很少看到它们.
RAID0是没有校验的基本数据条.
就是说,得到了性能上的优点但是没有校验.
当纯粹为了速度而可用性并不太重要时,这是很好的.
RAID1就是大家所知的镜像(mirroring),或者有时叫双工(duplexing),在镜像中同样没有校验.
实际上,对于偶数数目的磁盘组,其中的一半是保存实际的或主要的数据,另一半基于磁盘级保存数据的备份.
实际上,两部分磁盘是同时写入的,并且有时这意味着写入时性能的损失.
另一方面,在读的时候,如果软件被设计成能读多个盘,并且能将数据流合并使用,那么实际上读操作是可以被加速的.
RAID3是数据条,带有一个单一、专用校验盘.
可以丢失一个数据,并且仍然可以用校验盘来恢复它.
不过,校验盘是一个单一故障点.
如果它丢失,将是致命的,这依赖于软件或硬件,以及它是如何写入的来处理这类事件.
RAID5也是带有校验的数据条,只不过不是用一个单一、专用磁盘,它将校验信息与数据一起保存在所有的磁盘上.
校验信息和数据一样受到保护,并且没有单一的故障点.
和RAID3一样,RAID5能够在单个盘的丢失时恢复数据.
然而,3和5都不能恢复两个磁盘的缺失,因为丢失了太多的校验信息.
工业很少销售或实现RAID2、4、6.
这些级别的校验信息背后的数学计算量太大而不实用.
关于RAID最后要说明的就是:对于数据条,RDBMS和OS工具及技术手工能做的事,RAID都能做.
但是,它通常做得更好,它有精密形式的数据条,并提供更多的特性,如分区容量(数据条集合)、可调整大小的数据条等等.
另外,尽管RAID的数据条部分可以毫无困难地以一种总体的方式来实现,但你必须管理这些数据条.
RAID通常擅长于此,64Oracle8i数据库开发与专业应用并提供一个虚拟文件系统(VirtualFileSystem,VFS)的单一文件接口,协调OS文件级的命令和工具,并且提供了其他特性,如大于物理磁盘尺寸的文件.
最后,尽管可能可以管理某些形式的数据条,但是除了有标准的备份和恢复机制外,并没有其他保护措施.
但是RAID可以容忍丢失一张磁盘并进行恢复,如果试图自己编写这样的软件实在是太复杂了.
当可用性不是一个主要关系的事时,可以使用大致的、手工的RDBMS或OS数据条.
否则,当需要它提供的可用性并希望使用更为精密的数据条以获得更佳性能时,或需要它的其他特性(如巨型文件)的时候,要使用RAID.
2.
4.
6DBMS中的瓶颈过去,DBMS常常被指责为I/O限制或硬盘限制.
这就等于说一个DBMS由于它对磁盘的读出和写入,导致它在系统中成了瓶颈.
研究一下前面的分层结构就会发现这几乎是不相关的.
访问磁盘的速度要比访问内存或CPU的速度慢得多,这实际上就是过去许多数据库应用的情况.
对于DSS、VLDB和DW来说,这尤其正确.
因为,对于一个查询来说必须移动大量的数据.
然而,这并不永远是事实.
OLTP和OLAP系统通常是内存限制或CPU限制.
如果一个数据库硬件服务器有一个较低的内存对硬盘的比率,这就意味着应用是内存短缺的,数据库性能降低显然是由于存储数据库和缓存代码的内存空间不足.
如果一个OLAP类型的数据库被应用(比如一个科学数据库),那么速度是最重要的事.
因此,这种类型的应用如果运行在带有相对较弱CPU的服务器上,按照用户的期望(如响应时间)来讲,性能肯定是低劣的.
这里需要知道的就是任何系统(包括数据库系统)上,瓶颈现象是与应用类型相关的.
最后,在客户/服务器数据库系统中,网络系统是整个系统最慢的组件,甚至比硬盘还要慢.
为了有效地发挥一个客户/服务器系统的功能,必须合理地应用分段,并且网络系统一定不能超载.
另外,和其他资源一样,网络铣工必须被合理设计,以减少竞争.
还有,为利用当前网络的能力,网络硬件和软件应该实现现代化.
2.
4.
7平台的选择当选择适合于应用的硬件数据库服务器和操作系统时,有许多事情需要考虑,包括如下:(1)应用类型:正如已讨论过的OLTP、DSS、批处理或其他东西;(2)定量估计:正如前面讨论过的,关于事务的、量化的和筛分的数值;(3)当前环境:主要指现在的平台是什么;(4)趋势:对于当前的环境,工业发展的前进方向是什么;(5)处理的需要:需要是实时的、对时间要求不太严格的还是周期的,用事务的量化数值来说明并发和加载;(6)存储需要:用估算数值来确定对裸盘的需要,用事务和量化数值来确定是否需要RAID;(7)人员能力:哪些人员能力要求与现有的人员的基本能力相差甚远;(8)时间限制:在给定的时间内,是否能移植或开发出系统;第2章逻辑数据库的设计与实现65(9)衔接和合伙:RDBMS供应商是否与OS及硬件供应商有融洽的伙伴关系;(10)集成:与前一条类似,但是如不考虑他们之间的业务关系,那么将所有的工作放在一起会不会更好.
目前主要的RDBMS供应商是Oracle、Sybase和Informix.
CA在Ingres上做得多一些,微软只提供NT环境的服务器.
这里不考虑小型、桌面数据库.
现在只考虑Oracle,UNIX和WindowsNT是它的两个主要平台.
对UNIX来说,平台主要是SunSolaris.
当然,Oracle也可移植到其他形式的UNIX平台.
Oracle在MVS和VMS系统上也有一些大的安装数量.
至于硬件,不算Intel公司的机器,Sun公司的Solaris系统是唯一的真正选择.
Sun公司的机器已经经历了几代变化,但是它们均基于RISC的SPARC芯片.
WindowsNT主要使用在Compaq机器上,但也应用在DEC和HP的机器上.
在DEC上,关于WindowsNT最重要的事就是DEC支持Alpha和Intel的机器.
Compaq最近对DEC的购买,简化了软件提供商这种进退两难的局面.
Solaris和WindowsNT都可以在多处理器系统上运行.
但是,WindowsNT只能处理有限数量的处理器(14),并且用于处理Oracle的处理器的能力大约为4个.
Solaris能非常好地扩增,可以超过20个处理器,即使对于Oracle也是如此.
虽然Sun公司比Compaq、HP公司更容易提供更大的选择范围,但是磁盘存储选择几乎是相同的.
不必更深一步地比较硬件,这里有一个建议:作为一套常规准则,在准备选择一个平台之前,列出它们的各项指标,并充分考虑这些指标.
如果主要环境是DEC/VMS,并且有可能保留这种环境达几年时间,那么,下一个平台最有可能还是DEC/VMS,特别是如果只打算增加一台机器时更是如此.
如果准备为整个部门购买机器而且风险也不是关键问题,这时应考虑选用WindowsNT和UNIX最佳时机.
如果只需一台机器,且服务于相对较小的低于10GB的数据库,考虑选用NT较好.
相反,如果需要一台机器,但是对存储要求较大,或者对性能要求较高,考虑选用UNIX较好.
最后,如果没有一个真正的主导环境,或者你正在启动一个新计划(或这个新计划在某个方面影响你的购买),务必既要考虑WindowsNT也要考虑UNIX,还要考虑除了环境因素之外的所有因素.
当前,最后一个可供考虑的是Linux.
它起源于UNIX,当前得到一些支持,是WindowsNT的一个直接竞争者,因为它既是一个操作系统,又是一个网络操作系统(NetworkOperatingSystem,NOS).
因为它还有待于去建立硬件、应用和围绕它的技术支持,所以还没达到大多数工业销售的可信级,但是,它的普及程度还没有达到顶峰,决不可小视.
2.
4.
8操作系统集成和通用内存/CPU建议除了辅助存储、硬盘和RAID外,当讨论存储分层时,需要强调的是:考虑其他的硬件问题和操作系统组件,如内存和CPU.
内存通常指核心内存、物理内存、主存或随机存取内存(RAM).
对于一个DBMS来说,最重要的事情就是操作系统能够让出一些内存给它,那么DBMS用它来做自己要做的事,因此DBMS有时被称为微型操作系统、操作系统中的操作系统,或一个建立在操作系统上的操作系统.
实质上,虽然要服从操作系统并与之协作,但DBMS在管理和获取资源需求方面能够照顾自己.
这些事情通常是通过一个叫做共享内存功能来实现的,尤其是在UNIX环境中.
66Oracle8i数据库开发与专业应用加锁是DBMS的一个关键组成部分,它也是通过内存结构来控制的.
共享的资源没有进程竞争的危险,因为它们被依次使用.
DBMS控制它自己的锁,部分工作和操作系统一起来做,或将加锁任务交给操作系统完成.
当操作系统将它的部分内存让出给构成DBMS的一个进程时,DBMS从那里得到内存,并在这个内存空间里储存它自己的结构(代码缓存)和数据(数据缓冲).
Oracle的内存存取基于它的系统全局区(SystemGlobalArea,SGA)的资源分配.
SGA包含一个叫做数据库高速缓冲(告诉数据缓存)的结构和共享池.
共享池包含缓存(告诉代码缓存)以及数据字典缓存.
撤消(回滚)块存储在数据块缓冲内,重做块存储在它自己的重做日志缓冲(日志缓冲)部分.
通过Oracle的参数文件"init.
ora",这些组成部分都是可以配置的.
关于CPU的使用,RDBMS已走过了一段长路.
像前面提到的那样,多数过去的数据库系统趋向于I/O限制.
然而,有了VLDB和OLAP/MDD系统,越来越多的数据库变为内存限制或CPU限制.
有了VLDB,由于内存数量太小难以容纳大量的数据,内存成为瓶颈.
对于有大量的分析或科学的系统或者DW系统,由于庞大的、并行的计算要求,CPU可能会成为瓶颈.
在近十年中,随着多处理器机器的出现和改进,许多事情发生了变化.
现在,非常大的内存(大于几十GB)已成为可能,而且,CPU的体系结构和速度也大大提高.
CPU拥有密集的管线体结构,允许每个指令周期执行多条指令.
最重要的是新RDBMS软件也跟着推出.
Oracle和其他主要的RDBMS供应商一样,为充分利用这些先进硬件,有可能重新编写它们的过时代码.
除了共享内存和非常大的内存之外,多处理器的出现是近年来主要的提高和改进,目前存在两种主要的多处理器:(1)对称的多处理器(SymmetricMultiProcessor,SMP)(2)大规模并行处理(MassiveParallelProcessor,MPP)在SMP机器中(例如那些Sun公司提供的),CPU使用共享内存和其他内部硬件项目(如总线).
现在SMP已达到64个处理器.
MPP机器中有一个完全不共享体系结构,并且类似于微型局域网或一个盒子中的局域网.
MPP可以拥有数百个或数千个处理器.
现在,RDBMS软件或是完全多线程的或是多个进程.
多线程是软件的一种能力,在相同的父进程环境下,能够运行多个子进程或线程.
例如,Sybase和Informix就是完全多线程的;否则,它是单线程的.
数据库系统管理员只需要知道CPU的数目,并且能够配置OracleMTS就可以了.
其他的参数受CPU数目的影响.
2.
4.
9物理设计原则和常用硬件设计建议物理数据库设计实际上就是预调整,或者说是调整的第二个阶段(逻辑数据库设计是第一阶段).
因此,主要的物理数据库设计原则基本上与主要性能调整原则相同,只不过正在处理的数据库是在数据库创建之前或期间而不是创建之后.
设计原则主要有以下几条:(1)分而治之:分区、分段和并行是分而治之算法设计方法的扩展.
如果一个处理时间被分成数块并能够同时运行,那么就说它是可并行的.
对此的主要要求是处理的每个部分必须是与数据无关的.
即不管任何其他的程序块是否已结束,某一程序块都可以开始.
例如把一个求总数的运行时间很长的查询程序分割成两块,在不同的CPU上运行它们,然后把它们的部分和相加,得到最后的结果.
实际上,这就是Oracle的并行查询功能所提供的第2章逻辑数据库的设计与实现67东西.
(2)预分配和预编译:静态分配和固定分配都表示相同的意思,即预分配.
换句话说,提前分配资源,而不是动态地由软件来做这件事.
这通常导致额外的计算和I/O开销,而这总是不受欢迎的.
预编译程序比预解释程序执行起来要节省时间.
虽然DBMS缓存控制许多事情,但是DBA应该注意可以做些什么以进行补充,例如编写一些通用、可重复的过程并把它们储存到内存中.
Oracle的KEEP操作可实现后者.
(3)前摄:预测主要的问题.
遵循柏拉图规则:解决可能引起80%麻烦的20%的问题,这也称为20/80规则.
用统计的方式来说,就是所有的性能问题并不是由各种原因平均引起的.
应尽力预测最主要的问题,并且把它们设计在系统外或至少补偿并围绕它们进行设计.
考虑一个大型的串行运行的批处理作业系统,只有几个主要程序,每个都可以插入、更新或删除大量数据.
这里潜在的问题与事务日志有关,尤其是撤消日志增长得非常大,甚至有可能消耗光存储空间.
对于Oracle,撤消日志就是一组可用的回滚段.
对于一个DBA来说,合理的设计将至少有一个非常大的回滚段,而不是能够控制产生的最大数量回滚数据的SYSTEM表空间.
(4)批量、块和批处理:使用大量传送.
成批的事务在一起时进行批量处理才有意义.
这就意味着对硬盘和网络I/O这样的事物来说,常用的最好方法就是大量传送.
将有相同的起源和终点的I/O操作组合在一起.
这项工作通常是为DSS和批量处理系统而做的.
例如,用户可能经常从一个极大的表中选择多个行.
因为这些选择返回如此多行,因此他们从来不用任何可用的索引.
如果这时没有得益于任何并行硬件或软件,那么表应该连续地存放在一个单独的大磁盘上.
然后,你可以增加数据库逻辑缓存的尺寸,以同时读许多物理数据块.
例如,在Oracle中,可以把DB-BLOCK-SIZE设到平台所支持的最大值,这样一次读请求,便读到尽可能多的数据块.
这些都源于一个简单的事实,即在几乎所有的机电系统中,启动耗费是相当大的.
一个类似的网络情形是在每一个包里发送尽可能多的信息,因为这会提高成本效率.
(5)合理地分割应用:这可以看作是"分而治之"原则的小主题,它的区别在于所强调的东西是整个的环境和应用程序,而不只是它背后的数据库.
在分布应用前,考虑客户、网络和服务器的相对性能能力.
把功能放在逻辑上能被执行的地方.
例如,在一个交互式的应用中显示和表现的任务显然是属于客户的,而作为数据库对象的数据库事件应在数据库中处理,而不是由一些前端的软件处理.
在Oracle中,使用了触发器和存储过程进行这种设计.
物理设计和调整的主要目标是消除或最大限度地减少竞争,竞争(contention)就是两个或多个软件争夺同一个资源.
为了解决竞争,实践下列的规划建议:(1)把表和索引分开;(2)把大的表和索引放在单独的盘上;(3)把经常联合的表放在单独的盘上,或把它们聚合;(4)必要时,把不常联合的表放在相同的盘上;(5)把DBMS软件与表和索引分开;(6)把数据字典与表和索引分开;(7)如果可能,把撤消(回滚)日志和重做日志分别放到它们自己的盘上;(8)为撤消日志或重做日志使用RAID1(镜像);68Oracle8i数据库开发与专业应用(9)为表数据使用RAID3或RAID5(带有校验的数据条);(10)为索引使用RAID0(没有校验的数据条).
正如前面所讨论的,在某些情况下,如果RAID是不可用的,那么手工数据条可以在某种程度上满足需要.
但是,一般来讲,它不够灵活、安全或快速.
另外,当前面的列表要进行分离时,那是表示把他们放到单独的盘上;但是,这又可能进一步意味着把它们放到单独的磁盘控制器上.
控制器越多,性能和安全性就越理想.
2.
5小结1.
问:数据库设计的内容是什么它有哪些步骤答:数据库设计通常是在一个通用的DBMS支持下进行的,即利用现成的DBMS作为开发基础.
具体地说,数据库设计包括结构特性的设计和行为特性的设计两方面的内容.
结构特性设计是指确定数据库的数据模型.
数据库反映了现实世界的数据及数据间的联系,要求满足应用需求的前提下,尽可能减少冗余,实现数据共享.
行为特性的设计是指确定数据库应用的行为和动作,应用的行为体现在应用程序中,所以行为特性的设计主要是应用程序的设计.
数据库设计步骤要注意以下几点:(1)设计步骤是从数据库应用系统设计和开发的全过程来考察数据库设计问题,因此,它既包括数据库模型的设计,也包括围绕数据库展开的应用处理的设计过程.
(2)在设计过程中努力把数据库设计和系统其他成分的设计紧密结合.
把数据和处理的需求收集、分析、抽象、设计、实现在各阶段同时进行,相互参照,互相补充,以完善两方面的设计.
(3)在有关处理特性的设计描述中,采用的设计方法和工具在软件工程和信息系统设计等课程中都有介绍,这里不再讨论,本节重点讨论数据特性的设计描述,以及在结构特性设计中如何参照处理特性设计来完善数据模型设计的问题.
2.
问:什么是数据流图它有哪些功能答:数据流图是从"数据"和"处理"两方面来表达数据处理过程的一种图形化的表示方法.
在数据流图中,用方框表示数据处理(加工);用箭头的线段表示数据的流动及流动方向,及数据的来源和去向;用"书形框"表示要求在系统中存储的数据.
在系统分析阶段,不必确定数据的具体存储方式.
在此后的实现中,这些数据的存储形式可能是数据库中的关系,也可能是操作系统的文件.
数据流图的"处理"抽象表达了系统的功能要求,系统的整体功能要求可以分解为系统的若干子功能要求,通过逐步分解的方法,一直可以分解到将系统的工作过程表达清楚为止.
在功能分解的同时,每个子功能在处理时所用的数据存储也被逐步分解,从而形成若干层次的数据流图.
3.
问:什么是关键字它是如何组成的答:关键字是由一个或多个属性组成的可唯一标识一行的属性组.
关键字也可以是由一组属性合起来组成.
例如,如果允许学生同时参加多项活动,那么SID的值就可能出现在表中的两行或多行,因此,SID不能唯一地标识一行,这时,也第2章逻辑数据库的设计与实现69许就需要某些属性的组合,如(SID,Activity).
4.
问:规范化的本质是什么答:每个规范化的的关系只有一个主题,如果某个关系有两个或多个主题,它就应该分解为多个关系,每个关系只能有一个主题.
但是,每当我们分解关系时,我们应该建立对关联约束的要求,这一过程就是规范化的实质.
当我们发现一个关系存在更新异常时,通过把关系分解为两个或多个单独的关系,每个关系只有一个主题,我们就可以消除这种异常.
5.
问:关系是如何分类的答:关系可以根据其中易出现的更新异常的类型进行分类.
用以防止异常的关系和技术称作范式.
根据关系的结构,某个关系可以在第一范式、第二范式中,或在其他范式中.
E.
F.
Codd定义了第一、第二和第三范式(1NF,2NF,3NF).
后来,又有了Boyce-Codd范式(BCNF),接着,第四和第五范式也定义出来了.
这些范式是嵌套的.
就是说,第二范式中的关系也是第一范式中的,5NF(第五范式)中的关系也是4NF、BCNF、3NF、2NF和1NF中的关系.
6.
问:什么是域/关键字范式答:1981年,R.
Fagin定义了域/关键字范式(DK/NF).
他证明,域/关键字范式中的关系没有更新异常,没有更新异常的关系必定在域/关键字范式中.
该发现建立了范式定义的范围,至少是,为了消除更新异常,不需要再定义更高的范式.
DK/NF概念是非常简单的:如果一个关系中的每个约束都是关键字和域的定义的逻辑结果,则该关系在DK/NF中.
考虑该定义中的重要术语:约束、关键字和域.
7.
问:给定一个有某些函数依赖的属性集合,我们应该构成什么样的关系答:两个属性,假设A和B,他们可以有三种关联方式:(1)它们互相决定:A→B和B→A.
因此A和B之间有1对1的关系;(2)一个决定另一个:A→B,但B→A不成立.
因此,A和B之间有多对1的关系;(3)它们函数无关:A→B和B→A都不成立.
因此,A和B之间有多对多属性关系.
8.
问:如何实现设计的优化答:典型的方法是,我们通过把非规范化的表分解两个或多个表来创建规范化的表.
有些情况下,还有更好的方法可以获取规范化的设计.
例如,考虑关系COLLEGE(CollegeName,Dean,AssitantDean).
假定一个学院只有一个院长,有1~3个副院长.
此时,该表的关键字是(CollegeName,AssitantDean),且不在域/关键字范式中,因为约束CollegeNameDean不是该表的关键字的逻辑结果.
9.
问:使用实体联系模型设计数据库主要有哪两部分组成答:第一部分讨论如何把实体联系数据模型转化为关系设计.
规范化对这一过程是非常重要的,因为实体可以包含一个语义主题.
在说明如何表示实体后,我们考察使用关系模型对关系的表示.
第二部分应用第一部分描述的概念,阐述如何把实体联系模型转化为四个公共数据库结构的表示.
这些结构是E-R构件的特例,第一部分中的技术和关系一起可用来表示它们.
我们之所以给这些结构以特别的注意,只是因为它们作为实体和关系的公共模式经常出现.
10.
问:什么是树答:树有时又称作层次.
它是一种数据结构,结构中的元素之间只有1对多关系,每70Oracle8i数据库开发与专业应用个元素至多有一个父节点.
11.
问:什么是简单网络什么是复杂网络答:简单网络也是一种其中元素只有1对多关系的数据结构.
但是,在简单网络中,只要父节点的类型不同,一个元素就可以有多于一个的父节点.
复杂网络是其中至少有一个多对多关系的数据结构.
12.
问:什么是材料单答:材料单是一种经常在制造业的应用中出现的数据结构.
实际上,20世纪60年代,这种结构为数据库技术的开发提供了主要动力.
13.
问:在数据库系统应用领域有哪些主要的应用类型答:主要有以下主要的应用类型:(1)OLTP(联机事务处理);(2)DSS(决策支持系统);(3)批作业处理.
14.
问:什么是非标准化这样做是出于什么原因答:使非标准化是指由于物理设计、性能调整或其他原因,使表的标准化形式的级别在一定程度上降低.
一般情况下,除非有更好的理由,否则不要这样做.
没有根据地判定将会有一个不良性能,而不是实际存在不良性能,并不是一个好理由.
实际上,即使是不良性能本身,在逻辑设计上也不会立即表明有放弃的必要.
需要做的第一步工作是性能调整,非标准化一般是最后的办法.
15.
问:当选择适合于应用的硬件数据库服务器和操作系统时,要考虑哪些因素答:需要考虑的因素如下:(1)应用类型:正如已讨论过的OLTP、DSS、批处理或其他东西;(2)定量估计:正如前面讨论过的,关于事务的、量化的和筛分的数值;(3)当前环境:主要指现在的平台是什么;(4)趋势:对于当前的环境,工业发展的前进方向是什么;(5)处理的需要:需要是实时的、对时间要求不太严格的还是周期的,用事务的量化数值来说明并发和加载;(6)存储需要:用估算数值来确定对裸盘的需要,用事务和量化数值来确定是否需要RAID;(7)人员能力:哪些人员能力要求与现有的人员的基本能力相差甚远;(8)时间限制:在给定的时间内,是否能移植或开发出系统;(9)衔接和合伙:RDBMS供应商是否与OS及硬件供应商有融洽的伙伴关系;(10)集成:与前一条类似,但是如不考虑他们之间的业务关系,那么将所有的工作放在一起会不会更好.
第3章结构化查询语言SQL本章阐述了关系数据库查询语言SQL(StructuredQueryLanguage)的基本概念和原理.
同时还介绍在Oracle数据库管理系统中提供的工具SQL*Plus的使用方法.
涉及到数据库的数据定义、数据操纵、数据管理以及报表生成等方面的内容,指导用户如何执行数据库的基本操作,是用户使用Oracle的其他工具的基础.
3.
1Oracle数据库的基本概念在计算机应用系统中,现实世界的信息以数据的形式存储在计算机中,用户对这些信息作出种种询问.
例如,想了解本公司哪个部门发出的薪金每人每月超过2200美元,在传统的计算机信息管理系统中往往要经过多个步骤,花费较长的时间才能得到答案,一般来说有以下几步:(1)打开文件;(2)读入数据;(3)分类数据记录;(4)查询符合条件的记录;(5)显示数据记录;(6)关闭文件.
而且这种系统开发时编制程序所需时间较多,最后开发出来的系统向用户提供的查询接口不一定为用户所熟悉,或者和系统所要求的数据的组织格式不匹配.
为了解决以上问题,OracleRDBMS提供了SQL*Plus,它提供了一种灵活的数据库查询语言,易学易用,可靠性和查询效率都较高.
在Oracle数据库中SQL*Plus主要用来创建或修改表和视图,对数据操作语义范围极广的查询,并能生成各种格式的报表.
数据库是对计算机应用系统中集成化的数据集合的总称,获得恰当授权的用户和程序就可以对数据库中的数据进行存取和修改,建立数据库的一个主要目的是尽量减少冗余信息.
数据库管理系统是对数据库进行管理的一系列软件的总称,系统中的程序对数据库中数据进行存储、检索或修改,并保证数据的一致性,解决多用户环境下可能出现的并发控制问题,向多用户提供一个统一的接口来存取数据,并管理数据的所有存取请求.
数据库管理系统按照一定的数据模型来组织数据,共出现过三种数据模型:20世纪60年代出现的层次模型;70年代的网状模型和80年代的关系模型.
它们之间有很大的不同,例如就定义数据之间的关系的能力而言,层次模型只能定义数据之间的一个父对象和多个子对象的关系,网状模型还能定义多个父对象和多个子对象之间的关系,而关系模型则使系统能自动建立对象间的所有可能的关系.
关系数据模型由E.
F.
Codd在70年代提出,是72Oracle8i数据库开发与专业应用由IBM公司的ALPHA模型演化而来,而1979年推出的OracleV2则是第一个商用关系数据库管理系统.
关系数据库管理系统大都具有以下特点,以表格的形式来组织数据,提供一种第四代语言(4GL),其特点是非过程化的语义和自然的语法格式(如SQL的格式和英语的语言很接近),数据库中的操作以关系模型统一起来,所有的操作都是关系上的操作,查询时无需指定查询路径,由数据库管理系统进行自动导向,关系型的数据库具有较大的灵活性,数据库的结构和存储于其中的数据都易于修改,并提供集成的数据字典.
1974年在IBM公司的SANJOSE研究所最先开发出SQL的前身系统,并在1976年发布SQL的文本,1979年由Oracle公司公布第一个基于SQL的商用关系型数据库管理系统,1982年IBM公布该公司的第一个关系型数据库管理系统SQL/DS,随后在1985年公布了第二个关系型数据库管理系统DB2,从1986年开始ANSI指定SQL为工业标准.
3.
2SQL的基本概念关系数据库模型中信息以表格的形式组织起来并存储在数据库系统中,每个表所含的信息种类在表头中排列出来,所有的情况在表体中一行一行地列出来,每种情况的信息按表头的定义从左到右排列,用户从这样一张表中可以清楚地阅读、理解和使用表中的信息.
行和列是关系数据库中最基本的概念,每一列存储一类信息,行是由多个列组成的,行中的每一列记录一个值,请观察表EMP中关于JONES的一行,行中的SAL里记录一个值2975.
在数据库中,一个表与其他表的数据之间是可以有关联的,例如在表EMP中每个雇员都有一个部门号指向表DEPT中的一行.
数据库中的这种表达关联信息的能力使表成为组织数据库中的信息的独立管理单位.
在上例中雇员的信息和部门的信息是分别存储的.
在应用中可以对多个表作连接,然后获得所需的信息,如可以找出表EMP中的某一个雇员所在部门的地址.
事实上表中有相关的列就可以进行连接操作.
DEPTTableDEPTNODNAMELOC40OPERATIONSBOSTON30SALESCHICAGO20RESEARCHDALLAS10ACCOUNTINGNEWYORKEMPTableEMPNOENAMEJOBMGRHIREDATESALCOMMDEPTNO7369SMITHCLERK790217-DEC-80800207499ALLENSALESMAN769820-FEB-811,600300307521WORDSALESMAN769822-FEB-811,250500307566JONESMANAGER783902-APR-812,975207654MARTINSALESMAN769828-SEP-811,2501,40030第3章结构化查询语言SQL737698BALKEMANAGER783901-MAY-812,85030在Oracle数据库中用SQL命令来创建、存储、修改、检索和维护数据库中的信息.
进入SQL*Plus后系统开出一块存储空间称为SQL命令缓冲区,存储当前的SQL命令,SQL有很多关键字,与最基本的17条语句有关的关键字如下:alterauditcommit*commentcreatedeletedropgrantinsertlocknoauditrenamerevokerollback*selectupdatevalidate带星号的命令虽然是SQL的一部分,但不需要分号,也不会存储在SQL命令缓冲区中.
除SQL标准命令外,Oracle的SQL*Plus语言还有其他的扩充命令——SQL*Plus命令,用于建立复杂报表的环境设置(如页长、表头、各列显示格式等),另外还用于编辑SQL语句,提供帮助功能以维护系统变量.
扩充命令也不会存储在SQL命令缓冲区中,SQL*Plus有以下扩充命令:@#$/acceptappendbreakbtitlechangeclearcolumncomputeconnectcopydefinedeldescribedisconnectdocumenteditexitgethelphostinputlistnewpagepausequitremarkrunsavesetshowspoolsqlplusstarttimmingttitleundefine3.
3数据库查询3.
3.
1SQL的基本结构要使用SQL*Plus必须先注册,每个用户都有一个用户标识和密码,在操作系统的提示符下键入命令:SQLPLUS,则SQL*PLUS会要求用户输入用户标识和密码:ENTERUSERNAME:SCOTTENTERPASSWORD:其中密码是不会显示在屏幕上的,用户标识和密码都输入正确后,即进入SQL>提示符.
在使用SQLPLUS的时候可以用以下命令列出所有的SQL和SQL*Plus的命令:SQL>HELPSELECTSQL>HELPCREATE还可以用以下命令列出当前的帮助项目:SQL>HELPTOPICS数据字典是一组表和视图,它存储了包括所有表、用户存取权限以及数据库的其他特性的描述信息,在存取数据字典过程中最常用到的有以下几个表:TAB用户创建的所有表、视图和别名的列表DTAB组成数据字典的所有表COL用户创建的表中所有的列定义CATALOG用户存取的所有表用DESCRIBE命令可看到关于一指定的表的描述信息,描述信息包括每列的名,该列74Oracle8i数据库开发与专业应用是否允许空值以及该列的类型定义,类型定义显示为:char(w)字符型numeric(w,d)数值型w表示宽度,d表示十进制位数date日期型raw原始二进制3.
3.
2简单查询的语法在SQL中可以用多种方式查询数据库,因为SQL的语法非常灵活.
但执行SQL查询依然要遵循一定的语法规则,否则可能提出错误的SQL提问,或者得不到任何答案,或者答非所问.
SQL查询语句的总体语法如图3-1所示.
图3-1SQL查询语句的基本语法下面举几个例子说明具体的用法.
查看EMP表中的所有数据键入下述命令:SQL>SELECT*FROMEMP;其中星号表示表中的所有列.
查看表中某一特定列则用命令:SQL>SELECTENAMEFROMEMP;ENAME是表EMP中的一个列名,结果返回该列中的所有数据.
查看表中某几个指定列,键入下述命令:第3章结构化查询语言SQL75SQL>SELECTEMPNO,ENAME,JOBFROMEMP;SQL>SELECTJOB,ENAME,EMPNOFROMEMP;在上述命令中都没有WHERE子句,所以查询返回的结果返回所有的行.
如果定义了WHERE子句,则会返回符合条件的所有行.
SQL>SELECTENAMEFROMEMPWHEREDEPTNO=10;在关系数据模型中各行之间没有顺序,在查询命令中加入ORDERBY子句,可以保证查询结果的各行按特定顺序显示,试比较下述两个命令执行结果的不同.
SQL>SELECTENAMEFROMEMP;与:SQL>SELECTENAMEFROMEMPORDERBYENAME;按多个标准进行排序时,主顺序根据列出的第一个列排序,次顺序根据第二个列排序,依次类推.
默认是升序排序,如果要按降序排序,在ORDERBY子句后加上DESC,如下述命令:SQL>SELECT*FROMDEPTORDERBYDEPTNODESC;在WHERE子句中可以把一个列的值作以下形式的比较,返回符合条件的行:(1)把列的值和一个字符常量进行比较,字符常量用单引号括起来,例如:WHEREENAME='SMITH'(2)把列的值和一数学表达式进行比较,数学表达式无需引号,例如:WHEREDEPTNP=20(3)把列的值和另一列的值进行比较,这种结构在数据库中称为连接,会在后面有更详细的讨论,例如:WHEREEMP.
DEPTNO=DEPT.
DEPTNO在查询条件中使用以下逻辑比较运算符:相等=不等!
=或大于>大于等于>=小于SELECTENAME,JOBFROMEMPWHEREJOBIN('CLERK','ANALYST');用NOTIN则可选择不落在表中的所有行,如:SQL>SELECTENAME,JOBFROMEMPWHEREJOBNOTIN('CLERK','ANALYST');相反用NOTBETWEEN来找出不在此范围内的所有雇员:SQL>SELECTENAME,JOB,SALFROMEMPWHERESALNOTBETWEEN2000AND3000;在WHERE子句中用LIKE运算符来搜索字符串,如列出所有姓名以字母S开头的雇员:SQL>SELECTENAME,DEPTNOFEOMEMPWHEREENAMLIKE'S%';找出所有姓名以字母K结尾的雇员:SQL>SELECTENAME,DEPTNOFROMEMPWHEREENAMELIKE'%K';找出所有姓名以字母W开头且后跟三个字母的雇员:SQL>SELECTENAME,DEPTNO;FROMEMP;WHEREENAMELIKE'w---';观察上述命令的执行结果可以发现,符号%匹配任意长度的字符串,-则匹配单个字符.
用NOTLIKE选取与模式不匹配的行,如要列出工作不是以SALES开头的所有雇员:SQL>SELECTENAME,JOBFROMEMPWHEREJOBNOTLIKE'SALES%';3.
3.
3查询条件的描述空值NULL是一个特殊的值,表示某一列上的值为未知、丢失或不可用,空值和零值不能同等对待.
在一个数值列上的空值和零不同,零是一个数,而空值不是一个数.
空值第3章结构化查询语言SQL77在Oracle关系型数据库管理系统中不占存储空间.
下面的查询找出未有资格领取佣金的雇员:SQL>SELECTENAME,JOBFROMEMPWHERECOMMISNULL;下面的查询是用选取非空值的方法找出有资格领取佣金的雇员:SQL>SELECTENAME,JOBFROMEMPWHERECOMMISNOTNULL;WHERE子句中可以定义更多的条件来做查询,试比较下述两个命令的执行结果:SQL>SELECTENAME,JOBFROMEMPWHEREDEPTNO=20;与:SQL>SELECTENAME,JOBFROMEMPWHEREDEPTNO=20ANDJOB!
='CLERK'AND运算符给行的选取加上严格的条件,相反OR运算符放宽了选取的条件,试比较下述两个命令的执行结果:SQL>SELECTENAME,JOBFROMEMPWHEREDEPTNO=20ANDJOB!
='CLERK';与:SQL>SELCTENAME,JOBFROMEMPWHEREDEPTNO=20ORJOB!
='CLERK';在同一个WHERE子句中可同时使用AND和OR运算符,用()来确定运算的优先顺序,如果没有(),则按先做AND再做OR的顺序进行运算,如条件:WHEREDEPTNO=30ANDJOB='SALESMAN'ORSAL>2000表示在部门30工作的推销员或工资多于2000的所有雇员,而不是指在部门30工作的雇员中工作为推销员或工资多于2000的雇员.
在SQL语句中用以下数值运算符可作表达式的求值:+加-减*乘/除这些运算符可以在所在SQL的子句中使用,包括SELECT、WHERE、ORDERBY以78Oracle8i数据库开发与专业应用及其他子句,在FROM子句中使用数学运算符是没有用的.
在同一查询中可以使用多个表达式,如下述查询找出佣金多于工资5%的雇员:SQL>SELECT,SAL,COMM,COMM/SALFROMEMPWHERECOMM>0.
05*SALORDERBYCOMM/SALDESC;在同一条数学表达式中如果有多个运算符,则先对乘除求值,再对加减求值,求值顺序从左到右,也可用()来控制求值顺序,如12*(SAL+COMM)不等价于12*SAL+COMM.
在表达式中可以使用日期值,日期是一个求值的基本单位,可以对日期进行加或减,以下是使用日期加法的例子:87年3月6日加上2d:6-MAR-87+2=8-MAR-8787年3月6日加上2h:6-MAR-87+2/24=6-MAR-87and2hrs87年3月6日加上15s:6-MAR-87+15/(24*60*60)=6-MAR-87and15secs显示查询结果时,每列的标题以用户定义表时使用的名字为准,但也可以在SELECT子句中指定列的别名,显示不同的标题.
指定别名时在列名后加上一个空格再写上别名,如:SQL>SELECTENAMEEMPLOYEEFROMEMPWHEREDEPTNO=10;在SELECT子句中可以使用数学表达式并显示计算结果,显示时用表达式来做该列的标题,为了使显示结果更易读,应为这种计算的列指定一个别名.
这个别名作显示用,如果别名中含有特殊字符(如空格和斜杠等),就要用双引号括起来,且别名仅对指定别名的SELECT语句起作用,对其他查询不起作用.
下例查询找出佣金多于基本工资5%的雇员:SQL>SELECTENAME,SAL,COMM,COLL/SAL"C/SRATIO"FROMEMPWHERECOMM>0.
05*SALORDERBYCOMM/SALDESC;注意在ORDERBY子句中使用的应是表达式而不是别名,这个规定对其他子句也适用.
3.
3.
4SQL命令的编辑在编辑SQL命令时系统提供一个SQL缓冲区,该区保存当前SQL命令直到用户键入另一条SQL命令取代或退出系统,系统提供以下命令对当前SQL命令进行编辑:LIST或L显示SQL缓冲区中的内容LIST4显示当前SQL命令的第四行CHANGE或C将当前行中的旧串修改成新串,.
.
.
匹配任意长度的字符串,如可以用命令C/ANALYST')/INPUT或I在当前的SQL命令后加上一行或多行APPEND或A在当前行后添加字符DEL删除一行RUN显示SQL缓冲区中的语句并运行/运行SQL缓冲区中的语句第3章结构化查询语言SQL79EDIT把SQL缓冲区中的语句写入一个操作系统的文本文件中,并调用标准的操作系统编辑器来修改3.
4数据操纵3.
4.
1插入数据必须事先定义一个表才可以对它进行数据的插入,插入时用逗号把各个值分隔开.
插入的每个值必须和表定义的各列的顺序和类型匹配.
可以先用DESCRIBE命令显示各列的顺序和类型,插入时所有字符和日期类型的值必须用单引号括起来,插入命令的基本语法形式为:图3-2插入命令的基本语法例如:SQL>INSERTINTODEPTVALUES(10,'ACCOUNTING','NEWYORK');在INSERT子句中指定插入的一个或多个列的顺序后,插入的数据必须按指定的顺序排序,例如:SQL>INSERTINTODEPT(DNAME,DEPTNO)VALUES('ACCOUNTING',10);插入的数据可以是来自一个表的查询的结果,该查询语句代替了VALUES子句:SQL>INSERTINTOEMP(EMPNO,ENAME,DEPTNO)SELECTID,NAME,DEPARTMENTFROMOLD-EMPWHEREDEPARTMENTIN(10,20,30,40);在INSERT命令中可加入参数表示其值是在命令运行时获得,参数以&开头,后面通常跟对应的列名,例如:SQL>INSERTINTODEPTVALUES(&DEPTNO,&DNAME,&LOC);这条命令执行时,SQL*Plus提请用户输入每个参数的值,用户可以通过重复执行命令插入多行到表中.
如采用如下语句的格式,对应于字符类型和日期类型的参数无需用括号括起来:SQL>INSERTINTODEPTVALUES(&DEPTNO,'&DNAME','&LOC');如果没有给出INSERT子句中某一列的值,系统默认该列的值为空值,也可以在VALUES子句中对应地写上空值.
但如果某一列已经约束定义为非空(NOTNULL),必须输入与字段类型相符的数据:80Oracle8i数据库开发与专业应用SQL>INSERTINTODEPTVALUES(50,'EDUCATION',NULL);系统默认的日期输入格式是'日-月-年',例如要增加一个新雇员'STONE':SQL>INSERTEMP(EMPNO,ENAME,HIREADATE)VALUES(7963,'STONE','07-APR-87');还可以用SYSDATE自动地输入系统当前的日期和时间,例如输入一个今天进来的雇员"KOHN":SQL>INSERTINTOEMP(EMPNO,ENAME,HIREDATE)VALUES(7600,'KOHN',SYSDATE);3.
4.
2删除和修改SQL语言中删除命令和修改命令分别采用图3-3和图3-4所示的语法形式:图3-3删除命令的基本语法图3-4修改命令的基本语法用UPDATE命令可以修改数据库中的值,如把MARTIN晋升为经理:SQL>UPDATEEMPSETJOB='MANAGER'WHEREENAME='MARTIN';注意:如果在语句中没有WHERE子句,则会导致列中的所有值被改为SET所指定的值.
UPDATE语句可以有选择地修改表中的多行,如把所有推销员的工作改为市场研究员:SQL>UPDATEEMPSETJOB='MARKETREP'WHEREJOB='SALESMAN';UPDATE语句可以同时修改多列的值,在SET子句中指定要修改的所有值,如把所有推销员的工作改为市场研究员,同时调往部门40:SQL>UPDATEEMPSETDEPTNO=40,JOB='MARKETREP'WHEREJOB='SALESMAN';DELETE语句把表中行整行删除掉,而不会只删除一部分,所以不用指定列名.
如果第3章结构化查询语言SQL81要删除的行中的一部分可用把该列的值置为空值的方法来替代,用WHERE子句来指定要删除的行.
如果没有WHERE子句,则会把所有行都删除掉.
如MARTIN辞职了,要把他从公司名册中删除掉:SQL>DELETEFROMEMPWHEREEMPNO=7654;3.
4.
3提交和回滚对表的插入、删除和修改都要在工作提交(即对数据修改的确认)后才生效.
在作提交以前,只有作出数据修改的用户本身能看到改变的情况,其他用户要查看同一表格的数据时,看到的只是上次提交后的数据(即数据没有修改的情况).
提交命令COMMIT有三种形式:显式的、隐含的和自动的.
显式的提交就是打入SQL命令COMMIT使所有数据的改变生效.
SQL>COMMIT下列SQL命令引发隐含的COMMIT命令:ALTER,AUDIT,COMMENT,CONNECT,CREATE,DISCONNECT,DROP,EXIT,GRANT,NOAUDIT,QUIT,REVOKE,RENAME执行SQL*Plus命令,SET可以使系统对INSERT、UPDATE和DELETE命令的工作自动执行提交,使结果即时生效:SQL>SETAUTOCOMMITON如要把当前工作引起的修改撤消,使用SQL命令ROLLBACK.
执行ROLLBACK使数据库恢复到上次COMMIT时的状态:SQL>ROLLBAK数据库系统运行的过程中,把两个成功的提交操作之间所发生的所有改变称为一个事务.
事务执行被系统失效之类的严重错误所中断时,则把整个事务自动回滚,从而避免了只提交一个逻辑事务的部分改变.
在实际应用中会有以下逻辑事务:把一笔资金从一个储蓄账户中调出,然后存入另一个账户;在公司中创立一个新的部门,先把表EMP中要调入的新部门的雇员记录中的DEPTNO(部门号)做相应的改变,同时在表DEPT中加入新的一行.
3.
5创建表和视图创建一个表时需指定表的名字、表中各列的名字、表中各列的值的类型及每列的最大宽度.
在Oracle中一个表最多可包含254列,创建表后由系统自动修改数据字典.
下面的SQL命令创建一个表:SQL>CREATETABLEDEPT(DEPTNONUMBER(2),DNAMECHAR(14),LOCCHAR(13));创建表时,命名遵循一系列的规则,所有名字的第一个字母必须是A至Z或a至z的英文字母(一律以大写形式存储).
后面的字符还可以是数字和$,#,-等,但不能是逗号,82Oracle8i数据库开发与专业应用每个名字的最大长度不能超过30个字符.
创建的表名不能和发出的创建命令的用户标识相同,也不能和任何Oracle的关键字相同,在同一个表中各列的名字必须是唯一的.
如果为一个表命名时用双引号把表名括起来,则无需遵守上述命名规则,但在使用这样的表时必须用双引号把表名括起来.
在Oracle数据库中提供以下数据类型:字符串类型CHAR(N):定长字符串类型,N是字符串的最大,最大可为255,缺省值为1;字符串类型VARCHAR2(N):变长字符串类型,N是字符串的最大,最大可为2000;数值类型NUMBER(N,D):N是数值的最大数字位数,含小数点本身,D是小数点后的最大数字位数;日期类型DATE:DATE是Oracle提供的一个独特的数据类型,包括了一个日期和时间;长字符串类型LONG:最大可为2G的变长字符串类型;原始二进制数据RAW(IN):以字节为长度单位的原始二进制数据,最长为255字节;原始二进制数LONGRAW:与ROW相似,最长为2G字节;地址类型ROWID:数据表中每一行都有一个地址,当把一个列说明为这个类型时,则每一行在这个列中存放的是这行的地址值(十六进制),形式为:block.
row.
file.
定义表时可以指定某一个列的值不是空值,这是一种有效的保持数据完整性的手段,如在表EMP中插入一个新的雇员时必须保证该行的雇员号是已知的.
在创建表的语句中,在指定列的定义后面加上NOTNULL子句,即可保证该列是非空的.
对按下列命令创建的一个表DEPT,任何插入一行没有DEPTNO值的新数据行的企图都会失败,并引发系统报告一条错误信息:SQL>CREATETABLEDEPT(DEPTNONUMBER(2)NOTNULL,DNAMECHAR(14),LOCCHAR(13));创建表后还可以往表中增加一个新的列,新增的列在已有行的值是空值,试观察下面命令执行前后数据库的不同:SQL>ALTERTABLEDEPTADD(HEADCNTNUMBER(3));用ALTERTABLE命令改变列的宽度:SQL>ALTERTABLEDEPTMODIFYDNAMECHAR(20);除非某一列的所有值都是空值,否则既不能缩小该列的宽度,也不能改变该列的数据类型.
除非某一列的所有值都不是空值,否则不能把该列的性质定为非空.
为了方便表的操作,Oracle还提供了伪列.
伪列是一种行为像列,但又非确实在表中存在的一种表列,只可以对它进行查询,但不可以插入、删除和修改它,主要有以下几个伪列:CURRVAL:序号的当前值,序号是Oracle中的一种对象,它可以产生顺序不重复的序数;NEXTVAL:序号的下一个值;第3章结构化查询语言SQL83ROWID:表中行的地址;ROWNUM:查询结果中各行的顺序号,此顺序号是执行ORDERBY之前的顺序.
视图可以看作是表上的一个窗口,用户可以通过视图获得表中的信息,也可修改表中的数据.
视图是一种虚表,在用户的角度看来它是一个表,但它并不实际存在.
视图中的数据都来自其他表,但不是这些数据的复制.
视图具有清晰性,即根据用户的要求组织数据,而且还具有安全性,用视图可以防止未被授权的用户访问他不应该访问的行或列.
可以在同一个表上创建多个视图,创建视图的命令和创建表有所不同,在创建时可以用不带ORDERBY子句的SELECT语句来选择放入视图中的数据,如:SQL>CREATEVIEWMANAGERSASSELECTENAME,JOB,SALFROMEMPWHEREJOB='MANAGER';视图创建后可以和表一样用SELECT来查看其中的信息:SQL>SELECT*FROMMANAGERS;除非有特别的指定,视图的列名继承它的基表中的列名,创建时也可以指定不同于基表中的列名的别名,语法为:CREATEVIEWviewname(alias,alias.
.
.
)ASquery;例如:SQL>CREATEVIEWMYDEPT(PERSON,TITLE,SALARY)ASSELECTENAME,JOB,SALFROMEMPWHEREDEPTNO=10;WITHCHECKOPTION子句保证视图中的数据保持视图定义的性质,任何导致结果不满足视图定义的条件的插入和修改操作都不能执行,如在下例中创建了一个视图后,其后的修改语句就会引起错误:SQL>CREATEVIEWDEPT20ASSELECTENAME,JOB,SAL,DEPTNOFROMEMPWHEREDEPTNO=20WITHCHECKOPTION;SQL>UPDATEDEPT20SETDEPTNO=30WHEREENAME='WARD';注意:在视图中某列的修改在其基表中相应列也作相应修改,数据应保持一致.
在日常应用中,为了备份原始数据或者送一份拷贝给其他用户,又或者要做试验性的修改,在删除之前存档,都有必要对表或视图进行复制操作,复制操作是由一条带AS子句的CREATETABLE命令来实现的.
AS子句后跟的是一子查询,赋值的结果的表内包括了源表中的列和列中的数据.
84Oracle8i数据库开发与专业应用SQL>CREATETABLEEMP2ASSELECT*FROMEMP;SQL命令"DROPTABLE表名"把指定的表删除掉,被删除表中的数据将会被永久删除.
表被删除后也不能恢复.
SQL命令"DROPVIEW视图名"把指定的视图删除掉,但不会删除视图的任何基表.
3.
6SQL*Plus的报表3.
6.
1报表示例用传统的SQL命令只可以作出简单的逐行显示信息的报表,报表中不能显示统计数字,如下面的命令显示每个部门中工资超过2000美元的所有雇员,试执行并观察其结果:SQL>SELECTDEPTON,ENAME,SALFROMEMPWHERESAL>2000;如果用SQL*Plus的扩充命令,则可以生成形式灵活的多种报表,例如打入以下SQL*Plus的命令,则可以生成同样内容的一张报表,形式却有所不同:MONMAR12page1SAMPLEREPORTforHITECHCORPDEPARTMENTNAMESALARY10KING$5,000CLARK$2,450sum$7,45020FORD$3,000SCOTT$3,000JONES$2,975sum$8,97530BLAKE$2,850sum$2,850STRICTLYCONFIDENTIAL第3章结构化查询语言SQL85SQL>COLUMNDEPTNOHEADINGDEPARTMENTSQL>COLUMNENAMEHEADINGNAMESQL>COLUMNSALHEADINGSALARYSQL>COLUMNSALFORMAT$99,999.
99SQL>TTITLE'SAMPLEREPORTfor|HITECHCORP.
'SQL>BTITLE'STRICTLYCONFIDENTIAL'SQL>BREAKONDEPTNOSQL>COMPUTESUMOFSALONDEPTNOSQL>RUN3.
6.
2报表格式命令SQL*Plus的扩充命令后不需要跟分号,在打入完所有SQL*Plus的格式命令后运行即可生成报表.
打印报表可以首先定好报表的抬头和注脚,分别用TTITLE和BTITLE.
使用了TTITLE命令后每页的顶部都会自动打印当天日期和本页页号.
在TTITLE和BTITLE命令后跟的字符串中的竖线表示换行.
抬头标题和注脚标题都有三种形式:靠左、靠右和居中,分别在命令后跟关键字LEFT、RIGHT和CENTER.
标题命令在本节报表中一直有效,除非换了另一个标题,或者使用下列命令关闭标题:SQL>TTITLEOFFSQL>BTITLEOFF表的每一列在报表中的对应列的标题以HEADING指定对应关系:SQL>COLUMNENAMEHEADINGEMPLOYEESQL>COLUMNENAMEHEADING'EMPLOYEE|NAME'SQL>COLUMNENAMECLEAR如果标题只有一个单词,则无需用单引号,在字符串中的竖线字符表示换行.
上面的第三条命令把列名的指定对应关系取消.
指定了一列的格式和标题后,可以在其他列定义中用LIKE子句复制该列的定义,使两列具有完全相同的格式和标题.
SQL>COLUMNENAMEFORMATA15SQL>COLUMNSALFORMAT$99,999.
99SQL>COLUMNCOMMLIKESALBREAKON取消报表中重复出现的值的多次显示,把在该列上具有相同值的行划入同一组内输出,让该组的共同值只显示一次.
BREAKON命令必须与ORDERBY配合使用,OEDERBY对该列上的值进行排序,把相同的值放在一起.
BREAKON命令把具有相同值的行连续显示,在不同的值之间插入空行,试观察下列命令的执行结果:SQL>BREAKONDEPTNOSQL>SELECTDEPTNO,ENAMEFROMEMPORDERBYDEPTNO;请注意上面两条命令中前一条命令后不用分号,而后一条命令后必须加分号.
在生成报表时只有一条BREAKON命令有效,但可以按多列进行分组,命令格式如下:BREAKON列1ON列286Oracle8i数据库开发与专业应用下面命令产生的报表按部门分组,每两个部门之间间隔两行空行:SQL>BREAKONDEPTNOSKIP2SQL>SELECTDEPTNOENAMEFROMEMPORDERBYDEPTNO;BREAK命令的作用可用CLEARBREAK命令消除.
BREAKON命令除按列分组外,还可以按页或报表分组,分别用命令:BREAKONPAGE和BREAKONREPORT.
BREAK命令可以同时按多个条件分组,如命令:BREAKONPAGEONREPORT.
生成报表时分组的目的是为了计算关于各组信息的某些统计数据,如下列命令计算每个部门的工资总额:SQL>BREAKONDEPTNOSKIP2SQL>COMPUTESUMOFSALONDEPTNOSQL>SELECTDEPTNO,ENAME,SALFROMEMPORDERBYDEPTNO;BREAK命令后的SKIP子句把各组统计数据分开显示,使报表变得更清楚.
COMPUTER命令还可以计算关于组信息的以下统计数据:AVG组中所有值的平均数COUNT组中非空值的总数MAX组中数据的最大值MIN组中数据的最小值STD组中数据的标准差VAR组中数据的方差NUMBER组中总行数COMPUTER命令的格式为"COMPUTER统计功能名OF统计列ON分组列",COMPUTE命令的功能可以重定义,在本节报表结束时自动取消,也可以用CLEARCOMPUTER命令人工取消.
SQL*Plus运行过程中涉及到系统的一系列环境设置,可以用SHOW命令显示系统的当前设置.
SHOW命令的一般格式是"SHOW设置",显示某一特定的设置,SHOWALL则显示所有的设置.
指定系统的环境设置用SET命令,SET命令的一般格式是"SET设置值":SQL>SHOWAUTOCOMMITSQL>SETAUTOCOMMITONSET命令可以设置以下系统设置:SETAUTOCOMMIT{OFF|ON|IMMEDIATE}设置ON或IMMEDIATE使系统自动提交对所有数据的修改,OFF是系统的默认设置,系统不把修改自动提交;SETFEEDBACK{OFF|ON}设置为ON时完成查询后都会随即显示查询结果的总记录数,设置为OFF时则不会显示记录总数,系统的默认设置为ON;SETHEADING{OFF|ON}设置为ON时在查询结果显示的上端显示列名,设置为OFF则不显示列名,系统的默认设置为ON;第3章结构化查询语言SQL87SETPAGESIZE{N}每页显示的行数;SETPAUSE{OFF|ON|Text}设置为ON时显示完一页查询结果之后,要用户打一下回车键才显示下一页,设置为OFF则不用等待,用户还可以指定暂停时显示的文字,系统默认设置为OFF;SETBUFFER缓冲区,指定当前的命令缓冲区,SQL是系统默认的命令的缓冲区,SQL缓冲区只能存放一条SQL命令,如果要存放SQL*Plus命令,可以指定其他缓冲区.
SET命令设置的环境参数在用户运行的当前SQL*Plus进程中会一直有效,对于经常使用的设置可以放入LOGIN.
SQL文件中.
对于数据库中的空值,可以使用SETNULL命令,用任一字符串代替空值的显示.
试观察下面命令的执行结果,在部门30中没有佣金的雇员会显示"NODATE".
SQL>SETNULL'NODATA'SQL>SELECTENAME,COMMFROMEMPWHEREDEPTNO=30;3.
6.
3编辑文件命令用户可以把当前SQL命令存放在一个文件中.
命令格式是"SAVE文件名",如果用户在文件名中未指定后缀,系统会自动为文件加上.
SQL后缀,执行下面命令后在用户的目录上就生成了一个RESEARCH.
SQL文件.
SQL>INPUT1.
SELECTEMPNO,ENAME,JOB2.
FROMEMP3.
WHEREJOB='ANALYST'4SQL>SAVERESEARCH在SQL*Plus中可以运行主系统提供的编辑器,命令为:SQL>EDITEDIT命令编辑当前缓冲区中的内容,编辑过程中对缓冲区内容的修改都会存入缓冲区中,退出编辑后即能返回到SQL*Plus中.
如果要编辑一文件,只需在EDIT后加文件名,如果用户未指定文件的后缀,系统会自动加上.
SQL后缀:SQL>EDITRESEARCHSQL>RUNSTART命令把一磁盘文件的内容读入到SQL命令缓冲区并在屏幕上显示,文件内容调入缓冲区后即可用RUN命令来运行:SQL>GETRESEARCHSQL>RUNSTART命令把一命令文件的内容调入缓冲区并运行,该命令文件中包括SQL*Plus的扩充命令和SQL命令.
GET命令和START命令后的文件名都不用指定.
SQL后缀.
SPOOL命令把查询的结果存放在一用户指定的磁盘文件中,存放形式和屏幕上的显示形式一样.
如果用户未指定磁盘文件名的后缀,系统会自动加上后缀表明该文件是一列表88Oracle8i数据库开发与专业应用文件,具体的后缀名由操作系统设定.
SQL>SPOOLTRYFILESQL>SPOOLOFFSQL>SPOOLOUT上面的第二条命令终止,把查询结果输出到文件中,第三条命令把查询结果送到系统默认的打印机上打印出来,这两条命令都会关闭当前的输出文件.
在SQL*Plus中可以使用系统的编辑器生成一个含有SQL*Plus扩充命令和SQL命令的命令文件.
文件中每一条SQL命令后都要有分号,或者在其后的一行中写一斜杠,该行除斜杠外没有其他字符,下面命令生成一命令文件并执行文件的内容,方框内为编辑器显示的内容:SQL>EDITTRYFILESQL>STARTTRYFILE3.
7函数3.
7.
1基本函数SQL*Plus中的函数主要用于修改数据库中的值,结合一些原有的值计算出新的值或者改变值的显示形式,函数可以应用于任何类型的查询中,包括复杂查询.
函数和表达式一样可以用于SELECT子句、WHERE子句和ORDERBY子句中,但和表达式不同的是函数使用时总带有参数.
函数的一般使用形式是"函数名(参数)",即在函数名后跟括号,括号内是调用函数的参数.
调用函数时往往不只一个参数,如求子串函数SBUSTRSETECHOOFFSETAUTOCOMMITOFFSETPAGESIZE25INSERTINTOEMP(EMPNO,ENAME,HIREDATE)VALUES(9999,'GEIGER',SYSDATE);INSERTINTOEMP(EMPNO,ENAME,DEPTNO)VALUES(3333,'SAMSON',20);SPOOLNEW-EMPSELECT*FROMEMPWHEREDEPTNO=20ORDEPTNOISNULL/SPOOLOFFSETAUTOCOMMITOFF第3章结构化查询语言SQL89(DNAME,1,4).
在调用函数的参数表中第一个参数必定是调用参数的主体,下面命令选出名字长度为6的雇员:SQL>SELECTENAMEFROMEMPWHERELENGTH(ENAME)=6;SQL中函数可以按返回值的数据类型分为数值函数、字符函数和日期函数,也可以按作用范围分为个体函数,即把各行分开进行独立的求值的函数,还有组函数,即把多行聚集为一组进行求值的函数,下面分别进行讨论.
SQL*Plus中共有15个字符函数,最常用的有:INITCAP(ename):把每一个词的第一个字母变为大写,如:jacksmith变为JackSmithsmith-jones变为Smith-Jonessmith,jack变为Smith,JackLENGTH(ename):计算字符串中字符的个数,即字符串的长度,如:LENGTH('ALLEN')=5LENGTH('KING')=4SUBSTR(job,s,l):返回字符串中从第s个字符开始的1个字符,如:SUBSTR('CLERK',1,4)='CLER'SUBSTR('SALESMAN',1,4)='SALE'LOWER函数:把一个字符串中的所有字符变为小写;UPPER函数:把一个字符串中的所有字符变为大写;LEAST函数:返回一系列值中最小的一个,字符串的大小是按字典顺序来比较的;GREATEST函数:返回一系列值中最大的一个.
最常用的日期函数有:ADD-MONTHS函数:进行日期的加法,如ADD-NONTHS(hiredate,5)在雇佣日期上加五个月;MONTHS-BETWEEN函数:返回两个日期之间的月份数,如MONTHS-BETWEEN(sysdate,hiredate)返回当前日期和雇佣日期之间的月份数;NEXT-DAY函数:返回指定日期的最近一个星期数的日期,如:NEXT-DAY(hiredate,'friday'):返回雇佣日期的第一个星期五的日期,又如,下面的SQL命令显示出下一个星期五部门20的发薪情况:SQL>SELECTENAME,SAL,NEXT-DAY(SYSDATE,'FRIDAY')AS-OFFROMEMPWHEREDEPTNO=20;日期类型的数据在Oracle中以系统默认的格式显示,用户也可以用TO-CHAR函数来控制日期的显示格式.
该函数的格式是TO-CHAR(日期,日期格式),返回一个按指定格90Oracle8i数据库开发与专业应用式显示日期的字符串,试观察下面的执行结果:SQL>SELECTENAME,TO-CHAR(HIREDATE,'Dy,Mondd,yyyy')HIREDFROMEMPWHEREDEPTNO=10;结果为:ENAMEHIREDCLARKTueJun09,1981KINGTueNov19,1981MILLERSatJan23,1982日期类型的数据的内部存储日期可以精确到秒.
TO-DATE函数执行和TO-CHAR函数相反的功能,把一特定格式的字符串转换为一个Oracle的日期类型的数据,该函数的格式是TO-DATE(字符串,日期格式),如:SQL>INSERTINTOEMP(EMPNO,ENAME,HIREDATE)VALUES(7999,'ASMS',TO-DATE('070387083000','MMDDYYHHMISS'));日期格式是一个用单引号括起来的字符串,字符串的内容表达日期的显示格式:星期格式有:DD数字形式12DY缩写的星期形式FRIDAY全拼的星期形式FRIDAYDDSPTH序数法表示的日期TWELFTH月份格式有:MM数字形式03MON缩写的月份形式MARMONTH全拼的月份形式MARCH年份的格式有:YY只显示年份87YYYY显示年份和世纪1987另外,还可以使用修饰符FM和FX在日期格式中进行格式修饰:FM在TO-CHAR函数中去除返回值的尾部空格或前导零(返回值中前面的零);FX在TO-CHAR函数中要求字符串参数与日期格式精确匹配.
下面是使用日期格式的几个例子:Mar12,1987'Mondd,yyyy'MAR12,1987'MONdd,yyyy'ThursdayMARCH12'DayMONTHdd'Mar1211:00am'Monddhh:miam'Thu,thetwelfth'Dy,"the"ddspth'数值函数是对表或视图中的一组数据进行计算,如下面例子中数值函数LEAST求两个参数中的最小者,即找出雇员号小于其上司的雇员号的所有雇员.
第3章结构化查询语言SQL91SQL>SELECTENAME,EMPNO,MGR,LEAST(EMPNO,MGR)LOWNUMFROMEMPWHEREEMPNO0则返回+1;TRUNC(COMM-SAL):把工资数截断到最接近的整数,即没有小数位.
在Oracle数据库中任何数加空值都是空值,因此同时提供了函数NVL让用户对空值进行适当处理.
该函数的格式是NVL(参数1,参数2).
如果参数1非空,则返回该数的值,否则返回参数2的值,如下面的例子显示部门30的雇员的收入情况,注意比较两列显示结果的不同:SQL>SELECTENAME,COMM+SAL,NVL(COMM,0)+SALFROMEMPWHEREDEPTNO=30;3.
7.
2组函数组函数通常计算多行数据,然后返回一个值,主要用于计算数值类型的数据,也可以用于计算一些字符型或日期型的数据.
但应注意的是,除非在查询语句中使用了DROUPBY子句来分组,否则不能同时显示单个数据和组函数返回的数据.
如下面的第一条命令计算所有雇员的总佣金,第二条命令是错误的:SQL>SELECTSUM(COMM)FROMEMP;SQL>SELECTENAME,SUM(COMM)FROMEMP;MIN、MAX和COUNT三个组函数可以用于字符型、日期型和数值型三种类型的数据,试比较下面三种数据类型的执行结果:SQL>SELECTMIN(ENAME)FROMEMP;SQL>SELECTMIN(HIREDATE)FROMEMP;SQL>SELECTMIN(SAL)FROMEMP;COUNT函数返回数值的总个数,COUNTDISTINCT则忽略出现的数值,如下面的命令中,第一条是统计多少人有工作,第二条则是统计共有多少种不同的工作:SQL>SELECTCOUNT(JOB)FROMEMP;SQL>SELECTCOUNT(DISTINCTJOB)92Oracle8i数据库开发与专业应用FROMEMP;下面几个组函数只对数据型的数据有效:AVG计算一组数据的标准差,下面的命令计算雇员的平均工资:SQL>SELECTAVG(SAL)FROMEMP;STDDEV计算一组数据的标准差,下面的命令计算雇员工资的标准差:SQL>SELECTSTDDEV(SAL)FROMEMP;SUM计算一组数据的总和,下面的命令计算雇员的工资总额:SQL>SELECTSUM(SAL)FROMEMP;在查询语句中的GROUPBY子句把结果行按一定条件进行分组,分组后每一组内的行必定在指定的某一列或某几列上有相同的值.
进行分组的查询返回的结果是按每行一组的形式来显示的,如下例计算每个部门的总工资和平均工资:SQL>SELECTDEPTNO,SUM(SAL),AVG(SAL)FROMEMPGROUPBYDEPTNO;在解决一些实际问题时往往要根据多个列进行分组,如下面的命令中,第一条命令统计每个部门中的雇员数,第二条命令则按两列进行分组,统计每个部门中从事不同工作的雇员的总数:SQL>SELECTDEPTNO,COUNT(*)FROMEMPGROUPBYDEPTNO;SQL>SELECTDEPTNO,JOB,COUNT(*)FROMEMPGROUPBYDEPTNO,JOB;分组以后可以用HAVING子句来选择符合指定条件的组,HAVING子句和WHERE子句有些类似,但作用不同.
WHERE是指定SELECT的条件,而HAVING子句则是指定GROUP的条件,即选择分组的结果,如下例中找出总工资超过9000美元的部门:SQL>SELECTDEPTNO,SUM(SAL)FROMEMPGROUPBYDEPTNOHAVINGSUM(SAL)>9000;介绍了组函数有必要对查询语句的语法作一个小结,查询的语法总结为:SELECT列1,列2,…,列NFROM表1,表2,…,表NWHERE关于列的选择条件GROUPBY列1,列2,…,列NHAVING关于组的选择条件ORDERBY列1,列2,…,列N第3章结构化查询语言SQL93下面一个例子使用了所有列出的子句,找出所有工资超过8000的部门,计算时不包括办事员的工资在内,显示时先显示工资低的部门:SQL>SELECTDEPTNO,SUM(SAL)FROMEMPWHEREJOB!
='CLERK'GROUPBYDEPTNOHAVINGSUM(SAL)>8000ORDERBYSUM(SAL);3.
8复杂查询3.
8.
1连接运算连接就是把来自不同的表的列组合起来形成一个新表的结果,下例是一个简单的连接操作:SQL>SELECTEMPNO,ENAME,JOB,EMP,DEPTNO,DNAMEFROMEMP,DEPTWHEREEMP.
DEPTNO=DEPT.
DEPTNO;在表名后的句点是为了明确指定其后的列来自哪一个表,从而避免了歧义性.
WHERE子句则指定了连接条件,如果未指定连接条件即没有WHERE子句,就会生成笛卡儿积:SQL>SELECTENAME,EMP.
DEPTNO,LOCFROMEMP,DEPT;在做连接时可能发生这样的情况,某一部门(如部门40)在部门表中有一个记录,但在雇员表中没有该部门的雇员,如果做连接就会丢失了部门40的信息,因此提供了一种称为外连接的操作,把部门40放入连接后的表中,但相应的雇员信息则为空值,外连接的符号是(+).
试观察下面命令的执行结果:SQL>SELECTENAME,DEPT.
DEPTNO,LOCFROMEMP,DEPTWHEREEMP.
DEPTNO(+)=DEPT.
DEPTNO;一个表与自身做连接称为自连接,连接时把一个表视为两个独立的表,因而必须至少在FROM子句中为其中一个表指定列名,以免发生混淆,如下例中找出每个雇员的经理的名字:SQL>SELECTWORKER.
ENAME,MANAGER.
ENAME,MANAGERFROMEMPWORKER,EMPMANAGERWHEREWORKER.
MGR=MANAGER.
EMPNO;对于做连接时在WHERE子句中指定的连接条件是相等,称该连接为相等连接或自然连接,如果连接条件不是相等,则称该连接为非相等连接,如下例中涉及到一个工资的分级表,并找出工资为第三级的所有雇员:SQL>SELECTENAME,SAL94Oracle8i数据库开发与专业应用FROMEMP,SALGRADEWHEREGRADE=3ANDSALBETWEENLOSALANDHISAL;在关系数据库中一个表是行的集合,因而可以在连接结果的表之间做集合运算.
SQL中有三种集合运算:并、交、差.
并运算(UNION)把两个表中的所有行合并起来,删去重复出现的行.
交运算(INTERSECT)的结果是所有在两个表中都存在的行.
差运算(MINUS)的结果是只出现在第一表中的行.
在介绍运算的例子之前假设有如下三个视图:ACCOUNTVIEWENAMESALJOBCLARE2,450MANAGERKING5,000PRESIDENTMILLER1,300CLERKSALESVIEWENAMESALJOBALLEN1,600SALESMANWORD1,2500SALESMANMARTIN1,250SALESMANBLAKE1,500SALESMANTURNER1,500SALESMANJAMES950CLERKRESEARCHVIEWENAMESALJOBSMITH800CLERKJONES2,975MANAGERSCOTT3,000ANALYSTADAMS1,100CLERKFORD3,000ANALYST第3章结构化查询语言SQL95在下例中用并运算找出各个部门中工资超过2000美元的雇员,参与并运算的各个表的对应列的数据类型必须是一样的:SQL>SELECTENAME,SALFROMACCOUNTWHERESAL>2000UNIONSELECTENAME,SALFROMRESEARCHWHERESAL>2000UNIONSELECTENAME,SALFROMSALESWHERESAL>2000交运算找出各个表中的相同行,在下例中找出每个部门都有的工作:SQL>SELECTJOBFROMACCOUNTINTERSECTSELECTJOBFROMRESEARCHINTERSECTSELECTJOBFROMSALES;差运算找出只在第一个查询中出现的行,在下例中找出在会计部有而销售部没有的工作:SQL>SELECTJOBFROMACOUNTMINUSSELECTJOBFROMSALES;3.
8.
2子查询在查询的WHERE子句中还可以嵌套其他查询,该查询称为子查询.
子查询是相对于主查询而言的,是为了完成特定要求的询问而设计的.
如下例中找出与SMITH在同一部门工作的雇员:SQL>SELECTENAME,DEPTNOFROMEMPWHEREDEPTNO=(SELECTDEPTNOFROMEMPWHEREENAME='SMITH');96Oracle8i数据库开发与专业应用执行这个查询时先做子查询,找出SMITH所在部门的部门号,然后做主查询,找出在该部门中工作的所有雇员.
事实上可以嵌套多层的子查询,子查询可以使用主查询没有使用到的表,但不能有ORDERBY子句.
子查询的结果可以用来做关系比较运算,如下例找出和CLARK有同样工作的或工资比CLARK高的雇员:SQL>SELECTENAME,JOB,SALFROMEMPWHEREJOB=(SELECTJOBFROMEMPWHEREENAME='CLARK')ORSAL>(SELECTSALFROMEMPWHEREENAME='CLARK');做子查询可以同时从多个表中获取信息,如下例中找出在纽约工作且工资比SCOTT高的雇员:SQL>SELECTENAME,JOB,SALFROMEMP,DEPTWHERELOC='NEWYORK'ANDEMP.
DEPTNO=DEPT.
DEPTNOANDSAL>(SELECTSALFROMEMPWHEREENAME='SCOTT');如果上面查询中的SCOTT是指在达拉斯工作的SCOTT,即该公司不止一个SCOTT,则应在上面的子查询中加入这一条件.
最后要注意使用组函数的一点问题.
单列名和组函数不能在查询结果中同时使用,否则会出错.
但可以把组函数放入子查询,如下面两条命令中第一条会出错,而第二条则不会:SQL>SELECTENAME,MIN(HIREDATE)FROMEMP;SQL>SELECTENAME,HIREDATEFROMEMPWHEREHIREDATE=(SELECTMIN(HIREDATE)FROMEMP);3.
9特权和角色特权是指可执行某一特定的SQL语句类型的能力,如:登录数据库系统(创建一次会第3章结构化查询语言SQL97话),创建表,查询其他用户的表等等.
Oracle中的数据安全性管理机制把特权分为两类:系统特权和目标特权.
系统特权:是指对某一特定类型的目标可以采取某一特定行为的能力,如:创建表空间,删除任意表的记录等,都属于系统特权;目标特权:是指对特定的表、视图、序号、过程、函数或程序包可以采取某一特定行为的能力,如:从DEPT表中删去记录的能力即是目标特权.
特权的授予和回收用命令GRANT和REVOKE来实现.
例如:对于获得表EMP的目标特权来说,可以有两种途径,或者它是用户自己创建的一个表,或者从表的拥有者那里获得授权.
授权命令是GRANT,可授权的特权有六种:SELECT、INSERT、UPDATE、DELETE、ALTER和INDEX.
下面的第一条命令把两种特权授予用户SCOTT,第二条命令把所有的特权授予SCOTT:SQL>GRANTSELECT,INSERTONEMPTOSCOTT;SQL>GRANTALLONEMPTOSCOTT;从其他用户处获得授权SELECT后,就可以对表进行读取.
在下面的第一条命令中指定表所属的用户的用户标识,还可以给来自其他用户的表指定一个别名,第二条命令给ALLEN表EMP指定一个别名EMPLOYEE,指定完成后就可以在查询时用表名EMPLOYEE了:SQL>SELECT*FROMSCOTT.
EMP;SQL>CREATESYNONYMEMPLOYEEFORALLEN.
EMP;存取其他用户的表时系统可能会报告"表或视图不存在".
这种问题有两个可能的原因,其一是并未获得该用户的授权,不能存取这个表或视图;其二是这个表或视图确实不存在.
给其他用户授权时可以把对表的授权权力同时授予他,以后该用户就可以再把这个表的存取权限授予其他用户,如:SQL>GRANTALLONEMPTOSCOTTWITHGRANTONTION;系统特权的授权方式与目标特权的授权方式基本一致,只是在把系统特权授予用户的同时,又把这一系统特权的授权权力授予他了,使用的是WITHADMINOPTION,如:SQL>GRANTCREATESESSIONTOSCOTTWITHADMINOPTION;授权后还可以撤消,撤消命令如下:SQL>REVOKEINSERTONEMPFROMSCOTT;98Oracle8i数据库开发与专业应用Oracle提供了一种称之为角色的机制来简化特权管理过程,角色是相关的特权的集合.
在使用角色之前必须先创建它,例如,创建角色ACCTS-PAY:SQL>CREATEROLEACCTS-PAY;之后我们可以把多个系统特权或目标特权授予它,接着我们再把角色授予某个用户,这样,这个用户就具有了角色中所包含的特权了.
下面的命令表示了这一过程:SQL>GRANTCREATESESSIONTOACCTS-PAY;SQL>GRANTINSERTONEMPTOACCTS-PAY;SQL>GRANTACCTS-PAYTOSCOTT;为了与前面的版本兼容,在Oracle数据库系统中预定义了一些角色,这些角色是DBA、RESOURCE、CONNECT、EXP-FULL-DATABASE和IMP-FULL-DATEBASE.
3.
10索引使用索引可以提高RDBMS查询大型表的速度,因为索引查询不是在整个表中搜索,所以使用索引进行导向的效率会更高,为表创建索引命令:SQL>CREATEINDEXEMP-ENAMEONEMP(ENAME);删除已产生的索引命令:SQL>DROPINDEXEMP-ENAME;在实际应用中一般只对较大型的表(如多于50行以上)进行索引.
在做索引以前要先输入数据,在数据库中一个表可以有多个索引.
一般来说应该对表的主键做索引.
索引产生后由系统自动地根据表中数据的变化作相应地改动.
索引的使用并不会引起和SQL语法的冲突.
为了进一步提高性能,有必要保证索引列中的每一个值都是唯一的,例如在表EMP中应保证每一个雇员只出现一次:SQL>CREATEUNIQUEINDEXEMP-EMPNOONEMP(EMPNO);这样一个保证唯一性的索引建立后,再向表插入一行,其雇员号与已有的一个雇员号相同时,系统会发出错误信息.
3.
11并发控制在一个单用户实现环境下,用户可在一个事务中修改他的数据而不必考虑有其他用户在同一时刻也在操作这一数据.
然而,在多用户实现环境下,这个问题则必须考虑,这就是并发事务的控制问题.
这个问题的核心是如何保证数据的并发性和一致性.
一般来说,在并发事务中,我们采用锁的机制来控制数据的并发性、完整性和一致性.
锁分为两种:排他锁和共享锁.
排他锁禁止对资源的共享,共享锁允许对资源在某种程度上共享.
另一方面,锁可以加在整个表上和表中某些记录行上.
行级锁:是加在表中某些行上的排他锁,在释放前,其他事务不能对这些行操作.
第3章结构化查询语言SQL99当发出命令INSERT、UPDATE、DELETE和带FORUPDATE子句的SELECT,Oracle总是在执行的对象上加行级锁;表级锁:一个事务在使用这些DML(数据操作语言)语句时需要表级锁:INSERT、UPDATE、DELETE,带有FORUPDATE子句的SELECT和LOCKTABLE,表级锁的目的是保证数据的共享性以及禁止不妥当的DDL(数据定义语言)操作;锁释放:提交或回滚事务时.
在大多数情况下,锁的获取是由Oracle自动进行的,不需要用户关心这些细节.
Oracle总是自动地加上最低级的锁以保证最高度的数据共享性.
图3-5列出了执行有关的DML语句时,Oracle加锁的锁类型.
DMLStatementRowLocksModeofTableLockSELECT…FROMtableINSETRINTOtable…√RXUPDATEtable…√RXDELETEFROMtable…√RXSELECT…FROMtable…FORUPDATEOF…√RSLOCKTABLEtableIN…ROWSHAREMODERSROWEXCLUSIVEMODERXSHAREMODEXSHAREEXCLUSIVEMODESRXEXCLUSIVEMODEXRS:rowshareSRX:sharerowexlusiveRX:rowexclusiveX:exclusiveS:share图3-5DML语句加锁情况在一些特定情况下,用户可能希望由自己控制并发事务的表级锁,这就需要使用LOCKTABLE命令(图3-6).
手工加锁会覆盖Oracle的自动加锁.
要记住,当锁住了一个表时,就限制了其他用户对这个表的存取能力,一直到提交或回滚了事务.
另外,任何类型的锁都不影响查询操作,查询操作不会对一个表加锁.
图3-6LOCKTABLE命令的基本语法100Oracle8i数据库开发与专业应用其中lockmode是下面中的一种:ROWSHARE:指出握有这个锁的事务已经对表中某些行加好了锁,并准备进一步的操作.
它允许其他事务对这个表作各种操作,但不允许对表作EXCLUSIVE模式的锁;ROWEXCLUSIVE:指出握有这个锁的事务已经对表中某些行作了修改.
它允许其他事务对这个表作各种操作,但不允许对表作EXCLUSIVE,SHAREROWEXCLUSIVE,SHARE模式的锁;SHAREUPDATE:与ROWSHARE同义,为了与前面的版本兼容;SHARE:仅允许其他事务对表作查询,使用带FORUPDATE子句的SELECT,以及用SHARE模式的锁.
不允许对表作更新,删除,插入操作,不允许对表作SHAREROWEXCLUSIVE,ROWEXCLUSIVE和EXCLUSIVE模式的锁;SHAREROWEXCLUSIVE:仅允许其他事务对表做查询,使用带FORUPDATE子句的SELECT,不允许对表作更新、删除、插入操作,不允许对表作SHARE,SHAREROWEXCLUSIVE,ROWEXCLUSIVE和EXCLUSIVE模式的锁;EXCLUSIVE:仅允许其他事务对表作查询,此外任何操作都不允许.
3.
12管理员使用的SQL*Plus在此将讨论主要集中在DBA感兴趣的特性方面,包括EXECUTE、AUTOTRACE和各种各样的新特性,还有鲜为人知且较少用到的特性(COPY命令、禁止命令).
3.
12.
1系统管理的SQL*Plus有两个文件glogin.
sql和login.
sql用于SQL*Plus.
glogin.
sql文件是全局设置文件,login.
sql文件是为个人使用准备的.
这两个文件包含Oracle用户激活SQL*Plus所执行SQL*Plus的命令和/或SQL语句.
首先读和执行glogin.
sql文件,然后是用户的login.
sql文件.
glogin.
sql文件位于$ORACLE_HOME/sqlplus/admin目录下.
Oracle数据库系统管理员可以自定义该文件含有SQL*Plus命令、SQL语句和PL/SQL块,它们在每个SQL*Plus用户开始他或她的SQL*Plus会话时被执行.
glogin.
sql文件也被称作节点资源文件.
在Windows95/NT4.
0环境下,glogin.
sql文件位于%ORACLE_HOME%\PLUSnn目录下,这里的nn代表机器上安装的SQL*Plus版本号.
例如,如果安装的是SQL*Plus3.
3版,目录名将是%ORACLE_HOME%\PLUS33.
1.
使用SQL*Plus环境变量SQL*Plus里使用两个环境变量:SQLPATH和编辑器.
SQL*Plus使用环境变量SQLPATH指示login.
sql文件所在的目录.
换句话说,SQL*Plus将查看SQLPATH中定义的每个目录以找到login.
sql,使用本地目录(当启动SQL*Plus时所在的目录)启动SQL*Plus.
例如,如果希望SQL*Plus首先在本地目录下查找login.
sql文件,然后在根目录下查找,最后再查找其他目录,那么如下设置SQLPATH:$SQLPATH=".
:$HOME:";exportSQLPATH_(Bourne/Kornshell)第3章结构化查询语言SQL101$setSQLPATH=(.
$HOME)_Cshell在Windows95/NT4.
0环境下,SQLPATH在注册表中定义,缺省值是$ORACLE_HOME\DBS(在安装期间设置的).
ORACLE_HOME的值在Windows95中为C:\ORAWIN95,在NT4.
0中为C:\ORANT(如果没有将Oracle安装在C:驱动器上,使用安装Oracle的磁盘驱动器符号代替C:).
在Windows95/NT4.
0环境下,login.
sql文件位于%ORACLE_HOME%\DBS目录下,这是SQLPATH的缺省值.
在Windows95/NT4.
0环境下要设置或改变SQLPATH的值,遵照以下步骤:(1)在Start菜单中选择Run;(2)输入regedit.
exe/regedit32.
exe(分别对应于Windows95/NT4.
0环境);(3)点击OK;(4)双击HKEY_LOCAL_MACHINE;(5)双击SOFTWARE;(6)双击Oracle;(7)双击SQLPATH;(8)EditString对话框出现,在ValueData域输入新的SQLPATH值;(9)点击OK;(10)在Registry菜单,选择Exit;(11)重新启动机器,以便让新的值起作用(或者注销并再次登录进入WindowsNT4.
0).
SQLPATH还被SQL*Plus用于指示在SQL*Plus中运行的SQL脚本的位置.
在glogin.
sql或login.
sql中还可以设置另外一个环境变量,这个环境变量称为_editor,它定义了可以用于编辑SQL*Plus命令的编辑器.
要设置编辑器为vi文本编辑器,在glogin.
sql或login.
sql文件中输入下面的代码行:define_editor=vi;在Oracle8.
1.
x中,可以在工作过程中更改编辑器,进入Edit|Editor|Defineeditor并输入"Notepad"(笔记本)或"vi".
如果使用任何其他的文本编辑器,将"vi"替换为相应的名称.
有关使用不同编辑器的更多信息,稍后在第5点中再做讨论.
2.
激活/访问SQL*Plus要在操作系统提示符下激活SQL*Plus,请使用下列命令:$sqlplus[[-S[ILENT]][logon][start]|-当在一个脚本中运行SQL*Plus时,使用-S[ILENT]参数,因为它消除了SQL*Plus被激活时显示的全部信息,例如SQL*Plus标志、提示信息和命令行提示符.
[logon]部分需要下面的语法结构:username[/password][@connect_string]NOLOG[start]子句让你能够启动SQL*Plus并运行一个包含SQL*Plus命令、SQL语句或PL/SQL块的任意组合的命令文件.
另外,可以向这个命令文件传递参数.
start子句要求下面的语法:@file_name[.
exe][arg.
.
.
]如果没有输入用户名和/或口令,SQL*Plus提示输入它们.
102Oracle8i数据库开发与专业应用在成功地启动SQL*Plus后,可以在SQL*Plus提示符(SQL>)状态下输入三种类型的命令:(1)用于处理数据库对象和操作数据库中存储的数据的SQL命令/语句;(2)用于处理数据库对象和操作数据库中存储的数据的PL/SQL块;(3)用于设置选项、编辑、存户和提取SQL命令与PL/SQL块以及格式化查询输出结果的SQL*Plus命令.
要向SQL*Plus提交一条SQL命令,请在命令的结尾处输入一个分号(;)并且按下回车键.
SQL*Plus执行该命令,显示查询的结果,并且返回到提示符状态.
要结束一个PL/SQL块,在它自己的行上输入一个小数点即可.
要提交一个PL/SQL块用于执行,在PL/SQL的行上用一条斜线(/)结束它并按下回车键.
3.
编辑SQL命令如果在输入一条SQL命令时出现一个错误并且希望改正它,或者如果希望运行仅仅稍加改动的最后一条命令,SQL*Plus将最近输入的SQL命令存储在一个缓冲区中,该缓冲区被称为SQL缓冲区.
SQL*Plus提供了一系列命令来提取并编辑存储在该缓冲区中的SQL语句和PL/SQL块.
注意:SQL*Plus命令没有存储在该缓冲区中,所以,它们不能被提取和修改.
但是,有一种方法可以在该缓冲区中存储SQL*Plus命令,这种方法在稍后第4点中讨论.
表3-1列出了用于查看、编辑和运行SQL*Plus缓冲区中内容的命令.
表3-1用于SQL缓冲区的SQL*Plus命令命令缩写作用APPEND文本A文本在一行尾部添加文本CHANGE旧文本/新文本C旧文本/新文本使用新文本更新一行中的旧文本CHANGE/文本C/文本从一行中删除文本CLEARBUFFERCLBUFF删除全部文本DEL(无)删除缓冲区中的当前行INPUTI在缓冲区中添加一行或多行INPUT文本I文本添加一条文本组成的行LISTL列出SQL*Plus缓冲区中的内容LISTnLn或n列出第n行LIST*L*列出当前行LISTmnLmn列出第m行到第n行LISTLASTLLAST列出缓冲区中的最后一行除LIST命令外,所有其他的编辑命令仅影响缓冲区中的一行,该行被称为当前行,当列出SQL命令或PL/SQL块时,当前行用星号标记出来.
当运行LIST命令时,当前行总是缓冲区中的最后一行.
还要注意终结一条SQL命令的分号(;)没有存储在缓冲区中,如表3-2所示.
第3章结构化查询语言SQL103表3-2存储在缓冲区中的SQL语句SQL>LIST1SELECTempno,deptno,job,sal,comm2FROMemp3WHEREcomm.
ISNOTNULL如果得到一条错误信息,含有错误信息的行成为当前行,这样就可以立即编辑该行并纠正错误,表3-3显示了带有错误的程序清单.
表3-3带有错误的行成为当前行SQL>SELECTempno,empname,deptno,job,sal,comm2FROMemp3WHEREcommISNOTNULL;SELECTempno,empname,deptno,job,sal,comm.
ERRORatline1:ORA-00904:invalidcolumnname4.
输入并编辑SQL*Plus命令直接在SQL*Plus提示符下输入SQL*Plus命令(例如DESCRIBE)不保存在SQL缓冲区中.
所以,不能够提取最后输入的SQL*Plus命令来编辑并/或再次运行它.
试图从缓冲区中列出一条SQL*Plus命令的结果如表3-4所示.
表3-4SQL*Plus命令没有被保存在缓冲区中SQL>DESCRIBEEMPNameNullTypeEMPNONOTNULLNUMBER(4)ENAMEVARCHAR2(10)JOBVARCHAR2(9)MGRNUMBER(4)HIREDATEDATESALNUMBER(7,2)COMMNUMBER(7,2)DEPTNONOTNULLNUMBER(2)SQL>LISTNOlinesinSQLbuffer.
要在缓冲区中存储SQL*Plus命令,请输入不带有文本的INPUT命令并且按下回车键.
SQL*Plus使用了一个行号提示你可以输入命令.
当完成命令输入时,按下回车键输入一行空行.
表3-5显示了一个示例.
104Oracle8i数据库开发与专业应用表3-5在缓冲区中存储SQL*Plus命令SQL>INPUT1DESCRIBEEMP2SQL>L1*DESCRIBEEMP不可以从缓冲区中执行该命令,但是可以将它保存在一个文件中,可以以后在SQL*Plus中检索并执行这个文件.
表3-6显示了从缓冲区中执行一个SQL*Plus命令的尝试失败,后来成功地将它保存到文件中.
表3-6保存SQL*Plus命令到文件SQL>RUN1*DESCRIBEEMPDESCRIBEEMP*ERRORatline1:ORA-00900:invalidSQLstatementSQL>SAVEtestCreatedfiletest.
SQL>GETtest1*DESCRIBEEMP新创建的文件被保存在由SQLPATH环境变量指定的目录中.
5.
在SQL*Plus中使用你的操作系统编辑器SQL*Plus提供的编辑能力非常有限,而且相对于其他的文本编辑器也不直观(例如,不能使用箭头键、HOME键或END键).
所以许多用户喜欢使用他们自己感到满意的编辑器来创建命令文件,然后在SQL*Plus中使用START命令或@命令运行这些文件.
如果宁愿使用操作系统的编辑器而不愿使用SQL*Plus的编辑功能,可以在SQL*Plus中使用EDIT命令实现这种操作.
EIDT命令的语法为:EDIT[file_name[.
ext]]上述命令将会使用glogin.
sql和login.
sql文件中变量_editor指定的编辑器打开名为file_name的文件.
如果想在SQL*Plus会话里使用另一种编辑器,可以使用SQL*Plus命令DEFINE重新定义_editor变量:DEFINE_editor=emacs;如果_editor变量没有定义,EDIT命令尝试使用操作系统缺省的编辑器(例如,在Windows95环境下的记事本(Notepad)).
当发出EDIT命令时,从SQL*Plus内部激活一个编辑器而不需要退出SQL*Plus,这样是非常方便的.
如果运行EDIT命令时没有提供一个文件名,SQL*Plus将在一个文件中保存SQL缓冲区中的内容并使用编辑器打开这个文件.
在缺省情况下,该文件的名称为afiedt.
buf,它创建在当前目录下或由SQLPATH环境变量定义的目录下.
当打开编辑器的时候,可以使用你希望编辑的文件的全路径名,例如:EDITC:\MYDIR\MYFILE.
SQL.
第3章结构化查询语言SQL105SQL>EDITWrotefileafiedt.
buf通过在editfile变量中设置合适的值,可以更改SQL*Plus用于保存缓冲区内容的文件的名称,见表3-7.
表3-7被编辑的文件有一个缺省名称SQL>SHOWeditfileeditfile"afiedt.
buf"SQL>SETeditfile"buffer.
ext"SQL>SHOWeditfileeditfile"buffer.
txt"当运行EDIT命令时,如果没有输入一个文件名并且SQL缓冲区为空,SQL*Plus返回一个通知消息,见表3-8.
表3-8没有保存任何东西的空缓冲区SQL>CLEARBUFFERbufferclearedSQL>EDITNothingtosave.
缺省的文件扩展名为.
sql.
所以,如果没有指定一个文件扩展名,SQL*Plus将查找名为file_name.
sql的文件.
如果想编辑一个扩展名不是.
sql的文件,必须明确指定文件的扩展名.
还可以通过SUFFIX变量更改文件扩展名的缺省值,见表3-9.
表3-9更改缺省的扩展名SQL>SHOWSUFFIXsuffix"SQL"SQL>SETSUFFIXshSQL>SHOWSUFFIXsuffix"sh"SUFFIX变量只适用于命令文件,不适用于输出文件.
依赖于操作系统,输出文件的缺省扩展名是.
lst或.
lis.
6.
运行SQL*Plus命令可以采用三种方式运行SQL命令和PL/SQL块:(1)命令行方式;(2)SQL缓冲区方式;(3)命令文件方式(非正式地称为SQL脚本).
为了以缓冲区方式执行SQL命令或PL/SQL块,SQL*Plus提供了RUN命令和"/"命令.
RUN命令的语法是:R[UN]RUN命令列出并执行当前存储在缓冲区中的SQL命令或PL/SQL块.
假设缓冲区中包含以下查询:SELECTempno,ename,FROMemp使用RUN命令运行这个查询,见表3-10.
106Oracle8i数据库开发与专业应用表3-10使用RUN命令运行一个查询SQL>RUN1*SELECTempno,enameFROMempEMPNOENAME7369SMITH7499ALLEN7521WARD7566JONES7654MARTIN7698BLAKE7782CLARK7788SCOTT7839KING7844TURNER7876ADAMS7900JAMES7902FPRD7934MILLER14rowsselected.
RUN命令显示缓冲区中的命令并返回查询的结果.
另外,RUN命令使得缓冲区中的最后一行成为当前行.
"/"命令类似于RUN,它执行存储在缓冲区中的SQL命令或PL/SQL块,但它不显示缓冲区的内容,见表3-11.
表3-11使用"/"命令运行一个查询SQL>/EMPNOENAME7369SMITH7499ALLEN7521WARD7566JONES7654MARTIN7698BLAKE7782CLARK7788SCOTT7839KING7844TURNER7876ADAMS7900JAMES7902FPRD7934MILLER14rowsselected.
不同于RUN命令,"/"命令不会使缓冲区中的最后一行成为当前行.
要以命令行形式运行一个SQL命令、一个SQL*Plus命令或一个PL/SQL块,有两种命令:START和@("at").
第3章结构化查询语言SQL107START命令的语法是:STARTfile_name[.
ext][arg1arg2.
.
.
]参数file_name[.
ext]代表想运行的命令文件,如果省略扩展名,SQL*Plus使用缺省的命令文件扩展名(通常为.
sql).
SQL*Plus在当前目录下查找具有你在START命令中指定的文件名和扩展名的文件.
如果没有找到符合条件的文件,SQL*Plus将在SQLPATH环境变量中定义的目录中查找该文件.
也可以包括文件的全路径名,例如:C:\MYDIR\MYFILE.
SQL.
可以在一个命令文件中包括正常情况下交互地输入的任何SQL命令、SQL*Plus命令或PL/SQL块.
命令文件中的EXIT或QUIT命令用于退出SQL*Plus.
参数部分([arg1arg2.
.
.
])代表希望传递给命令文件中的参数的值,命令文件中的参数必须使用如下格式声明:&1、&2、.
.
.
(或&&1、&&2、.
.
.
).
如果输入一个或多个参数,SQL*Plus使用这些值替代命令文件中的参数.
第一个参数替代每个&1,第二个参数替代每个&2,以此类推.
START命令使用参数的值定义参数.
如果在同一个SQL*Plus会话中再次运行这个命令文件,可以输入新的参数或省略参数以使用参数的当前值.
要运行名称为DELTBL.
SQL的命令文件,输入以下代码:SQL>STARTDELTBL@("at")命令的功能与START命令非常类似,唯一的区别就是@命令既可以在SQL*Plus会话内部运行,又可以在启动SQL*Plus的命令行接级别运行,而START命令只能在SQL*Plus会话内部运行.
要启动一个SQL*Plus会话并执行一个文件中的命令,输入下列代码:$sqlplus[username/password]@file_name[.
ext][arg1arg2.
.
.
]如果START命令被禁止,同样会禁止@命令.
本节后面3.
12.
4将介绍关于禁止SQL*Plus命令的详细信息.
(1)使用EXECUTE命令从SQL*Plus3.
2开始,有一个新的命令——EXECUTE,该命令能够直接在SQL*Plus提示符状态下执行单条PL/SQL语句,而不需要从缓冲区或命令文件中执行.
EXECUTE的主要用途是运行涉及一个函数或存储过程的PL/SQL语句,见表3-12.
表3-12使用EXECUTE命令运行存储过程SQL>VARIABLEidNUMBER-DefineabindvariableSQL>EXECUTE:id:=ADD_CASES(10);PL/SQLproceduresuccessfullycompleted.
SQL>PRINTidID10SQL>EXECUTE:ID:=ADD_CASES(3);PL/SQLproceduresuccessfullycompleted.
SQL>PRINTidID0108Oracle8i数据库开发与专业应用存储过程ADD_CASES返回的值存储在绑定变量:id中.
(2)保存SQL*Plus/SQL命令使用SAVE命令,可以将缓冲区中存储的SQL*Plus或SQL命令保存到一个操作系统文件(称为命令文件)中.
SAVE命令的语法为:SAV[E]file_name[.
ext][CRE[ATE]|[REP[LACE]|APP[END]]file_name[.
ext]是用于存储SQL缓冲区内容的操作系统文件的名称.
要命名该文件,应使用SQL*Plus运行的操作系统的文件命名约定.
如果没有提供文件的扩展名,SQL*Plus使用缺省的扩展名.
sql.
还可以指定一条路径作为文件名称的一部分.
如果没有指明路径,SAVE命令将使用SQLPATH环境变量中指定的目录作为文件的路径.
CRE[ATE]参数创建命令文件.
如果这个文件已经存在,将收到一条错误信息.
REP[LACE]参数使用SQL缓冲区中的内容替换一个已有文件.
如果文件不存在,SAVE.
.
.
REPLACE命令创建它.
APP[END]参数将SQL缓冲区中的内容添加到文件的尾部.
如果文件不存在,SAVE.
.
.
APPEND命令创建该文件.
(3)提取SQL*Plus/SQL命令要提取SQL*Plus或SQL命令,使用GET命令.
该命令的语法是:GETfile_name[.
ext][LIS[T]|NOL[IST]GET命令加载包含SQL*Plus和/或SQL命令的操作系统文件file_name到SQL缓冲区,那么就可以编辑文件中的命令或运行它们.
文件的缺省扩展名为.
sql.
LIS[T]参数在SQL*Plus加载文件到缓冲区时列出文件的内容.
LIST参数是缺省设置.
NOL[IST]参数不列出文件的内容.
如果在GET命令中没有指定文件名的全路径,SQL*Plus首先在当前目录下查找该文件,然后在环境变量SQLPATH中列出的目录中查找文件.
如果使用Windows95/NT,通过在指定目录下启动SQL*Plus应用,可以让SQL*Plus在该目录下查找命令文件.
要实现它,更改Windows快捷方式的StartIn属性为包含这些文件的目录.
没有指定全路径的文件将在SQL*Plus启动时所在的目录中被打开、创建或保存.
3.
12.
2使用SQL*Plus的COPY命令虽然由于Oracle在7.
2版本中推出的CREATETABLE.
.
.
UNRECOVERABLEASSELECT.
.
.
命令在某种程度上削弱了COPY命令所起的作用,但COPY命令仍然是一条最为有用的SQL*Plus命令.
但是人们对它不甚了解,所以不经常使用它.
COPY命令可以用来实现几个功能:(1)从一个本地数据库将一个或多个表或整个模式拷贝到一个远程数据库或另外一个本地数据库.
这可以用于从一个数据库将整个模式移动到另外一个数据库,而不需要使用导出/导入工具,当导出大于操作系统文件限制的文件时这尤其有用.
(2)将一个表中指定的记录(基于查询)拷贝到远程数据库或本地数据库的其他表中.
(3)将包含LONG类型数据列的表的内容拷贝到其他表.
因为LONG类型的列不能用于SELECT语句中,所以这是解决问题的唯一方法.
(4)从一个Oracle数据库向一个非Oracle数据库拷贝表.
第3章结构化查询语言SQL109COPY命令的语法为:COPY{FROMusername[/password]@database_specification|TOusername[/password]@database_specification|FROMusername[/password]@database_specificationTOusername[/password]@database_specification}{APPEND|CREATE|INSERT|REPLACE}destinaiton_table[(column,column,column.
.
.
)]USINGqueryusername[/password]代表希望拷出/拷入的Oracle用户名和口令.
在FROM子句中,username/password表示数据的源,在TO子句中username/password表示数据的目的地.
如果既没有在FROM子句中指定口令也没有在TO子句中指定口令,SQL*Plus会提示输入口令.
SQL*Plus不显示对这些提示的用户的响应.
database_specification(数据库声明)是数据库链接名、Net8服务名或SQL*NetV2服务名.
在COPY命令中,必须提供数据库声明子句.
在FROM子句中,数据库声明代表源端数据库,在TO子句中,数据库声明代表目的端数据库.
destination_table(目标表)是希望创建的表或向其中添加数据的表,[(column,column,column.
.
.
)]指示了目标表中的列名.
如果指定列,列的数据必须与查询选择的列的数目相同.
如果没有指定列,如果COPY命令创建目标表,被拷贝的列在目标表中将是具有与源表中的列相同的名字.
USINGquery参数指定一个提取COPY命令拷贝的行和列的SELECT语句.
FROMusername[/password]@database_specification部分定义用户名、口令和含有需要拷贝的数据的数据库.
如果省略FROM子句,源数据库在缺省情况下为SQL*Plus连接的数据库.
必须包含一个FROM子句以指定缺省数据库以外的源数据库.
TOusername[/password]@database_specification部分说明包含目标表的数据库.
如果省略TO子句,目标表在缺省情况下为SQL*Plus连接的数据库.
必须包含TO子句以指定一个缺省数据库以外的目标数据库.
有几个参数用于控制COPY命令如何从一个表向另一个表中拷贝数据.
这些参数如下所示:(1)如果目标表存在,APPEND将查询出的记录插入到目标表.
如果目标表不存在,COPY命令创建该表.
即使该表为空(不含数据),APPEND命令也插入记录.
(2)CREATE首先创建目标表,然后向目标表中插入取自查询的记录.
如果目标表已经存在,COPY命令返回一个错误.
(3)INSERT将取自查询的记录插入目标表.
如果目标表不存在,COPY命令返回一个错误.
当使用INSERT命令时,USING查询必须为目标表中的每列选择一列.
(4)REPLACE使用查询提取的记录替换目标表及其内容.
如果目标表存在,COPY删除它并用含有拷贝数据的表替换它.
如果目标表不存在,COPY命令创建它.
有三个SQL*PlusSET变量控制COPY命令的行为:(1)LONG(2)COPYCOMMIT(3)ARRAYSIZELONG变量决定所拷贝的LONG类型列的长度.
如果LONG类型列包含的数据长度大110Oracle8i数据库开发与专业应用于LONG变量的值,COPY命令将截断数据.
在缺省情况下,SQL*Plus在每个成功执行的COPY命令后面执行一次提交.
如果设置SQL*Plus的SET变量COPYCOMMIT为一个正整型值n,SQL*Plus将在每拷贝n批记录后执行一次提交.
SET变量ARRAYSIZE决定批操作的大小.
当使用COPY命令时,一些操作系统环境(特别是VAX/VMX、OpenVMX)要求以双引号括起数据库声明.
如果COPY命令的(column,column,.
.
.
)子句中定义的任一列名含有小写字母或空格,列名必须使用双引号括起来.
当使用COPY命令拷贝含有数字型(NUMBER)列的表时,要非常小心这些列在目标数据库中变为精度为38位的小数类型(DECIMAL).
3.
12.
3使用SQL*Plus创建SQL在许多情况下数据库系统管理员或一个普通的用户需要对许多数据库对象(表、索引等等)执行SQL语句.
例如,数据库系统管理员可能会需要周期性地从一个成品数据库加载数据到开发数据库或测试数据库.
在加载数据之前,可能需要删除开发数据库或测试数据库中所有表中的数据.
基于单个表来做这件工作会非常繁琐,尤其当数据库中有几百个表时.
在这种情形下,一种简单快捷的解决方案是使用SQL*Plus创建所需的SQL语句,将它们保存到一个操作系统文件中,并在SQL*Plus中运行该文件.
例如,要删除属于用户SCOTT的所有表中的所有记录,SYSTEM用户可以使用表3-13中的SQL语句.
表3-13SQL*Plus生成SQLSQL>CONNECTSYSTEMEnterpassword:Connected.
SQL>SETPAGESIZE0SQL>SETHEADINGOFFSQL>SETFEEDBACKOFFSQL>SETVERIFYOFFSQL>SETECHOOFFSQL>SPOOLDELTBL.
SQLSQL>SELECT'DELETE'||TABLE_NAME||';'2FROMDBA_TABLES3WHEREOWNER='SCOTT';DELETEACCTS;DELETEACCT_ADDRS;DELETEBONUS;DELETECITIES;DELETECOMPANY_SUMMARY;DELETECUSTOMER;DELETEDEPT;第3章结构化查询语言SQL111(续)DELETEDUMMY;DELETEEMP;DELETEFUNDS;DELETEFUND_CONTRIB;DELETEFUND_XACT;DELETEF_EMPCOMP;DELETEF_XACT_TYPE;DELETEINVINFO;DELETEINVREQUEST;DELETEITEM;DELETEORD;DELETEORDER_HISTORY;DELETEPRICE;DELETEPRODUCT;DELETESALES_REVENUE;DELETESALGRADE;DELETESTOCK_HISTORY;SQL>SPOOLOFF当运行上述文件时,将得到文件DELTBL.
SQL,如下所示:DELETEACCTS;DELETEACCT_ADDRS;DELETEBONUS;DELETECITIES;DELETECOMPANY_SUMMARY;DELETECUSTOMER;DELETEDEPT;DELETEDUMMY;DELETEEMP;DELETEFUNDS;DELETEFUND_CONTRIB;DELETEFUND_XACT;DELETEF_EMPCOMP;DELETEF_XACT_TYPE;DELETEINVINFO;DELETEINVREQUEST;DELETEITEM;DELETEORD;DELETEORDER_HISTORY;112Oracle8i数据库开发与专业应用DELETEPRICE;DELETEPRODUCT;DELETESALES_REVENUE;DELETESALGRADE;DELETESTOCK_HISTORY;发出命令@DELTBL.
SQL运行DELTBL.
SQL文件将删除表中的记录.
其他的命令用于格式化输出和创建命令文件:(1)SETPAGESIZE0关闭全部页格式化信息,例如列标题、起始空白行、分页符等等.
(2)SETHEADINGOFF关闭列标题显示(可以使用SETHEADINGOFF或SETPAGESIZE0实现).
(3)SETFEEDBACKOFF隐藏查询返回的记录号.
(4)SETVERIFYOFF不在SQL*Plus使用实际值替换变量的前后显示SQL命令的文本.
(5)SETECHOOFF可以在文件执行时,隐藏DELETE.
SQL文件中的SQL命令清单.
(6)SPOOLDELTBL.
SQL开始将把在SQL*Plus提示符下输入的命令查询结果保存到名为DELTBL.
SQL的文件中.
命令和查询结果继续在终端上显示.
如果没有指明一个文件扩展名,SQL*Plus为输出文件使用缺省的扩展名(.
lst或.
lis).
(7)SPOOLOFF停止保存并关闭DELTBL.
SQL文件.
如果SYSTEM想删除SCOTT用户的全部表中的记录,他所要做的就是在SQL*Plus中执行DELTBL.
SQL文件,可以按照以下方式实现:SQL>@DELTBL3.
12.
4在SQL*Plus中对用户权限的限制Oracle为数据管理员提供了一个工具,让他们能够在SQL*Plus环境下禁止指定的SQL和SQL*Plus命令的执行,它基于单个用户实现.
事实上,这个工具是一个表——PRODUCT_USER_PROFILE,由用户SYSTEM拥有.
在表3-14中给出PRODUCT_USER_PROFILE的说明,表3-15说明PRODUCT_USER_PROFILE中每列的用途.
表3-14PRODUCT_USER_PROFILE表定义名称能否为空类型PRODUCT不能为空VARCHAR2(30)USERIDVARCHAR2(30)ATTRIBUTEVARCHAR2(240)SCOPEVARCHAR2(240)NUMERIC_VALUENUMBER(15,2)CHAR_VALUEVARCHAR2(240)DATE_VALUEDATELONG_VALUELONG第3章结构化查询语言SQL113表3-15PRODUCT_USER_PROFILE表的列的用途列用途PRODUCT必须含有产品的名称(在本例中为SQL*Plus)在该例中不允许使用通配符(%)或空(NULL)值USERID必须含有希望禁止命令操作的用户的名称(大写)如果针对几个用户禁止某个命令,使用通配符(%)或输入多条记录.
如果针对全部用户禁止某个命令,只要在该列中插入一个通配符(%)即可ATTRIBUTE必须包含被禁用的SQL或SQL*Plus命令(例如ALTER)的名称(大写).
该列不允许使用通配符值SCOPESQL*Plus忽略该列.
应该在该列输入一个空(NULL)值该列被保留用于非SQL*Plus产品NUMERIC_VALUESQL*Plus忽略该列.
应该在该列输入一个空(NULL)值该列被保留用于非SQL*Plus产品CHAR_VALUE必须含有字符串"DISABLED"DATE_VALUESQL*Plus忽略该列.
应该在该列输入一个空(NULL)值该列被保留用于非SQL*Plus产品LONG_VALUESQL*Plus忽略该列.
应该在该列输入一个空(NULL)值该列被保留用于非SQL*Plus产品作为SYSTEM用户运行脚本PUPBLD.
SQL创建PRODUCT_USER_PROCEDURE表.
这个文件的位置根据操作平台的不同而不同.
例如,对于Windows95下的个人Oracle系统,PUPBLD.
SQL文件位于目录C:\ORAWIN95\DBS中(C:\ORAWIN95是Oracle产品在Windows95操作系统中的缺省ORACLE_HOME目录).
在UNIX平台,这个文件位于$ORACLE_HOME/sqlplus/admin目录下.
在安装Oracle软件与创建起始数据库期间(对于UNIX平台在crdb脚本中,对于Windows95/NT平台在builddall脚本中),PUPBLD.
SQL命令文件本运行.
如果在安装过程中没有创建起始数据库,必须作为SYSTEM用户运行PUPBLD.
SQL脚本以创建PRODUCT_USER_PROFILE表.
如果PUPBLD.
SQL没有运行,每当登录SQL*Plus时,将收到下面的警告消息:Warning:Productuserprofileinformationnotloaded!
Errorindisablingrolesinproductuserprofile.
(警告:产品用户环境资源文件信息没有加载!
在产品用户环境资源文件中禁止角色产生错误.
)1.
禁用一个SQL命令要禁止给某给定用户使用某个SQL或SQL*Plus命令,SYSTEM用户必须插入与表3-16中的列和值匹配的一条记录.
114Oracle8i数据库开发与专业应用表3-16用于限制SQL*Plus命令的值列值PRODUCTSQL*PlusUSERID被限制的用户的用户名ATTRIBUTE被限制的命令名称CHAR_VALUEDISABLEDSCOPENULL(空)NUMERIC_VALUENULL(空)DATE_VALUENULL(空)LONG_VALUENULL(空)例如,要禁止用户SCOTT从SQL*Plus访问操作系统,需要作为SYSTEM用户登录到SQL*Plus,并执行表3-17中的SQL语句.
表3-17禁止SCOTT用户使用HOST命令INSERTINTOproduct_user_profile(product,userid,attribute,scope,numeric_value,char_value,date_value,long_value)VALUES('SQL*Plus','SCOTT','HOST',NULL,NULL,'DISABLED',NULL,NULL);当用户访问SQL*Plus时,SQL*Plus从PRODUCT_USER_PROFILE表读取用户限制,并在用户对话期间强制实施这些限制.
如果在PRODUCT_USER_PROFILE表中做出影响用户的任何改动,这些改变将不会影响用户的当前对话.
用户可以在下一次登录到SQL*Plus时看到这些改变的效果.
2.
重新允许使用一个SQL命令要重新允许使用一个SQL命令,需要删除含有限制的记录.
表3-18重新允许使用在表3-17中被禁止的命令.
表3-18允许用户SCOTT使用HOST命令DELETE[FROM]product_user_profileWHEREuserid='SCOTT'andattribute='HOST';可以使用PRODUCT_USER_PROFILE表禁止下面的SQL*Plus命令(按字母顺序排列):(1)COPY(2)EDIT(3)EXECUTE(4)EXIT(5)GET(6)HOST(或者操作系统HOST的别名,例如UNIX上的'!
'或VMS上的'$')(7)QUIT(8)PASSWORD第3章结构化查询语言SQL115(9)RUN(10)SAVE(11)SET(禁止SQL*Plus的SET命令还会禁止SETROLE和SETTRANSACTION命令)(12)SPOOL(13)START(禁止SQL*Plus命令还会禁止SQL*Plus的@和@@命令)下面的SQL命令可以被禁止:(1)ALTER(2)ANALYZE(3)AUDIT(4)CONNECT(5)CREATE(6)DELETE(7)DROP(8)GRANT(9)INSERT(10)LOCK(11)NOAUDIT(12)RENAME(13)REVOKE(14)SELECT(15)SETROLE(16)SETTRANSACTION(17)TRUNCATE(18)UPDATE还可以禁止下面的PL/SQL命令:(1)BEGIN(2)DECLARE禁止BEGIN和DECLARE命令不妨碍SQL*Plus的EXECUTE命令的使用.
EXECUTE命令必须被单独禁止.
3.
禁用SETROLESQL命令SETROLE使应用的用户能够访问获取应用的角色授权的特权,这样做可能会产生安全问题.
要阻止应用的用户在SQL*Plus中获取应用的角色,数据库系统管理员可以使用PRODUCT_USER_PROFILE表禁用SETROLE命令.
当启动SQL*Plus时,该命令限制SQL*Plus,用户只能使用角色允许的相关的权限.
4.
禁用角色要禁止一个指定用户的角色,应在PRODUCT_USER_PROFILE表中插入一条记录,该记录的UserID列中含有用户的用户名,Attribute(属性)列含有ROLES,Char_Value列含有角色名称.
当禁用角色时,如果在UserID列中键入PUBLIC或%,便禁止了全部用户的角色.
%116Oracle8i数据库开发与专业应用或PUBLIC只能用于被授权为PUBLIC的角色.
Oracle用户SYSTEM拥有PRODUCT_USER_PROFILE表.
当SYSTEM登录时,SQL*Plus不读取PRODUCT_USER_PROFILE表.
因此,没有任何SQL*Plus限制应用到SYSTEM用户上.
PRODUCT_USER_PROFILE表提供的产品级安全策略只由SQL*Plus实施,而不是由OracleRDBMS实行.
3.
12.
5追踪SQL语句在SQL*Plus3.
3之前,获得有关在SQL*Plus中SQL语句的执行情况的统计手段非常有限.
用于统计目的的命令只有SETTIME和SETTIMING.
SETTIME命令控制SQL*Plus如何显示当前时间.
ON参数在每个SQL*Plus提示符前面显示当前时间,OFF参数关闭当前时间的显示.
SETTIME命令的语法是:SETTI[ME][OFF|ON](OFF是缺省值)表3-19显示了使用SETTIME命令的一个示例.
表3-19估算运行时间SQL>SHOWTIMEtimeOFFSQL>SETTIMEON01:17:57SQL>SELECTt1.
dname,t2.
name,t2.
sal,t2.
job01:18:112FROMdeptt1,empt201:18:233WHEREt1.
deptno=t2.
deptno;DNAMEENAMESALJOBRESEARCHSMITH800CLERKSALESALLEN1600SALESMANSALESWARD1250SALESMANRESEARCHJONES2975MANAGERSALESMARTIN1250SALESMANSALESBLAKE2850MANAGERACCOUNTINGCLARK2450MANAGERRESEARCHSCOTT3000ANALYSTACCOUNTINGKING5000PRESIDENTSALESTURNER1500SALESMANRESEARCHADAMS1100CLERKSALESJAMES950CLERKRESEARCHFORD3000ANALYSTACCOUNTINGMILLER1300CLERK14rowsselected.
01:18:43SQL>通过用查询执行后第一个提示符显示的时间(01:18:43)减去最后一个输入行处显示的时间(01:18:23),用户可以得到一个执行这个查询所消耗的时间估算值(包含用于输入WHERE子句的时间).
使用这种方法计算得出的运行时间不能反映Oracle执行一个查询的真正速度,因为流第3章结构化查询语言SQL117逝的时间包含查询结果显示到SQL*Plus界面的时间消耗,运行查询的实际时间要短得多.
SETTIMING命令控制执行时间统计的显示,SETTIMING命令的语法为:SETTIMI[NG][OFF|ON](OFF是缺省值)SETTIMINGON命令是显示SQL*Plus中执行的每一条SQL语句或PL/SQL块的执行时间统计.
SETTIMINGOFF关闭时间统计的显示.
表3-20显示了使用SETTIMING命令的一个示例.
表3-20执行的计时SQL>SHOWTIMINGtimingOFFSQL>SETTIMINGONSQL>SELECTt1.
dname,t2.
name,t2.
sal,t2.
job2FROMdeptt1,empt23WHEREt1.
deptno=t2.
deptno;DNAMEENAMESALJOBRESEARCHSMITH800CLERKSALESALLEN1600SALESMANSALESWARD1250SALESMANRESEARCHJONES2975MANAGERSALESMARTIN1250SALESMANSALESBLAKE2850MANAGERACCOUNTINGCLARK2450MANAGERRESEARCHSCOTT3000ANALYSTACCOUNTINGKING5000PRESIDENTSALESTURNER1500SALESMANRESEARCHADAMS1100CLERKSALESJAMES950CLERKRESEARCHFORD3000ANALYSTACCOUNTINGMILLER1300CLERK14rowsselected.
real:2690表3-19和表3-20中,SETTIME和SETTIMING命令提供了在SQL*Plus中SQL语句和(或)PL/SQL块执行情况的非常基本且不是非常精确的计时统计.
在SQL*Plus3.
3以前的版本中,不能直接获得关于优化器使用的执行(访问)路径的任何信息.
SQL*Plus3.
3版以及更高版本中使用了一个称为AUTOTRACE的新功能.
AUTOTRACE使SQL*Plus用户可以在SQL*Plus中查看数据库管理语言(DML)语句(SELECT、INSERT、UPDATE和DELETE)的执行计划,而不必使用Oracle提供的普通工具(SQL_TRACE、EXPLAINPLAN和TKPROF工具)来追踪SQL语句的执行情况.
要使用该功能,数据库系统管理员必须作为SYS用户运行一个称为PLUSTRCE.
SQL的SQL脚本.
PLUSTRCE.
SQL文件的位置依赖于操作系统.
PLUSTRCE脚本完成下列任务:(1)创建一个名为PLUSTRACE的角色.
(2)为角色PLUSTRACE授予V$SESSTAT、V$STATNAME和V$SESSION表的118Oracle8i数据库开发与专业应用SELECT权限.
(3)使用ADMIN选项将PLUSTRACE角色授权给DBA角色.
要让用户具有AUTOTRACE能力,必须满足三个条件:(1)用户必须被任何具有DBA角色的用户授予PLUSTRACE角色.
(2)用户必须在自己的模式中创建一个PLAN_TABLE表.
用户可以运行utlxplan.
sql脚本完成这项工作.
在UNIX操作平台下该脚本位于目录$ORACLE_HOME/rdbms/admin中,在Windows95/NT操作系统下该脚本位于目录%ORACLE_HOME%\Rdbms8x\Admin下.
(3)必须适当地设置SET系统变量AUTOTRACE.
在这些步骤执行后,在成功地运行任何DML语句(SELECT、INSERT、UPDATE和DELETE)后,用户能够得到关于优化器使用的执行路径的一个报告和执行统计.
报告的输出由系统变量AUTOTRACE控制.
在表3-21中列出系统变量AUTOTRACE允许的设置和它们的使用结果.
表3-21AUTOTRACE值值结果SETAUTOTRACEOFF缺省值.
不生成任何报告SETAUTOTRACEONEXPLAIN追踪报告只显示执行路径,不显示执行统计SETAUTOTRACEONSTATISTICS追踪报告只相识执行统计,不显示执行路径SETAUTOTRACEON追踪报告同时显示执行路径和执行统计SETAUTOTRACETRACEONLY与SETAUTOTRACEON相同,但是不显示查询的结果1.
理解执行计划执行计划显示当执行一个查询时优化器使用的访问路径.
使用EXPLAINPLAN命令生成执行计划的输出.
执行计划中显示的每一行都有一个连续的行号,也显示父操作的行号.
执行计划由四列组成(对于标准查询,只显示三列,只有在分布式查询或使用并行查询选项(ParallelQueryOption,PQO)运行查询的情况下才显示第四列).
表3-22显示列的名称和它们的说明.
表3-22执行计划列说明列名说明ID_PLUS_EXP显示每步执行步骤的行号PARENT_ID_PLUS_EXP显示某步和它的父步骤之间的关系PLAN_PLUS_EXP显示报告的每个步骤,例如TABLEACCESS(FULL)OF'DEPT'OBJECT_NODE_PLUS_EXP显示使用的数据库链接或并行查询服务器(只有在运行分布式查询或使用并行选项(PQO)时)缺省的列格式通常在站点环境资源文件(glogin.
sql文件)中设置.
列的格式可以使用SQL*Plus命令COLUMN加以改变.
可以更改列的宽度、重新命名列或停止显示列.
例如,要禁止显示ID_PLUS_EXO列,应键入:SQL>COLUMNID_PLUS_EXPNOPRINT第3章结构化查询语言SQL119此语句追踪报告的第二部分显示语句执行的统计.
它们显示用于执行查询的系统资源和它们的用法.
与执行路径不同,不能改变统计报告的缺省格式.
2.
使用AUTOTRACE功能现在详细介绍使SCOTT用户能够在SQL*Plus中使用AUTOTRACE功能所需要的步骤.
首先,用户SYSTEM登录到SQL*Plus,并授予用户SCOTTPLUSTRACE角色(SYS用户已在先前运行过$ORACLE_HOME/sqlplus/admin/plustrce.
sql脚本,在数据库中创建了PLUSTRACE角色).
表3-23显示该项工作已经完成.
表3-23授权PLUSTRACE角色SQL>C:\>sqlplussystemSQL*Plus:Release8.
1.
3.
0.
0-BetaonSunMar709:25:091999(c)Copyright1998OracleCorporation.
Allrightsreserved.
Enterpassword:Connectedto:Oracle8EnterpriseEditionRelease8.
1.
3.
0.
0-BetaWiththePartitioningandObjectsoptionsPL/SQLRelease8.
1.
3.
0.
0-BetaSQL>GRANTplustraceTOscott;Grantsucceeded.
接着,用户SCOTT登录到SQL*Plus,并通过运行$ORACLE_HOME/rdbms80/admin/utlxplan.
sql脚本在他的模式中创建PLAN_TABLE(这是EXPLAINPLAN命令需要的),见表3-24.
表3-24创建PLAN_TABLESQL>CONNECTscottEnterpassword:*****Connected.
SQL>@$ORACLE_HOME/rdbms80/admin/utlxplanTablecreated.
SQL>L1createtablePLAN_TABLE(2statement_idvarchar2(30),3timestampdate,4remarksvarchar2(80),5operationvarchar2(30),6optionsvarchar2(30),7object_nodevarchar2(128),8object_ownervarchar2(30),9object_namevarchar2(30),10object_instancenumeric,120Oracle8i数据库开发与专业应用(续)11object_typevarchar2(30),12optimizervarchar2(255),13search_columnsnumeric,14idnumeric,15parent_idnumeric,16positionnumeric,17costnumeric,18cardinalitynumeric,19bytesnumeric,20other_tagvarchar2(255),21*otherlong)L[IST]命令列出SQL缓冲区中的内容,它含有从ORACLE_HOME/rdbms80/admin/utxlplan.
sql脚本中执行的最后一条SQL命令——CREATETABLEplan_table语句.
接着,SCOTT用户输入并执行希望追踪的的查询.
表3-25显示了一个示例.
表3-25追踪一个查询SQL>SELECTt1.
dname,t2.
ename,t2.
sal,t2.
job2FROMdeptt1,empt23WHEREt1.
deptno=t2.
deptno;DNAMEENAMESALJOBRESEARCHSMITH800CLERKSALESALLEN1600SALESMANSALESWARD1250SALESMANRESEARCHJONES2975MANAGERSALESMARTIN1250SALESMANSALESBLAKE2850MANAGERACCOUNTINGCLARK2450MANAGERRESEARCHSCOTT3000ANALYSTACCOUNTINGKING5000PRESIDENTSALESTURNER1500SALESMANRESEARCHADAMS1100CLERKSALESJAMES950CLERKRESEARCHFORD3000ANALYSTACCOUNTINGMILLER1300CLERK14rowsselected.
要同时得到执行路径和执行统计的信息,用户SCOTT必须正确地设置AUTOTRACE变量.
表3-26显示了设置AUTOTRACE为打开状态并从缓冲区中运行先前的查询的命令.
第3章结构化查询语言SQL121表3-26追踪缓冲区中的查询SQL>SETAUTOTRACEONSQL>/ExecutionPlan0SELECTSTATEMENTOptimizer=CHOOSE10NESTEDLOOPS21TABLEACCESS(FULL)OF'EMP'32TABLEACCESS(BYROWID)OF'DEPT'43INDEX(UNIQUESCAN)OF'DEPT_PRIMARY_KEY'(UNIQUE)Stastistics0recursivecalls2dbblockgets43consistentreads0physicalreads0redosize726bytessentviaSQL*Netfromclient376bytesreceivedviaSQL*Netfromclient3SQL*Netroundtripsto/fromclient0sorts(memory)0sorts(disk)14rowsprocessed不显示查询数据,追踪相同的语句,如下所示:SQL>SETAUTOTRACETRACEONLYSQL>/-slashcommand:doesn'tdisplayquerytext14rowselected.
ExecutePlan0SELECTSTATEMENTOptimizer=CHOOSE10NESTEDLOOPS21TABLEACCESS(FULL)OF'EMP'32TABLEACCESS(BYROWID)OF'DEPT'43INDEX(UNIQUESCAN)OF'DEPT_PRIMARY_KEY'(UNIQUE)Stastistics0recursivecalls2dbblockgets43consistentreads0physicalreads0redosize726bytessentviaSQL*Netfromclient122Oracle8i数据库开发与专业应用376bytesreceivedviaSQL*Netfromclient3SQL*Netroundtripsto/fromclient0sorts(memory)0sorts(disk)14rowsprocessed当返回一个大量记录的查询时,TRACEONLY选项特别有用.
执行统计中涉及的客户是SQL*Plus.
不管SQL*Net是否被安装并使用,SQL*Net是指客户(SQL*Plus)和服务器(OracleRDBMS)之间常用的进程间的通信.
3.
12.
6SQL*Plus8.
1版的增强SQL*Plus8.
1版给予用户实现下列功能的能力:(1)访问所有的Oracle8i数据类型和用户定义的数据类型.
(2)访问所有Oracle8i引入的SQL新特性.
(3)SQL*Plus8.
1版拥有8.
0版具有的全部特性.
而且,服务管理器功能目前在SQL*Plus中已可使用.
这些功能包括:启动、关闭、显示参数、显示系统全局区(SGA)、归档日志、恢复数据库和内部连接等.
有一个名为ARCHIVELOG的新命令,ARCHIVELOG命令使重做日志文件被归档,它还显示重做日志文件的信息.
例如:SQL>connectinternalConnected.
SQL>archiveloglistDatabaselogmodeNoArchiveModeAutomaticarchivalEnabledArchivedestinationD:\ORANT\oradata\orcl2\archiveOldestonlinelogsequence2Currentlogsequence5SQL>现在可以在SQL*Plus中使用RECOVER命令恢复一个数据库.
RECOVER命令执行表空间、数据文件或整个数据库的介质恢复.
例如:SQL>recoverdatabaseORA-00283:recoverysessioncanceledduetoerrorsORA-01124:cannotrecoverdatafile1-fileisinuseorrecoveryORA-01110:datafile1:'D:\ORANT\ORCL2\SYSTEM01.
DBF'SET命令现在有一个INSTANCE子句,INSTANCE子句将会话的缺省实例改变为指定的实例.
SET命令现在还有一个LOGSOURCE子句,LOGSOURCE子句指定数据库恢复期间检索归档日志的路径.
现在可以在SQL*Plus中使用SHOWPARAMETERS命令查看init.
ora参数.
例如:第3章结构化查询语言SQL123SQL>showparametersblockNAMETYPEVALUEdb_block_buffersinteger1000db_block_checkingbooleanTRUEdb_block_checksumbooleanFALSEdb_block_lru_latchesinteger1db_block_max_dirty_targerinteger1000db_block_siezeinteger2048db_file_multiblock_read_countinteger8hash_multiblock_io_countinteger1sort_multiblock_read_countinteger2可以在SQL*Plus中查看系统全局区(SGA)的信息.
例如:SQL>showsgaTotalSystemGlobalArea20396276bytesFixexSize63732bytesVariableSize18210816bytesDatabaseBuffers2048000bytesRedoBuffers73728bytesSQL>可以在SQL*Plus中使用带有安装和打开一个数据库的选项的STARTUP命令来启动数据库.
例如:SQL>startupORACLEinstancestartedTotalSystemGlobalArea20396276bytesFixexSize63732bytesVariableSize18210816bytesDatabaseBuffers2048000bytesRedoBuffers73728bytesDatabasemounted.
Databaseopened.
SQL>可以在SQL*Plus中使用SHUTDOWN命令关闭一个数据库,SHUTDOWN命令关闭当前正在运行的一个Oracle实例.
该命令也可以关闭和卸载一个数据库.
例如:SQL>shutdownimmediateDatabaseclosed.
Databasedismounted.
124Oracle8i数据库开发与专业应用ORACLEinstanceshutdown.
SQL>SQL*Plus是最经常用来和数据库交互并执行系统管理功能如启动、关闭或恢复数据库等的唯一工具.
它是一个交互式工具,允许用户创建、修改、删除或查询数据库对象如表、视图、索引和约束等.
它还允许具有适当权限的用户创建新的用户,向他们授予特权或修改现有的用户.
拥有适当权限的用户能够在SQL*Plus中删除其他用户和取消他们的权限.
在Oracle8i中,所有的服务器管理命令都合并入SQL*Plus,所以数据库系统管理员能够使用这个工具有效地管理他们的数据库.
3.
13小结1.
问:什么是SQL它在Oracle数据库中的作用是什么答:SQL是结构化查询语言(structurequerylanguage)的缩写.
在Oracle数据库中用SQL命令来创建、存储、修改、检索和维护数据库中的信息.
2.
问:如何登录SQL*Plus答:要使用SQL*Plus必须先注册,每个用户都有一个用户标识和密码,在操作系统的提示符下键入命令:SQLPLUS,则SQL*Plus会要求用户输入用户标识和密码:ENTERUSERNAME:SCOTTENTERPASSWORD:3.
问:如何查看表中某几个指定的列答:查看表中某几个指定列键入下述命令:SQL>SELECTEMPNO,ENAME,JOBFROMEMP;SQL>SELECTJOB,ENAME,EMPNOFROMEMP;4.
问:怎样返回符合条件的所有行答:使用WHERE子句,例如:SQL>SELECTENAMEFROMEMPWHEREDEPTNO=10;返回所有DEPTNO=10的行.
5.
问:如何定义更多的查询条件答:使用AND和OR运算符,例如:SQL>SELECTENAME,JOBFROMEMPWHEREDEPTNO=20ANDJOB!
='CLERK';和SQL>SELCTENAME,JOBFROMEMP第3章结构化查询语言SQL125WHEREDEPTNO=20ORJOB!
='CLERK';6.
问:如何向表中插入数据答:使用INSERT语句,如下:SQL>INSERTINTODEPT(DNAME,DEPTNO)VALUES('ACCOUNTING',10);并且插入的数据可以是来自一个表的查询的结果,该查询语句代替了VALUES子句:SQL>INSERTINTOEMP(EMPNO,ENAME,DEPTNO)SELECTID,NAME,DEPARTMENTFROMOLD-EMPWHEREDEPARTMENTIN(10,20,30,40);7.
问:怎样修改多列的值答:使用UPDATE语句可以同时修改多列的值,在SET子句中指定要修改的所有值,如把所有推销员的工作改为市场研究员,同时调往部门40:SQL>UPDATEEMPSETDEPTNO=40,JOB='MARKETREP'WHEREJOB='SALESMAN';8.
问:"对表的插入、删除和修改都要在工作提交(即对数据修改的确认)后才生效",这句话正确吗答:正确.
在做提交以前,只有做出数据修改的用户本身能看到改变的情况,其他用户要查看同一表格的数据时,看到的只是上次提交后的数据(即数据没有修改的情况).
提交命令COMMIT有三种形式:显式的、隐含的和自动的.
显式的提交就是打入SQL命令COMMIT使所有数据的改变生效.
SQL>COMMIT9.
问:如何创建一个表答:创建一个表时需指定表的名字、表中各列的名字、表中各列的值的类型及每列的最大宽度.
在Oracle中一个表最多可包含254列,创建表后由系统自动修改数据字典,下面的SQL命令创建一个表:SQL>CREATETABLEDEPT(DEPTNONUMBER(2),DNAMECHAR(14),LOCCHAR(13));10.
问:什么是视图答:视图可以看作是表上的一个窗口,用户可以通过视图获得表中的信息,也可修改表中的数据.
视图是一种虚表,在用户的角度看来它是一个表,但它并不实际存在.
视图中的数据都来自其他表,但不是这些数据的复制.
视图具有清晰性,即根据用户的要求组织数据,而且还具有安全性,用视图可以防止未被授权的用户访问他不应该访问的行或列.
11.
问:SQL中的函数有哪些类型答:SQL中函数可以按返回值的数据类型分为数值函数、字符函数和日期函数,也可126Oracle8i数据库开发与专业应用以按作用范围分为个体函数,即把各行分开进行独立的求值的函数,还有组函数,即把多行聚集为一组进行求值的函数.
12.
问:HAVING子句和WHERE子句有哪些异同答:WHERE是指定SELECT的条件,而HAVING子句则是指定GROUP的条件,即选择分组的结果,如下例中找出总工资超过9000美元的部门:SQL>SELECTDEPTNO,SUM(SAL)FROMEMPGROUPBYDEPTNOHAVINGSUM(SAL)>9000;13.
问:如何实现复杂查询答:可通过连接运算,连接就是把来自不同的表的列组合起来形成一个新表的结果,下例是一个简单的连接操作:SQL>SELECTEMPNO,ENAME,JOB,EMP,DEPTNO,DNAMEFROMEMP,DEPTWHEREEMP.
DEPTNO=DEPT.
DEPTNO;14.
问:"在查询的WHERE子句中还可以嵌套其他查询",这句话是否正确答:正确.
该查询称为子查询.
子查询是相对于主查询而言的,是为了完成特定要求的询问而设计的.
如下例中找出与SMITH在同一部门工作的雇员:SQL>SELECTENAME,DEPTNOFROMEMPWHEREDEPTNO=(SELECTDEPTNOFROMEMPWHEREENAME='SMITH');15.
问:什么是特权和角色答:特权是指可执行某一特定的SQL语句类型的能力,如:登录数据库系统(创建一次会话),创建表,查询其他用户的表等等.
Oracle提供了一种称之为角色的机制来简化特权管理过程,角色是相关的特权的集合.
在使用角色之前必须先创建它,例如,创建角色ACCTS-PAY:SQL>CREATEROLEACCTS-PAY;16.
问:在大型数据库的查询中,怎样提高查询效率答:使用索引可以提高RDBMS查询大型表的速度,因为索引查询不是在整个表中搜索,所以使用索引进行导向的效率会更高,为表创建索引用命令:SQL>CREATEINDEXEMP-ENAMEONEMP(ENAME);17.
问:怎样控制数据的并发性、完整性和一致性答:一般来说,在并发事务中,我们采用锁的机制来控制数据的并发性、完整性和一致性.
锁分为两种:排他锁和共享锁.
排他锁禁止对资源的共享,共享锁允许对资源在某种程度上共享.
另一方面,锁可以加在整个表上和表中某些记录行上.
第3章结构化查询语言SQL12718.
问:glogin.
sql和login.
sql在SQL*Plus中有何作用答:glogin.
sql文件是全局设置文件,login.
sql文件是为个人使用准备的.
这两个文件包含Oracle用户激活SQL*Plus所执行SQL*Plus的命令和/或SQL语句.
首先读和执行glogin.
sql文件,然后是用户的login.
sql文件.
19.
问:使用COPY命令可以用来实现哪些功能答:可以实现如下功能:(1)从一个本地数据库将一个或多个表或整个模式拷贝到一个远程数据库或另外一个本地数据库.
这可以用于从一个数据库将整个模式移动到另外一个数据库,而不需要使用导出/导入工具,当导出大于操作系统文件限制的文件时这尤其有用.
(2)将一个表中指定的记录(基于查询)拷贝到远程数据库或本地数据库的其他表中.
(3)将包含LONG类型数据列的表的内容拷贝到其他表.
因为LONG类型的列不能用于SELECT语句中,所以这是解决问题的唯一方法.
(4)从一个Oracle数据库向一个非Oracle数据库拷贝表.
20.
问:如何在SQL*Plus中实现对用户权限的限制答:Oracle为数据管理员提供了一个工具,让他们能够在SQL*Plus环境下禁止指定的SQL和SQL*Plus命令的执行,它基于单个用户实现.
事实上,这个工具是一个表——PRODUCT_USER_PROFILE,由用户SYSTEM拥有.
21.
问:如何在SQL*PLUS中追踪SQL语句答:在SQL*Plus3.
3之前,获得有关在SQL*Plus中SQL语句的执行情况的统计手段非常有限.
用于统计目的的命令只有SETTIME和SETTIMING.
SETTIME命令控制SQL*Plus如何显示当前时间.
ON参数在每个SQL*Plus提示符前面显示当前时间,OFF参数关闭当前时间的显示.
SETTIME命令的语法是:SETTI[ME][OFF|ON](OFF是缺省值)第4章Oracle8数据库介绍4.
1Oracle8当Oracle改变产品编号的第一位数字时,就表示这个产品在功能上有了重大的变化.
Oracle推出数据库管理系统产品的7.
x家族已经有好几年了.
从7.
0、7.
1、7.
2到7.
3,每次版本的增强也都表现了产品在功能上的提高.
例如从产品7.
1版开始有了并行查询处理,而7.
3版则引入Oracle的全能服务器(universalserver)的内容,如视频服务器.
根据这种惯例,在产品Oracle8中应该会有重要的变化.
它不是在已有的Oracle体系结构上增加内容,而是对体系结构的完全的修改.
以Oracle8引入的面向对象来说,当不得不学习对象的程序设计时,首先面临的麻烦就是所处理的每件事都要有一个新名字(正确的面向对象术语).
现在有一些纯粹的面向对象的数据库,它与关系数据库差异太大,而Oracle版本7数据库升级到Oracle8时,不需要任何软件或数据库对象的修改,这使得过去的经验继续有效.
当然,除了功能上的变化,在营销方面,Oracle公司对命名和捆绑的方式也引入了一些变革.
在产品第一次发售时并没有考虑到这些细节,但以后要以新的命名和捆绑方式发售.
4.
1.
1最新版本的Oracle8上面已经提到,Oracle8是数据库管理系统的一个重大升级产品.
要评价这个新产品,在进行有关技术讨论之前,需要介绍下面几点:(1)Oracle8经过了大规模的beta测试.
尽管Oracle产品总是要进行beta测试,但这次不同寻常,他们邀请了更大规模的用户群,这次测试甚至包括一些小商店.
这有助于使产品覆盖更加多样化的应用环境,而不仅仅是支持那些直接的大型数据中心的用户.
(2)这是Oracle数据库管理系统产品中,把WindowsNT作为第一级开发平台的第一个重要版本.
对于尚不熟悉第一级平台这个术语的人来说,可以将其理解为能够首先接受Oracle软件新产品的那几个计算机环境(目前大约有8~10个).
这些环境通常是Oracle软件最重要的应用环境.
Oracle还准备承诺提供最好的支持、最少的系统差错和最新的版本.
这是Oracle公司面向NT用户的一个重要的策略.
(3)新产品的学习和培训对Oracle的商业伙伴和客户都很重要,但对开发商和最终用户并不太重要,因为他们依赖于外部咨询专家.
这些咨询专家已经提前进行了学习并早已得到软件,当产品发行后,他们可以有效地工作.
软件的使用功效是软件的内在功能同使用软件的人的能力相结合的产物.
学习和准备工作会使Oracle8的应用变得容易.
(4)在Oracle产品中,把Web和网络计算机环境作为系统的重要内容来强调Oracle8是第一个版本.
当然有关内容在Oracle7.
3,甚至更早的数据库版本中就已经出现过.
Oracle第4Oracle8数据库介绍129公司在过去几年里花费了大量的时间和资源来开发与Internet相关的技术,Oracle8就是支持这些环境的优化产品.
当Internet环境中一些核心的技术(HTML,Web浏览器,Java等)逐渐成熟并在商业领域走向实用时,Oracle8也应运而生.
(5)Oracle公司做出了大量的努力以支持开发人员在Internet环境下建造应用.
Oracle8的推广,为开发人员特别是为Web应用的开发人员带来了便利.
他们可以充分享受其插件结构(cartridgearchitecture)和其他开发选项的好处.
在最新的Oracle版本中,也有一些东西是一些人所不喜欢的.
下面提一下有关的反对意见:(1)Oracle8不是百分之百地满足CORBA的.
CORBA表示公共对象请求代理程序体系结构(CommonObjectRequestBrokerArchitecture).
这是一项技术标准,它允许使用其他应用程序内部的函数和数据的标准.
另一个与之相竞争的标准是DCOM(分布公共对象模型),是微软推出的.
这是因为一些读者最初接触共享对象的概念,是在一个文字处理文件中间包含一个到电子表格的连接的时候.
读取和处理电子表格数据的代码不是重复处理代码,而是通过电子表格软件来访问.
一些追溯潮流的人不满意Oracle公司没有在Oracle8中提供对CORBA的完全支持.
在Oracle8的开发过程中,CORBA技术还尚未定型.
对于那些硅谷里刚冒出来的小公司来说,他们在赶时髦、追逐不稳定的新技术方面,比Oracle这样的公司做起来容易.
因为Oracle是大量商业数据处理中心赖以支撑的基础,应该确保技术的可靠性.
当Oracle和CORBA在技术都成熟时,Oracle会在以后的版本中百分之百地支持CORBA标准.
(2)Java不是一个用于数据库的自然的过程语言,而PL/SQL依然是占统治地位的数据库内部编程语言.
目前有计划使Java成为Oracle数据库管理系统的可选的内部编程语言.
然而,Java语言仍处于不稳定的发展当中,当Java和Oracle技术上成熟时,Java会成为Oracle数据库内部编程语言的一种可选项.
那时就可以通过存储在数据库之外的Java应用程序来访问数据库(通过J/SQL).
最新版本的Oracle数据库管理系统是值得大家关注的.
当许多前沿技术的热情追逐者正醉心于面向对象的技术和Web插件的可能性时,Oracle数据库管理系统依然对Oracle版本7所开发的所有传统数据库提供支持.
用户如果选择Oracle8,就可以充分享用Oracle8在速度和可伸缩性方面的许多内在技术的进步.
当一个新用户询问是应该买Oracle8,还是以Oracle7作为起步时,建议直接使用Oracle8,并且使用那些既需要又习惯的功能.
Oracle8包括Oracle7所有的内容,并且还包含有更多的功能.
4.
1.
2Oracle8主要的改进首先讨论一下版本7中已经有的,但在Oracle8中得到增强Oracle的技术.
其中大多数内容是普通用户和开发人员,甚至DBA不能直接看到的东西.
然而在大多数的Oracle实际商业应用中,这些内容比起新功能重要得多.
在Oracle8中对现有技术的增强主要包括以下部分:(1)并行的更新、插入和删除(parallelupdate,insert和delete)Oracle从版本7.
1开始支持并行查询.
在过去,更新、插入和删除都是串行的(一个进程完成一个给定的任务).
通过对表和索引进行分割,Oracle8可以分配若干个进程来并行地执行插入、更新或删除,以此来加速这些操作.
这种并行化对于执行数据仓库加载这130Oracle8i数据库开发与专业应用样的任务是非常重要的.
(2)增量备份(Incrementalbackuo)Oracle以前的版本采用完全备份策略,即使用冷或热的备份技术将整个的表空间或数据库备份下来.
这要输出整个表或者一组表.
这样相对于较小的数据库(几十个GB以内)是可行的,但对于非常大的数据库,这种方法就不可行了(一天之内不能完成备份工作).
使用增量备份技术可以执行多层的备份,在一个层中,只捕捉那些最近一次备份执行后所发生的事务.
一个层(level)是一个参照点,从0开始编号.
高层号的备份比低层号的备份执行得更频繁,备份的信息也比低层号的少.
(3)DBLink集中(DBLinkconcentration)对一个数据库服务器来说,要支持大量的用户(几万到几百万),会面对很大的挑战.
一种解决方案是实现多级处理.
例如,一个服务器用于执行大多数商业逻辑处理,而另一个服务器执行数据库检索.
DBLink集中技术可使多个用户通过共享一个物理(网络接口)和操作系统接口,连接到其他数据库.
(4)连接池(connectionpooling)连接池可使大量用户连接到一个数据库.
不是为每个单独用户连接分配各自的内存和处理器,而是系统使用一个所有用户共享的连接池.
只有活动用户才占有资源.
(5)改进的并行服务器为了可靠,Oracle在版本7中实现了并行服务器.
在并行服务器的环境里,可以使用多个计算机来存取共享磁盘组(只要硬件结构允许这种共享)上的一个单个数据库.
在Oracle8中,通过缩短故障处理时的停工期,这个功能得到了提高.
而且,由于对与并行服务器相联系的总任务数进行了最小化,性能也得到改进.
(6)改进的复制功能复制功能用来将一些表从一个数据库中复制到另一个数据库中.
Oracle8中,复制是基于行标识(ID),并且使用一系列触发器来实现.
在Oracle8中,复制功能在几个方面都得到了改进.
第一,能够并行地以多个进程流(与并行查询类似)来更新一个给定的场点(site),而不是只使用单一进程.
第二,为了提高性能,复制功能直接包含在服务器软件之内,而不是由一系列触发器组成.
第三,现在可以根据表的主关键字来更新一个快照,而不是使用行标识,因为行标识在需要经常重新组织的数据库中发生变化.
(7)对非结构化数据的支持Oracle公司的一个初衷就是将Oracle系统变成一个媒体服务器.
为此,大对象类型的范围得到了增强,突破了原来的2GB的限制.
而且,现在允许每个表有多个大对象类型.
大对象的存取和更新功能也得到加强,变得更加有效.
(8)优化器的增强优化器是Oracle软件的一部分,用于在检索数据库信息时确定合适的算法.
优化器已经得到改进,可以进行更好的决策.
在优化器的改进中,特别需要指出的是用于数据库常见的新模式的算法.
除了上述的改进功能,Oracle8还增强了新的功能:(1)表分割(Tablepartitioning)对于处理超大型的表,这是一个重大的改进.
可以根据某些逻辑索引值将一个表分成多个部分(例如,可将一个Orders表按月份划分成若干段).
每个部分段可置于不同的磁第4Oracle8数据库介绍131盘上.
这样安排是有好处的,因为Oracle系统可以智能地判断何时需要哪一段.
当执行一个查询时,系统将略过不需要的分段,从而减少了扫描的数据量.
表分割又可以提高可靠性,如当一个表的某一个分段由于磁盘要求或其他方面的故障而丢失,依然可以操作这个数据库.
当然,不能发出一个查询来要求已丢失分段中的信息.
但可以面向其他完好的分段发出查询,并向另一个分段添加数据.
(2)索引分割(Indexpartitioning)索引分割类似于上面描述的表分割,是根据索引的值将一个索引划分为多个部分(磁盘).
这对于大的索引在分割式(splitting)磁盘输入输出时非常有用.
(3)在服务器内的备份与恢复管理(Backupandrecoverymanagementwithintheserver)Oracle以前的版本根据操作系统的实用程序来执行备份.
但随着复杂的备份策略,需要利用数据库及其结构方面的知识.
在Oracle8数据库系统中实现了更复杂的备份策略,并通过了企业管理工具(EnterpriseManagerTool)来调整.
可以使用这个工具确定哪些东西被备份过,并实现有效的恢复.
(4)连接管理(ConnectionManager)在处理用户和数据库连接时,为使系统资源得到更好的利用,Oracle实现了连接管理.
(5)安全服务器(SecurityServer)在分布式数据库环境下,各个数据库并发运行,系统要进行相应的维护工作.
Oracle8使用安全服务器在一个单独的场点对此进行集中管理,这个场点可以在企业管理器(EnterpriseManager)中用图形用户界面进行维护.
现在所有数据库都到这个中央资料库访问安全信息,而不必各自在内部维护这些信息.
(6)用户定义数据类型(User-defineddatatypes)尽管Oracle提供了很多的数据类型,但高级的用户还需要由基本数据类型构成的复杂数据类型(如同X光片需要同病人的其他信息相结合,构成一个单一数据项).
Oracle8允许用户用基本数据类型的组合来定义数据类型,并当作单一数据对象处理.
(7)面向对象的扩展(Object-orientedextensions)Oracle8实现了面向对象程序设计中的一些功能,包括数据方法和数据类型.
这些数据和方法被看作是组合在一起的实体(对象)来处理.
(8)数据插件(Datacartridge)用户利用Oracle数据库建立应用已经很久了.
然而现在许多人希望他们的软件能同Oracle更紧密地结合.
可以通过配置数据插件来处理复杂数据类型(如视频)或提供扩展的软件(如图像识别系统软件).
这里需要强调的是,数据插件是通过应用程序编程接口(API)同数据库紧密连接的,而不是仅仅通过客户机—服务器数据访问机制来连接.
4.
1.
3Oracle8产品家族Oracle8实际上是一个产品的家族.
它包括提供数据库管理服务的软件,也包括一系列工具,使用户可以访问和更新数据库中的数据(如SQL*Plus,Loader,Import和Export).
它还包括一系列管理工具,以便执行例行管理任务以及维护数据库的运行(比如Servermanager和EnterpriseManager).
另外还有一些可选的部件(其中包括改进的复制功能和并行服务器),用以执行特殊的功能.
这些可选项可以另外购买,不包含在基本的Oracle8服务器软件包中.
132Oracle8i数据库开发与专业应用4.
1.
4在应用环境中装备Oracle8Oracle8支持几种不同的体系结构.
可以用Oracle8作为传统的主机-终端系统,在其上编写的软件使用某种字符模式的界面运行在服务器上.
也可以用客户机-服务器结构实现Oracle8,以PC提供前端功能,以服务器提供数据库管理功能.
也可以实现Web服务器或应用服务器,用三个不同的计算机来提供服务.
4.
2Oracle数据库体系"数据库"这个术语既可以作为整个数据库管理环境的名字,也可以用来描述建立关系型数据库管理系统(RDBMS)的逻辑和物理的数据结构.
可以把Oracle数据库定义为共同组成的数据处理环境的配置文件、数据文件、控制文件以及重做日志文件、表索引和其他包含在这些对象中的结构.
4.
2.
1SYS和SYSTEM模式SYS和SYSTEM是每个Oracle数据库都缺省安装的两个账户.
SYS上模式是所有内部数据库表、结构、供给包和过程等等的拥有者,它还拥有所有的V$和数据字典视图,并创建所有封装的数据库角色(DBA,CONNECT,RESOURCE等等).
SYS是一个Oracle数据库的根用户或系统管理员.
由于它具有全能的性质,应尽量避免作为SYS注册到系统中工作.
当以SYS账户注册到系统中工作,哪怕一个简单的打字错误,就有可能造成毁灭性的灾难.
SYS账户是唯一能够访问特定内部数据字典表的用户,因为它拥有所有的数据字典结构,为了将数据字典对象明确地授权给其他模式,SYS也是必须登录的账户.
当使用数据字典视图和表编写存储过程或触发器时,也必须使用SYS账户.
当数据库首次安装时,SYS账户的缺省口令是CHANGE_ON_INSTALL,并且每个称职的系统管理员都会立即更改这个口令.
SYSTEM模式也是在数据库创建时安装的,是用于DBA任务的缺省账户.
SYSTEM也对所有的数据库对象拥有完全的权限,而且许多第三方工具软件依赖于SYSTEM模式的存在及特权.
SYSTEM账户的缺省口令是MANAGER,并且像SYS口令一样,在数据库创建后应该立即更改.
许多数据库系统管理员使用SYSTEM模式执行数据库管理任务,但它更适合创建一个特殊的用户来完成数据库管理员的任务,这就确保了一个特殊的账户与一个特定的人相连,而那个特定的用户则对全部数据库的修改负有责任.
因为这些模式都被大家所熟知,并且存在于每个Oracle数据库中,在安装数据库后立即更改它们的缺省口令是很重要的,这样可以防止对账户未经授权的访问.
如果安全性是个主要的问题,或许还应该考虑将这些账户变为不可登录,只在需要登录时,才设置合法的口令.
发出ALERTUSERXXXIDENTIFIEDBYVALUES"口令"命令,可以禁止对一个账户的注册,这里的口令是任何小写字符串.
这就将储存的口令设置为用户给出的实际的值,而不是加密的方式,在加密方式中,Oracle用一个普通的ALERTUSERXXXINDENTIFIEDBY"口令"命令来存储口令.
对Oracle来说,产生一个小写加密口令字符串是不可能的,从而使得对该账户的登录变为不可能.
第4Oracle8数据库介绍1334.
2.
2数据库组件可以把数据库对象划分为两种不同的类型:一类是由RDBMS内部使用的对象,被称为系统数据库对象(systemdatabaseobject),另一类是可以通过任何程序访问的对象,被称为用户数据库对象(userdatabaseobject).
1.
系统数据库对象当提到系统数据库对象时,是指RDBMS用于支持数据库功能的数据库对象.
这些对象是由数据库系统管理员或服务器本身配置和创建的,并且不显式地用于用户数据库事务.
系统数据库对象主要有如下几种.
(1)初始化参数文件初始化参数文件(initializationparameterfile)或init.
ora是RDBMS主要的配置点,它是配置键码和数值的集合,每一个配置键码和数值都能控制或修改数据库和实例操作的某个方面.
它是一个ACSII文件,可以在UNIX服务器上的$ORACLE_HOME/DBS目录下和NT服务器上的$ORACLE_HOME/database下找到它.
默认条件下,文件的名字为initSID.
ora,在这里,SID相当于它所控制的数据库的标识符.
在一个UNIX服务器上,如果在命令行上没有显式地指定一个init.
ora文件,当启动一个数据库时,这就是Oracle服务器所要寻找的文件名.
每个Oracle数据库和实例都有它自己唯一的init.
ora文件.
init.
ora文件可以包含来自其他使用的IFILE参数的文件的配置值.
在UNIX环境中,通常将$ORACLE_HOME/dbs/init.
ora文件与其他位置的文件相连,以便使数据库环境安装有更好的控制和结构.
非正式的参数(主要是由OracleWorldwideCustomerSupport使用)使用前缀下划线来命名.
当数据库启动时,在创建实例或读取控制文件之前,先读取init.
ora文件.
init.
ora文件中的值决定着数据库和实例的特性,例如共享池、高速缓存、重做日志缓存分配、后台进程的自动启动、控制文件的读取和自动联机回滚段等等.
直到数据库被关闭并重新启动,对init.
ora文件中参数的更改才被承认.
在OracleRDBMS中,缺省的init.
ora文件位于$ORACLE_HOME/dbs目录下,带有针对小、中、大型数据库所预先设置的基本init.
ora参数和不同的推荐值.
当创建数据库和实例时,这个文件可被复制和重新命名.
通过查询V$PARAMETER视图,可以从数据库内部观察init.
ora文件中的配置参数集.
V$PARAMETER视图把所有的init.
ora参数和它们的值都列出来,并且每一个值都有一个标记符,用以指明参数值是否为服务器默认值.
在表4-1中,解释说明了包含在缺省init.
ora文件中的参数.
表4-1常用的init.
ora参数参数名称用途audit_trail允许或禁止写记录到审计追踪文件.
注意,这里只是允许审计,审计的动作必须分别配置background_dump_destOracle后台进程追踪文件的最终目录,包括alter.
logcompatible数据库的兼容级.
能够防止使用比所使用数据库版本参数值高的数据库特性control_files数据库的控制文件134Oracle8i数据库开发与专业应用(续)参数名称用途db_block_buffers包含在高速缓存中的数据库块数目.
db_block_buffersxdb_block_size=数据库高速缓存的大小,单位为字节db_block_sizeOracle数据库块的大小.
在数据库建立起来后,这个值就不能改变了db_files能够打开的数据库文件的最大数目db_name可选择的数据库的名字.
如果使用该参数,它必须与用在CREATEDATABASE语句中的数据库名称一致db_file_multiblock_read_count一次I/O操作所能读取数据库块的最大数.
这是用于顺序搜索的,当调整全表搜索时,是非常重要的dml_locks由所有数据库用户用于全部表的DML锁的最大数目log_archive_dest归档重做日志文件的最终位置log_archive_start允许或禁止自动归档.
如果允许,当实例启动时,ARCH进程自动地启动log_buffer分配给重做日志缓冲区的字节数log_checkpoint_interval触发一个检测点需要填充的重做日志文件块数processes能与数据库连接的操作系统进程的最大数目,其中包括后台进程.
当在UNIX服务器上调整共享内存时这很重要remote_login_passwordfile确定一个口令文件是否用于远程内部验证,并指定有多少实例可以使用一个口令文件.
它可以被设置为NONE、SHARED和EXCLUSIVErollback_segments在数据库启动时,自动联机回滚段的列表清单sequence_cache_entries能够存在系统全局区中的序列数.
它应当被设置成实例中随时能用的最大序列数shared_pool_size共享池的大小,用字节表示snapshot_refresh_processes在实例启动时,启动的SNP进程数目.
SNP进程负责刷新快照,以及执行由DBMS_JOB提交的数据库工作timed_stastistics允许或禁止收集数据库的实时统计信息.
虽然把该参数设置成"真"会导致性能开销,但是在数据库调整时有更大的灵活性uer_dump_dest用户追踪文件的最终记录,包括通过设置sql_trace为"真",所产生的那些文件(2)控制文件控制文件是数据库的心脏,它包含以下信息:属于数据库的数据文件和重做日志文件信息、数据库中的数据应该以何种字符集存储的信息、数据库中每个数据文件的状态和版本信息以及其他的重要信息.
包含在控制文件中的大部分参数是在数据库创建过程中设定的,并且相对来说是静态的.
也就是说,它们不是经常改变的.
控制文件采用二进制格式,并且是不可读或手工编辑的.
控制文件是在数据库创建时创建的.
大多数数据库可以操作多个控制文件.
特定控制文件的创建是在init.
ora参数CONTRLO_FILES中指定的,在CREATEDATABASE子句中指定的数据库创建参数存储在这些文件中.
如果没有正确的控制文件,数据库不能被打开.
如果由于某种原因,导致控制文件无效或毁坏,数据库将无法启动,并且存储在数据库中的数据信息将无法访问.
正是由于这个原因,控制文件的镜像备份功能是被Oracle服务器支持的,并且也是大力推荐的.
如果要将控制文件镜像备份到一个新的数据库中,只需要在发出CREATEDATABASE命令之前,为CONTROL_FILES指定一个以上的参数值即可.
要将控制文件镜像备份到一个现有的数据库中,必须关闭数据库,将当前的控制文件拷贝到你想要备份的目录当中,编辑CONTROL_FILES参数,指定新的控制文件的位置,然后启动数据库.
第4Oracle8数据库介绍135修改控制文件不像修改初始化参数并启动数据库那么容易.
为了改变任何控制文件参数,必须重新创建控制文件.
重新创建控制文件的步骤如下:①备份数据库:修改控制文件过程中,出现的任何一个错误都会毁坏数据库,使之无法恢复,因此在修改之前要备份数据库.
②发出ALERTDATABASEBACKUPCONTROLFILETOTRACE命令,它是来自服务器管理或SQL*Plus的命令.
这就建立了一个用户追踪文件(位于USER_DUMP_DEST),该文件带有重建当前控制文件所必须的命令.
③编辑在前面步骤中所产生的追踪文件.
除了CREATECONTROLFILE语句外,删除追踪文件中的所有行,设置新的参数值.
④正常关闭(SHUTDOWNNOMAL)数据库.
将旧的控制文件移放到备份目录里,确保Oracle在数据库启动时,不能在目录中找到任何文件的任何副本,否则下一步操作将会失败.
⑤执行STARTUPNOMOUNT命令启动数据库,运行编辑的CREATECONTROLFILE追踪文件,这将重建带有新参数值的控制文件.
⑥执行ALTERDATABASEOPEN命令.
在创建数据库时,把数据库参数值设为比需要的值高一些,可以避免重建控制文件.
将数据库的值设为比需要的高一些,带来的唯一负面影响是在内存和磁盘空间方面微不足道的浪费.
当创建数据库时,正确地设定CHARACTERSTER参数是很重要的,改变这个参数需要重新创建整个数据库,不能通过重建控制文件来改变它.
可配置的系统控制文件参见表4-2.
表4-2包含在控制文件中的可修改的配置参数参数名称说明MAXLOGFILES联机重做日志文件的最大数MAXLOGMEMBERS每个重做文件的最大成员数MAXDATAFILES数据文件的最大数MAXINSTANCES能够安装到这个数据库上的实例数(并行服务器)MAXLOGHISTORY用于恢复实例的归档重做日志文件组的最大数(并行服务器)要改变数据库名,要像前面所描述的那样重新创建控制文件.
但是,要在追踪文件中把REUSEDATABASE行变为SETDATABASE.
V$CONTROLFILE视图列出了Oracle服务器当前正在读写的控制文件.
应该经常通过执行语句ALTERDATABASEBACKUPCONTROLFILETOTRACE,保持控制文件的一个备份(在保持通常的二进制副本的同时),当所有其他的手段都失败的时候,它可以帮助重建数据库.
(3)联机重做日志文件日志写后台进程(LGWR)将重做日志缓冲区的内容写入联机重做日志文件中,重做日志储存了数据库的所有变化信息,并在数据库的恢复期间被Oracle使用.
如图4-1所示,联机重做日志文件至少由两组重做日志文件组成,并且按照一种循环的特性写入.
136Oracle8i数据库开发与专业应用图4-1带有多个成员的重做日志一个重做日志组如果当前正被LGWR写入,那么它是当前的.
当前日志组被填满,并且LGWR进程停止对它的写入而转到下一个日志组的时候,就发生日志切换.
当日志切换发生,并且归档日志模式被数据库允许的时候,前面写入的重做日志组被归档(ARCH)进程锁定,并被拷贝到磁盘或磁带上,具体拷贝方向取决于系统配置.
如果LGWR追上ARCH进程,并且需要实时写入由ARCH正在写入的组,所有的数据库活动将被挂起,直到ARCH进程写完日志.
如果在alert.
log文件中看到错误说明一个自由的日志组不能被LGWR进程锁定,那么说明需要添加更多的重做日志组或者调整日志组的大小.
每个日志组可由多个成员组成,日志组的每个成员是其他成员的精确镜像,并且重做日志项被并行地写入每个成员中.
如果LGWR不能写入组里的成员,它也不失败.
相反,它在alert.
log文件中写入一个数据项.
通过在每个组中使用多个成员,能防止数据库由于丢失重做日志而导致失效.
只要组里有一个成员是可用的,数据库就能继续工作.
通过使用RAID1(镜像)镜像备份重做日志组,可以获得同样的功能.
当LGWR进程必须为每个数据库事务更新多个日志组成员时,这将缓解上述情况造成的系统开销.
V$LOG和V$LOGFILE视图保存联机重做日志文件的信息,下列的查询检查当前日志的状态:SELECTb.
member,a.
bytes,a.
members,a.
statusFROMv$loga,v$logfilebWHEREa.
group#=b.
group#ORDERBYb.
member;(4)追踪文件所有的Oracle数据库都至少有一个文件用于记录系统信息、错误及主要事件.
这个文件叫做sidALERT.
log(这里sid是数据库系统的标识符),存储在由init.
ora参数BACKGROUND_DUMP_DEST指定的位置.
当调查数据库故障时,这是应该查看的第一个位置.
关键的错误总是在这里被记载,如数据库的启动和关闭信息、日志切换信息以及第4Oracle8数据库介绍137其他的事件.
后台进程和用户进程也建立他们自己的追踪文件,在其中记载出现问题和故障的信息.
后台进程追踪文件储存在BACKGROUND_DUMP_DEST指定的目录,而用户进程追踪文件储存在由USER_DUMP_DEST参数所设置的目录里.
将USER_DUMP_DEST目录设定为不同于由BACKGROUND_DUMP_DEST指定的目录,这样能够跟踪不同类型的追踪文件.
后台进程追踪文件被命名为sidPROC.
trc,这里sid是数据库的系统的标识符,PROC是后台进程(DBWR、LGWR、SMON和PMON等等)的名字.
用户会话追踪文件带有一个ora前缀,后面是一系列带有.
trc文件扩展名的唯一标识数字.
当一个用户会话引起无法恢复的问题(例如死锁或一个服务器进程崩溃)或用户会话被显式地告知创建跟踪文件时(例如当SQL跟踪被允许,或者发出一个ALTERDATABASEBACKUPCONTROLFILETOTRACE命令),用户会话追踪文件就被生成.
如要允许SQL追踪,在SQL*Plus提示符状态下发出ALERTSESSIONSETSQL_TRACE=TRUE命令,或把init.
ora参数SQL_TRACE设置为TRUE.
但是注意,在init.
ora中将SQL_TRACE=TRUE,将会导致把所有与数据库不一致的SQL语句写进文件中,这将产生大量的追踪信息.
可以在V$PARAMETER视图中获得BACKGROUND_DUMP_DEST和USER_DUMP_DEST参数的当前位置.
(5)行内部地址为了提取信息,Oracle数据库必须能够唯一识别数据库中的每一行.
OracleRDBMS中用于这种任务的内部结构叫做行内部地址(ROWID),这是存储数据库中每条记录行的物理位置的两字节数值.
ROWID的格式如下:BBBBBBBB.
RRRR.
FFFFBBBBBBBB是数据文件中行所在的块号(采用16进制).
RRRR是数据行所在块中的行号(采用16进制),FFFF是块所在的文件号(采用16进制).
例如一个表中可能有的一行ROWID形式为:00000680.
0000.
0001.
这表示它在第一个数据文件(0001)的68C块中,并且是该块的第一行(0000).
通过查询DBA_DATA_FILES视图,可以把前面ROWID中的文件号和文件名相匹配.
在Oracle8中,它们是在数据库启动时决定的.
当每行在第一次创建时,都会被分配一个ROWID.
除非该行被删除或该行所在的段被重组,否则这个ROWID保持不变.
在数据库中使用ROWID是找到一行的最快的方法.
数据库的每个表都有一个名为ROWID的伪列(pseudocolumn),通过查询它可以列出表中每一行的ROWID.
因为ROWID的唯一性,它可以被用来创造性地解决许多不同的难题.
例如,ROWID的一个最常见的用途是在数据库中识别那些具有相同值的列,语法如下:deletefromduplicate_tablewhereROWIDnotin(selectMIN(ROWID)fromduplicate_tablegroupbya1,a2);在查询时,有可以使用ROWID的实际值,下面显示一个在其中含有行的表的数据库文件数目:SELECTCOUNT(DISTINCT(SUBSTR(ROWID,15,14)))"Files"FROMtest_table;138Oracle8i数据库开发与专业应用(6)Oracle块能操作的最低级的数据库存储就是Oracle块,这是服务器能够访问的最小单元.
不应该把它与操作系统块混淆,一个Oracle块是由操作系统块组成的,它们是不同的.
Oracle是操作系统块的整数倍.
例如,在UNIX中,操作系统块通常为8KB,那么db_block_size应该设置为8192、16384等等,为8KB的整数倍.
所有的数据访问都是以Oracle块的形式实现的.
Oracle块的大小是指一次I/O过程中,RDBMS从数据文件中读写的字节数、数据库对象大小和高速缓存中的块也是以Oracle的形式设置的.
Oracle块的大小是在数据库创建时为数据库设置的,是不能改变的.
如在创建数据库后,认为需要大一些的或小一些的块,就不得不从头开始,重新建立整个数据库.
每个Oracle块都包含头信息空间、块中数据将来的更新空间以及块中实际存储所占空间.
块头保存着这样的信息,例如在块中有行存在的数据库段、同时可以有多少事务访问块等等.
每个块还分配了一定量的空间,用于块中储存行的更新,如果升级引起原先的行变大,那么这个自由空间就被使用了.
一个块可以用于接收新行的能力是通过PCTFREE和PCTUSED存储设备来控制的,PCTFREE参数负责分配块空间的百分比,这些空间被保留在一旁,用于数据更新.
例如,如果一个块有一个30%的PCTFREE值,那么该块70%的空间是用于存储新行的,当该块70%的块已经被填充时,Oracle把该块从自由列表中取出,利用剩下的30%的空间来处理要求更多的空间的块中的行的更新.
在块被重新放回自由列表之前,PCTUSED参数指定块中必须有多少自由空间(通过删除块中的行,或更新减少储存一行所需的时间).
PCTFREE参数和PCTUSED参数一起使用,确保一个块有足够的空间来满足将来的存储需要,而且确保了这个块不会反复摆动,换句话说,不会花费相当多的时间从自由列表进进出出.
PCTFREE和PCTUSED的值不应该等于100%,否则参数值就不起作用了.
因为数据块决定着在每一次I/O操作中能从数据库读取的字节数,所以它的大小是非常重要的调整因素.
联机事务处理(OnlineTransactionProcessig,OLTP)应用有时可以从较小的块上获益,因为这些应用在每个事务期间,通常要读写少量的数据,因此较小的块在I/O性能方面更为有效.
对于仓库式的或决策支持系统(DecisionSupportSystem,DSS)数据库来说,较大的数据库块能够极大地提高性能.
这些类型的应用在一个事务过程中,常常需要处理大量的数据,并且通常考虑系统的响应时间以分钟来计时,而不以秒来计时.
通过设置数据库块的大小,可以调整一次I/O操作所读入内存缓冲中的数据量.
当决定数据库块的大小时,必须记住应用将要执行的特定类型的数据存储,以及希望储存在每一行中的数据量.
一个过大的数据库块会把一些不必要的数据读进缓冲区,而一些太小的块则会导致行链接.
2.
用户数据库对象用户数据库对象(Userdatabaseobjects)是指那些不是OracleRDBMS专用的对象.
当然,他们是受Oracle内部管理的,但是它们能够提供一组用户建造块,利用这些块用户可以创建自己的数据库.
用户数据库对象包括数据文件、区间、表空间以及数据库段.
(1)数据文件第4Oracle8数据库介绍139Oracle数据文件作为操作系统文件而存在,每个数据文件被分配给一个表空间,并且拥有存储在那个表空间里的实际数据.
数据文件是文件系统中的实际文件,它可以像其他任何操作系统文件一样进行监控和操作.
存储在数据文件中的数据采用Oracle二进制格式,这样除了OracleRDBMS外,不能被其他任何东西读取.
数据文件是使用SQL命令CREATETABLESPACE或ALTERTABLESPACE创建的.
一个数据文件的大小是根据CREATE语句中指定的大小来建立的,而不是由它所存储的数据量决定的.
例如,一个以10MB大小创建的数据文件,不管它包含一行或一百万行,它都用满10MB的空间.
从Oracle7.
3开始,数据库管理具备动态增加和缩减Oracle数据文件的能力.
然而,数据文件不能被收缩得小于数据文件的高水位线.
数据文件也能被单个脱机,以进行备份或其他的数据库操作.
可以访问DBA_DATA_FILES和V$DATFILE视图,来获得数据文件中为数据库定义的有关信息.
下列查询展示了表空间与数据文件之间的映射:SELECTtablespace_name,file_name,bytesFROMdba_data_filesORDERBYtablespace_name,file_name;(2)区间区间(extent)是一个存储单位,由一个或多个逻辑(就是说,在Oracle内)连续的Oracle块组成,每个数据库段都是由一个或多个区间组成,在一个数据库段中的每个区间的大小可以相同或不同.
从Oracle7.
3开始,一个数据库对象所能拥有的区间最大数取决于Oracle块的大小.
一个数据库段在对象创建时,完全按照CREATE命令的存储子句所指定的来分配区间.
当一个段再也无法把新数据库填充到它当前分配的区间中时,必须为它分配其他的区间.
下一个分配区间的大小取决好几个因素,有些因素并不是显而易见的.
新区间的分配管理是数据库空间管理主要涉及的内容.
区间储存在DBA_EXTENTS视图中.
(3)表空间表空间(tablespace)是一个数据结构,用于组合被相似地访问的数据.
每个表空间都是由一个或多个数据文件组成的,所有的数据库对象必须被指定一个表空间,它们在那里被创建.
于是组成对象的数据就被储存到分配给指定表空间的数据文件中.
表空间被用于分隔设计数据访问的I/O,例如,可以创建一个表空间来存储数据对象,也可以创建另外一个表空间来存储索引对象.
通过给驻留在不同物理磁盘上的表空间分配数据文件,可以确保对索引数据的访问不会影响对索引指向的数据的访问.
在数据库备份和恢复中,表空间也扮演了一个重要的角色.
因为一个表空间直接映射着一个或多个数据文件,备份和恢复数据通常是在表空间(数据文件)级下进行的.
当然,备份或恢复操作应用于整个数据库时是例外的.
可以在DBA_TABLESPACE查看表空间的信息.
4.
2.
3数据库段数据库段(databasesegment)是储存在数据库中的用户建立的对象.
这在很大程度上140Oracle8i数据库开发与专业应用包括了组成模式的数据(表)和索引.
除了用户创建的数据和索引外,通常还有两种类型的段被称为系统段和管理员创建段,它们是临时段和回滚段.
当然,那些拥有合法权限的用户可以创建这些段.
但是,最好由数据库系统管理员来创建,然后让应用用户和程序共享这些段.
1.
表表(table)是存储数据的数据库段.
每个表是由一个或多个列组成的,每个列都被指定一个名字和数据类型.
每个列的数据类型为储存在表中的数据定义了类和精度,合法的Oracle数据类型列于表4-3中.
表4-3有效的Oracle列数据类型数据类型说明最大长度CHAR固定长度的字符域,尾部使用空格填充255字节VARCHAR变长字符域2KBVARCHAR2变长字符域2KBLONG变长字符数据2GBNUMBER变长数字数据1*10-130~9.
99*10125DATE固定长度的日期和时间域,从公元前到公元后4712年12月31日4712年1月1日RAW变长原始二进制数据255字节LONGRAW变长原始二进制数据2GBROWID行内部地址变量类型6字节为预防ANSI规定的改变,Oracle建议所有的变长字符域定义为VARCHAR2,而不是VARCHAR.
Oracle保证永远不对VARCHAR2做出导致需要对应用程序修改才能使它们向上兼容的功能性变化.
因为VARCHAR的功能是由ANSI标准委员会授权管理的,Oracle不能保证这些功能在新版本里不发生巨大的变化.
2.
索引索引(index)是为了加速对特定表数据的访问而创建的数据段.
一个索引拥有表的一列或多列的值以及与这些相对应的行内部地址(ROWID).
当Oracle服务器需要在表中查找某一指定行时,它在索引中查找ROWID,然后直接从表中提出数据.
在OracleRDBMS中有几种可用的索引类型.
到目前为止,最常用的索引类型是B*-Tree(B-树)索引.
这是执行标准的CREATEINDEX语句时,需要使用的索引类型.
B*-Tree索引是标准的搜索树算法的一个变异,其中通过遍历索引树,保证能在相同数量的树遍历过程中找到所有的叶子结点.
每一个叶子结点指向下一个和前一个叶子结点的位置,这样能够在索引扫描范围内进行快速索引搜索及类似操作.
B*-Tree索引能确保维持平衡状态,并且每个结点的四分之三都是空的,以便为更新提供可用空间.
簇(cluster)索引是在簇中被表共享的列的索引.
不同于常规的索引,簇索引在索引中只存储一次索引键值,而不管索引键在表中重复多少次.
在簇上能够执行任何数据操作语言(DML)前,必须在簇上创建簇索引.
最新的索引类型是位映射(bitmap)索引,在一个位映射索引中,位映射是从索引表的列值中创建而来的,并存储在索引中,而不是由实际的列值创建的.
换句话说,在键上索引为每一行保存一个位映射,键对于表中的每一行包含一位信息.
如果值包含在行里,位值是1,否则为0.
在基数较低(不同值数量较小)的列中,位映射索引可以比传统的B*-Tree索引第4Oracle8数据库介绍141更小,更有效.
表4-4是一个关于汽车表的位映射例子,位映射的键是在表中的颜色列.
表4-4汽车表位映射索引汽车颜色位映射红色00010010001000100001绿色10000001010001001010银色00100000100010010000白色00001000000000000100黑色01000100000100000000在这个例子中,表中共有20行.
汽车表中行与颜色相匹配处,位映射为1,即第4、7、11、15和20行是红色汽车,而第2、6和12行是黑色汽车.
位映射索引结构创造了比传统B*-Tree索引更小的索引,但位映射只适用于特定类型数据.
3.
回滚段回滚段(rollbacksegment)是存储在数据库事务中的发生改变的原始数据块的数据库对象.
它们用于提供数据的已经改变但尚未提交的读一致性视图.
当做出数据改变时,原始数据就被拷贝到回滚段中,而且在内存缓冲区对数据块做出更改.
如果其他用户会话要求同样的数据,那么存储在回滚段中的原始数据就会被返回(这叫读一致性).
当做出更改的会话被提交时,回滚段项将被标明为无效.
多个用户会话可以共享一个回滚段,每个回滚段至少由两个区间组成.
当一个事务开始时,用户会话在一个可用回滚段中得到一个可用区间的专用锁,于是事务信息被写入回滚段中,如果事务填满了第一个区间,它会被分配另一个区间.
如果另一个区间不可用,回滚段会自动地给自己分配其他的区间,这正是用户会话所要获取的,这叫回滚段扩展(rollbacksegmentextension).
因为区间的分配影响性能,因此,应该在没有分配新区间的情况下,使所有事务能够执行.
如果回滚段不能分配其他的区间(或许是因为已经达到回滚段的最大区间数,或者在回滚段表空间上没有更多的自由空间),那么就会出现错误,而且事务将被回滚.
这通常发生在装载大量数据时,在那时联机回滚段无法为事务提供足够的空间来存储全部的回滚信息.
DBA_ROLLBACK_SEGS视图中含有关于回滚段的信息.
4.
表簇表簇(tablecluster)是一个数据库对象,它可以将那些经常在相同数据块中一起使用的表进行物理分组.
当处理那些经常连接在一起进行查询的表时,表簇是特别有效的.
一个表簇存储簇键(用于将表连接到一起的列),以及簇表中的列值.
因为簇中的表都被储存在相同的数据库块中,所以使用簇工作时,I/O操作就减少了.
5.
哈西簇哈西簇(hashcluster)是数据库存储的最后选项.
在一个哈西簇中,表是基于哈西值组织的,在表的主键值上使用哈西函数可以得到这个哈西值.
在从哈西簇中提取数据时,哈西函数被用于要求的键值上,结果值给出Oracle哈西簇中的存储数据的块.
使用哈西簇能明显减少从表中提取数据行的I/O操作,但是使用哈西簇也有一些缺点.
142Oracle8i数据库开发与专业应用4.
2.
4Oracle数据字典数据字典(datadictionary)是存储数据库中的所有对象信息的知识库,OracleRDBMS使用数据字典获取对象信息和安全信息,而用户和数据库系统管理员用它来查阅数据库信息.
它保存着数据库中数据库对象和段的信息,例如表、视图、索引、包以及过程,它还保存着关于用户、权限、角色、审计和约束等的信息.
数据字典是只读的,不能对任何数据字典表中的任何信息进行手工更新或改动.
它由四部分组成:内部RDBMS(X$)表、数据字典表、动态性能(V$)视图和数据字典视图.
1.
内部RDBMS(X$)表Oracle数据库的心脏就是所谓的内部RDBMS(X$)表,这些表被OracleRDBMS用于跟踪内部数据库信息.
X$表是加密命名的、非文献性的表,并且几乎是无法解密的.
大多数X$表被设计成不能被数据库系统管理员或用户直接使用.
尽管如此,它们仍包含着有价值的信息.
许多非文献性的或内部的统计和配置只能在X$表中找到.
要解密在某个X$表中储存的信息,最简单的方法是从一个已知的数据字典表倒推寻找.
SQL*Plus自动跟踪特性对这项工作是非常有用的.
例如,要想知道V$SGASTAT中的信息到底存放在哪里,可以执行下面的分析步骤:(1)作为SYS用户(或者一个对X$和V$表有明确访问权限的账户)登录到SQL*Plus.
如果所登录的模式中不存在PLAN_TABLE,可以通过运行$ORACLE_HOME/rdbms/admin/UTLXPLAN.
sql语句来建立一个.
(2)执行SQL*Plus命令SETAUTOTRACEON.
(3)针对感兴趣的内容的表执行一条查询,把WHERE子句设为一个永远不会为真的值,以便没有任何行能够返回:SELECT*FROMV$sgastatWHERE0=1.
在其他信息中,自动追踪返回类似下列的输出:ExecutionPlan0SELECTSTATEMENTOptimizer=CHOOSE10FILTER21FIXEDTABLE(FULL)OF'X$KSMSS'从SQL追踪的输出,可以解密数据字典基表,从基表中抽取视图信息.
查询建立在这种形式上的X$表,常常可以产生令人吃惊的信息.
2.
数据字典表数据字典表(datadictionarytable)存储表、索引、约束以及所有其他数据库结构的信息.
它们属于SYS,通过运行SQL.
BSQ脚本来创建(在数据库创建时自动发生).
通过它们名字后面的$符号(tab$、seg$、cons$等等),可以很容易地将它们辨认出来.
在数据字典视图中可以找到数据字典表中的大部分信息,但是一些应用或查询也可以从使用包含在基表中的信息中获益.
数据字典的列和表在SQL.
BSQ文件中被很好地归档,这个文件在$ORACLE_HOME/dbs目录中可以找到.
当熟悉了SQL.
BSQ的内容后,就可以更好地理解OracleRDBMS实际上是怎样储存数据字典和数据库信息的了.
3.
动态性能视图动态性能(V$)视图(dynamicperformance(V$)view)是Oracle数据库系统管理员第4Oracle8数据库介绍143的主要依靠,这些视图包含了大量数据库函数运行时的性能和统计信息.
它们还具有相当强的可读性(与X$表相反),也就是说能够被数据库系统管理员用于诊断和解决问题.
注意,V$视图实际上是由SYS拥有V$的视图的公共同义词,当编写读取V$表的存储过程或函数时,这是很值得注意的.
引用或授权基表V$视图(而不是V$公共同义词)常常是必要的.
4.
2.
5其他数据库对象在数据库中还储存着一些其他的对象,这些对象没有被准确地按段分类,尽管如此还是应该讨论一下它们.
它们包括视图、序列、同义词、触发器、数据库链以及存储包、过程和函数.
1.
视图视图是存储的能够被查询的SQL语句.
由于安全的原因,视图用于隐藏一些数据(例如一个HR视图只显示姓、名和地址信息,而没有显示社会保险号和工资数据),并使复杂的查询变得易于理解和使用.
通过在远程数据库表上创建视图,视图也能被用于隐藏分布式数据库对象.
任何可以作为SQL查询而执行的语句,都能被创建成为一个视图.
在设计应用程序时,视图是非常有用的,因为它们能够以表的形式隐藏复杂的查询逻辑,使得更易于查询.
它们可以和嵌在内部的优化器提示一起被创建,以确保最佳的查询性能.
THEDBA_VIEWS视图存有在数据库中创建的视图的信息.
2.
序列序列是产生唯一数码的数据库对象.
序列创建时带有初始值、增量值以及最大值.
每次从序列中返回一个数字,当前序列值是一个一个递增的,每个序列产生的数字可长达38位.
可以通过选择来自序列的NEXTVAL或CURRVAL伪列使用序列.
例如,有一个名为EMP_SEQ的序列,执行"SELECTEMP_SEQ.
NEXTVALFROMDUAL;"语句,返回序列的下一个整数值,并且当前序列值加1;可以使用"SELECTEMP_SEQ.
CURRVALFROMDUAL;"语句,返回当前序列的整数值.
注意,要使用CURRVAL,必须通过执行一个序列在NEXTVAL伪列上的查询,来预先初始化用户会话的序列.
序列最通常的用途是提供唯一的数字作为表主键列的代用品.
有关序列的信息储存在DBA_SEQUENCES视图中.
3.
触发器触发器(trigger)是存储过程,当针对一个表发生特定的动作时,就会激活它.
触发器可以被编码.
当针对一个表进行插入、更新、删除或三种操作的结合时,激活触发器,也可以在某行被影响或某条语句出现时被激活.
触发器经常用于加强数据完整性约束和业务规则,这些业务规则对于内建的Oracle引用完整性约束来说实在是太复杂了.
关于数据库触发器的信息可以在DBA_TRIGGERS视图中找到.
4.
同义词同义词(synonym)是指向其他数据库表的数据库指针.
当创建一个同义词时,就指定了一个同义词名字和同义词所应用的对象.
当引用同义词名字时,Oracle服务器会自动地用同义词定义的对象名字来代替同义词的名字.
同义词有两种类型:私有(private)和公共(public).
私有同义词是在指定的模式中创建的,并且只允许拥有它的模式访问.
公共同义词由PUBLIC模式所拥有,所有的数据库模式都144Oracle8i数据库开发与专业应用可以引用它们.
理解在SQL语句中对象名字的解析顺序是十分重要的.
如果执行SQL语句"SELECT*FROMEMP_SALARY;",Oracle服务器将按照如下方式决定EMP_SALARY对象:(1)首先,服务器查看在发出命令的用户模式中是否有名为EMP_SALARY的表或视图.
(2)如果这个表或视图不存在,Oracle检查名为EMP_SALARY的私有同义词是否存在.
(3)如果这个私有同义词存在,这个同义词所引用的对象将取代EMP_SALARY.
(4)如果这个私有同义词不存在,检查名为EMP_SALARY的公共同义词是否存在.
(5)如果这个公共同义词不存在,Oracle返回信息"ORA-000942,tableorviewdoesnotexist".
公共同义词应小心使用,因为所有的模式都可以用公共同义词决定对象名字,以至产生无法预料的结果.
关于公共同义词的信息储存在DBA_SYNONYMS中.
注意,在这个视图中,公共同义词的拥有者作为PUBLIC被列出来.
5.
数据库链数据库链(databaselink)是与远程数据库连接的存储定义,它们用于查询分布式数据库环境中的远程表.
因为它们存储在Oracle数据库中,它们被归入数据库对象类别.
关于数据库链的详细信息可以在DBA_DB_LINKS数据字典视图中得到.
如果使用特定的UserID和口令与远程数据库连接,DBA_DB_LINKS是一种能够以明码存储口令的视图.
当允许终端用户访问这个数据库视图时,一定要小心.
6.
包、过程和函数存储包、过程和函数与它们的源代码一起存放在数据字典中.
一个存储过程是一个操作的代码单元,可以被传递参数,并能够返回值.
一个存储函数是一个代码单元,可以被传递参数,并能够返回一个值.
一个包是一个过程、变量和函数的集合,包按照功能被逻辑地分组.
可以通过DBA_OBJECTS和DBA_SOURCE视图查看有关存储包、过程和函数的有关信息.
4.
3Oracle的一些基本概念4.
3.
1进程现在深入一点讨论后台进程.
Oracle进程可以分为四类:对用户的请求提供服务;向数据文件中写数据;在日志文件中记录事务;监控数据库的功能运行.
1.
用户进程第一组进程是用户用来请求提供服务的进程.
可将它们看作是用户与Oracle之间的联络人.
当你需要信息时,它们为你寻找;当你要更新数据库或往数据库添加内容时,它们将相应的事务存放在共享内存区,以备将来转换到数据文件中.
用户进程的用途就是作为用户和Oracle数据库的接口.
2.
数据写入程序第二组进程用于将数据写到数据文件中.
当用户向Oracle数据库中写数据时,数据首先存放在内存区.
然后Oracle使用一个或多个数据库写入(databasewriter)进程将共享内存区中的数据更有效地写到数据文件中.
最后Oracle再将内存区中占用的空间释放,供其他第4Oracle8数据库介绍145的事务和查询使用.
还有一个可选的检查点(checkpoint)进程,它使用最近一次对数据库执行的事务的记载,来更新所有的数据(使用内部Oracle事务号).
如果检查点进程没有启动,那么数据库写入进程将代替行使这个功能.
3.
日志进程第三组进程用于在日志文件中记录事务.
商业级的多用户数据库系统与其他系统的一个很重要的差别就是,故障(如磁盘故障)恢复是非常重要的.
Oracle故障恢复实现了其中的一部分,是通过在数据文件之外一个单独的文件中记载每个事务(即在一个特殊的表中为每个事务插入一个记录)来实现的.
如果发生某个文件丢失的情况,则日志文件使用从备份文件中检索出来的该文件的拷贝,将数据文件恢复到故障发生前的状态.
4.
监控进程第四组进程用来监控数据库的功能.
可能数据库会给我们很复杂的感觉,但是,我们不必密切注意数据库发生了什么,也用不着管理那些细节问题.
Oracle实现了若干个进程来监管数据库并处理所发生的问题.
4.
3.
2内存与速度共享内存是OracleRDBMS中提高速度的关键.
Oracle内存区是需要密切注意的内容,又是不易把握的内容,理解它很重要.
可以运行操作系统实用程序来查看哪个进程在运行;也可以查看数据文件,看它何时更新过、文件有多大等等.
但对于共享内存来说,就没有多少类似实用程序的方法来检查全部的共享内存,看它们是否正常工作.
Oracle所用的内存区的不同组件如图4-2所示.
图4-2Oracle内存区的简单示意图1.
软件代码区软件代码区是用来存储Oracle数据库本身的软件代码.
在某些操作系统中,这个软件区可以在实例之间共享.
注意这里的软件指的是数据库自身运行的软件,而不是用户开发的应用程序.
2.
系统全局区(SGA)系统全局区可看作一个Oracle数据库的心脏.
用户的进程向这个内存区发送事务,并146Oracle8i数据库开发与专业应用且以这里作为高速缓存读取命中的数据,以实现加速的目的.
有四部分内容存储在SGA中:(1)数据库缓冲区(databasebuffercache)用来存放等待写入磁盘或提供读取的数据库记录.
(2)重做日志缓冲区(redologbuffer)用来存放一个已经对数据库执行,并等待写入到重做日志文件中的事务的副本.
(3)共享SQL区存放已经编译好并准备执行的查询.
在许多数据库中,用户会对同一个查询执行很多次,当这些查询在内存区中等待执行时性能会增强.
在Oracle版本6中,这类信息实际上存放在程序全局区(PGA)中.
(4)数据字典缓冲区存放有关数据库本身、数据库对象(表、视图等)以及用户的数据.
3.
程序全局区(PGA)在SGA中存放的信息可以被实例中的每个人所共享,而程序全局区(PGA)中存放的信息只能被一个用户进程使用.
当一个人建立一个Oracle会话时(指用户和一个数据库实例相连接),Oracle就建立相应的PGA.
PGA包含栈空间,在许多情况下,存放有关用户会话的信息.
4.
排序区排序区可以极大地提高最常用的数据操作——排序的性能.
很少有人乐意按照数据输入的顺序(在Oracle中,是Oracle选择的存储数据的顺序)查阅数据行.
对多数应用来说,数据都要做某种排序(按照名字的拼音字母、日期顺序等).
由于访问内存比访问磁盘速度要快得多,Oracle将准备排序的一些数值存储在内存区中,并在那儿排序,这就是排序区的用途.
4.
3.
3磁盘存储存储机制速度较慢,但费用低廉并且不易损坏.
它在多数Oracle实例中可以见到磁盘驱动器.
这种小巧的东西可以建立以千兆甚至兆兆字节计的人类共同智慧的宝库.
下面讲述OracleRDBMS使用的几种文件类型,图4-3给出了Oracle数据文件的基本类型.
图4-3Oracle数据文件的基本类型第4Oracle8数据库介绍1471.
数据文件这些文件中包含了希望在关系数据库系统中查找的东西,是一系列被编排在表中的数据记录.
在这种文件中还有几种其他类型的数据库对象(索引、视图等),但只需明白这是可以找到所需要数据的地方就可以了.
需要指出的是,Oracle可以把软件存储在这些数据库文件中(以数据包或过程形式).
2.
日志文件联机重做日志文件的概念很简单,即把对数据库所做的每一个事务记录在一个文件中,这个文件独立于主数据文件.
当一个数据文件损坏时,这些文件用来恢复对数据库所做的所有改变.
Oracle使用一些这种文件,把它们排成一串,当写完最后一个文件时,就开始重写第一个联机重做日志,如此往复.
当向一个联机重做日志写完一个记录后,一个后台进程就将此重做日志文件复制成一个独立的文件,并赋给一个唯一的序号.
这个文件可以保存在磁盘或磁带上.
然后,当要恢复一个损坏的数据文件时,就从归档日志磁盘或磁带中取出所做的备份,并执行该备份完成以来所有记录在重做和归档日志文件上的事务.
3.
初始化文件初始化文件等价于微软DOS的antoexec.
bat和config.
sys文件.
在Oracle初始化文件集中有两个文件:init.
ora和config.
ora(尽管也可以只有一个或多于两个文件).
在特定的实例中,这些文件的名字中要带有相应Oracle实例的ID(SID).
例如,如果Oracle实例ID是test,那么文件名就是inittest.
ora和configtest.
ora.
这些文件的用途是为Oracle指定下面的启动参数:(1)所有Oracle用来改进性能的可调参数的值;(2)控制文件和归档日志文件的位置;(3)一些日志和错误消息文件的位置.
4.
控制文件控制文件用来帮助Oracle密切注意数据库的运行.
这些文件关注数据文件的位置,并记录最近对数据库执行的事务的编号.
后一个功能可使Oracle在故障恢复时知道要执行多少事务.
这些文件以二进制方式存储,所以不能用标准操作系统文本文件命令(如UNIX中的more,或VMS中的type)来读.
5.
SGA定义文件另一个二进制文件是SGA定义文件.
对所创建的每一个Oracle实例要有一个这样的文件.
这个文件可以使Oracle知道在启动时建立SGA的细节.
6.
日志与错误消息文件最后一类文件是日志和错误消息文件.
Oracle被设计成一个产品化的、商业级的数据库.
因此,当系统发生问题时,应该能够迅速确定出了什么错,并加以修复.
为支持这种需求,Oracle把主要的数据库活动(插入、更新等)记录在一组日志文件中.
而且,当Oracle的监控进程检测到一个问题时,会尽可能地将可找到的与该问题相关的数据写到一系列错误日志文件(在Oracle中称为跟踪文件)中.
这样,DBA看几个文件就可以确定发生了什么问题.
4.
3.
4与DBMS的连接Oracle的DBMS软件能够为应用程序处理所有的数据存储和数据检索的细节问题.
这148Oracle8i数据库开发与专业应用与过去的平面文件不同,在过去的文件中,应用程序要对存储和检索过程实施完全控制.
现在需要学习Oracle的界面来控制与数据存储应用的交互.
可以在两个级别上考虑这种交互.
第一级涉及应用程序与数据库管理系统之间相联系的通信机制.
第二级是在与数据库通信之后,如何规范信息请求,以及以什么格式把输出返回到应用程序中.
首先接受Oracle支持的通信机制,基本上有三种方式,如图4-4所示.
(1)第一种机制取决于标准的操作系统进程之间通信机制.
这是主机系统上应用程序之间交互的基础.
当用户的应用程序与OracleDBMS运行在同一台计算机时就使用这种机制.
(2)第二种机制取决于Oracle的通信实用程序,即SQL*Net(Oracle8之前就有,但Oracle8依然支持)或Net8.
该软件处理与适当的通信协议相连接的细节,并且传送查询/事务,然后将这些传送与数据库管理系统相连接.
(3)第三种机制使用WWW开发的标准协议和工具(HTTP和HTML).
可以在Oracle8系统上安装一个全功能的Web服务器.
这个服务器可以接收发来的数据,并且对连接在Internet和Intranet上的Web浏览器发送应答.
Web服务器和DBMS之间的通信使用前述的机制(即SQL*Net或ODBC),但客户工作站只能使用标准的Web协议.
这可以让相对较小的客户工作站,具有较小的内存,但有磁盘存储和一定的处理能力.
这也节省了客户端的配置工作.
图4-4Oracle通信机制当Oracle实现了CORBA(公共对象代理程序体系结构)时,就可以调用其他程序(如Oracle服务器)中的方法.
将可以用标准的方法来存取数据,这些标准方法作为CORBA的一部分,既可以对本地的计算机,也可以对远程计算机上的数据库进行这种访问.
当然也可以使用SQL*Net或Net8实现这种功能.
学习CORBAAPI的好处是可以用相同的技术来访问各种不同应用程序中的数据和方法.
Oracle还将提供Oracle产品之间的标准接口以简化在移植时的开发工作.
4.
3.
5多处理器配置前面所介绍的体系结构既适用于单处理器配置,也适用于多处理器配置.
如果拥有多处理器系统,就不允许作业在缓慢运行,而让一些CPU空闲着的状况.
Oracle已经实现了为支持大型查询而设计的软件,以便使用尽可能多的CPU来执行单一操作.
对支持多CPU第4Oracle8数据库介绍149的操作系统来说,Oracle增加了一系列进程来利用多出来CPU的.
1.
并行查询进程这些进程可将一个给定的查询分散到多个处理器上执行.
根据这个查询,Oracle可以使用一个处理器扫描索引,而另一个处理器从相应的表上检索信息.
Oracle可以用不同的处理器查询不同的表,然后将它们连接(join)起来.
这里关键是对于一个查询要让多个CPU同时工作,可能还有多个磁盘同时工作.
2.
并行加载进程这些进程可将批量处理数据库加载分散到多个处理器,类似于并行查询的做法.
3.
并行DML语句这些语句可对分割后的表使用多个处理器来做插入、更新和删除.
也可以对未分割的表使用多处理器执行insert、select等语句.
4.
3.
6容错一些公司和组织对系统很挑剔,他们宁愿多花钱,也要将系统出现不可用的可能性减到最小.
数据库及相应的应用程序要执行公司各机构的日常功能并实现基本的商业操作,它的正常运行就成为基本要求.
为此,Oracle在其体系结构中使用了一些手段来提高系统容错的能力.
引起错误的故障包括CPU、电源、内存或磁盘故障.
在投放市场的容错产品中,第一个可用系统实际上与Oracle无关.
磁盘生产商开发了建立磁盘镜像的技术(0级RAID).
0级RAID可以使操作系统重复写两个磁盘.
如果其中一个磁盘失效,操作系统可以使用另一个磁盘进行数据的存储和检索.
现在的镜像方案有基于硬件和基于软件两种.
一种Oracle镜像的实现是建立联机重做日志文件的镜像.
这样既可以提高性能,也可以改进安全性.
另一个保护Oracle数据库的容错技术是并行服务器技术,这是Oracle的DBMS可选产品.
这种产品用于这样的计算机系统,在系统中多个计算机可以访问一个公共磁盘组.
Oracle并行服务器协调在多个CPU上执行的活动和事务.
它解决发生在CPU之间的封锁.
它还提供这样的手段,即在一个CPU发生故障时,有另一个处理器接替执行未完成的任务.
Oracle8有一项新的容错功能,就是表和索引的分割功能.
可以分割一个给定的数据库表,将不同部分存放在不同地方.
已经实现了这种功能的检索方法是:尽管一个磁盘有故障,只要不需要访问这个故障磁盘上的数据,就仍然可以对这个经过分割的表执行查询.
例如存储六月份数据的磁盘坏了,但仍可以运行有关七月份数据的查询.
当一个大的系统,其中一部分数据经常访问,而其余部分不经常访问时,采用分割方法就很有用.
4.
4分区分区(partitioning)可能是Oracle8RDBMS中最重要的一个新特性.
尽管它的有些形式已经存在于Oracle7中,但是它在Oracle8中得到增强,并更完全地并入RDBMS引擎.
分区这个术语被"重载",对于数据库理论和其他厂商,它有很多层意思.
但是,这里所处理的是特定的Oracle分区表和索引能力.
150Oracle8i数据库开发与专业应用4.
4.
1什么是分区1.
分区在Oracle7中首次出现了用分区视图进行分区的能力.
分区视图帮助按照用户定义的业务规则、条件和规范,物理地分开磁盘上的数据存储.
从本质上讲,表和索引是能够按照给定的值被分离开的.
例如,一个州的列包括两个字符的州名缩写,一个表能够按组成国家的不同地区的州存储在分离的磁盘上.
这是通过使用检查约束来完成的,通过互斥来执行.
也就是说,对给定的列的所有不同的子集的值,当被分配时,不能重叠.
如果它们重叠,将可能在多个磁盘中存储同一行记录,但是Oracle就不知道使用哪一条记录.
另外,手工建立相互排斥的分区,应将partition_view_enabled初始化参数设置为真.
这将告诉优化器去研究对所有表被分区的可能性,以使WHERE语句能够访问唯一的或少量的几个分区,而不是访问组成整个表的全部分区.
对经历全表扫描的大表,这种有效性更为显著,但在其他环境中也能意识到这种有效性.
例如,用大的索引扫描或中等尺寸的表或索引访问能够提高分区的有效性.
优化器操作如果知道分区边界,就能够跳过分区,称为分区消除.
表4-5显示了如何在Oracle7中建立分区视图.
表4-5在Oracle7中创建分区视图SQL>createtableEAST_REGION(STATEID,SQL>createtableWEST_REGION(STATEID,SQL>createtableNORTH_REGION(STATEID,SQL>createtableSOUTH_REGION(STATEID,SQL>createviewNATIONALas2select*fromEAST_REGIONunionall3select*fromWEST_REGIONunionall4select*fromNORTH_REGIONunionall5select*fromSOUTH_REGIONunionallSQL>altertableEAST_REGION2addconstraintCKSTATEcheck3(STATE_IDbetween1and13);.
.
.
SQL>altertableSOUTH_REGION2addconstraintCKSTATEcheck3(STATE_IDbetween39and50);Oracle7分区视图的能力被加强和合并到Oracle8中,现在没有像partition_view_enabled这样的初始化参数需要告诉优化器.
除了在Oracle7中的初始化参数外,分区通过约束和视图来实现.
实际上,整个被分区的表是一个由约束创建和存储的所有这些平行的片段的联合体.
平行片段自身在实际的表中.
在Oracle8中情况有所不同,因为在Oracle8数据库存储结构中,分区是一个新的物理层,驻留在表和它的区间之间.
表被映射为一系列分区,这些分区反过来逐一映射到一系列区间,每个区间又映射到一个或多个表空间,每个表空间具有一个或多个数据文件.
图4-5比较了分区表和非分区表.
第4Oracle8数据库介绍151图4-5比较分区表和非分区表更进一步,分区是Oracle扩展SQL数据定义语言(DDL)的一部分.
分区作为语言的一部分是十分重要的,这意味着优化器是"知道分区"的,并可以在不需要像初始化参数这种东西的情况下,利用分区消除的优点.
表和索引能够被分区.
2.
分区策略这里存在着几种分区策略.
数据库对象(如表和索引)能够使用列值范围被分区,在Oracle7或Oracle8中均可以这么做,这就是通常所说的键值分区,因为列时常是表的索引或键值.
Oracle7能够用BETWEEN.
.
.
AND或=不等式限定范围,Oracle8要求使用新语言LESSTHAN.
有一些Oracle目前没有实现的其他类型的分区,这些分区包括散列分区和表达式分区,键值分区只是表达式分区的特殊情况.
当前使用的Oracle只能采用一列的顺序范围的连续子集对表进行分区.
假如纯粹是为性能原因,想使用某些MOD或RANDOM函数以某种方式平均分布数据,而与任何特定的列值无关,这时就需要Oracle7或Oracle8不提供的表达式分区.
通常而言,这有可能损坏正常能获得的分区消除的好处,但在有些情况下,它可能是有益的.
例如,分区有可能作为Oracle数据条和RAID的替代品.
图4-6显示了这个效果.
花费某些代价,能在Oracle中使用键值分区和每个表中的一个附加列模仿表达式分区.
图4-6RAID、数据条和分区的比较152Oracle8i数据库开发与专业应用例如,假如想将一Oracle表随意分区,可以在表中增加一列,该列含有对每一行唯一的机器产生的随机数,然后使用LESSTHAN关键字应用Oracle8的键值分区.
能作到这一点,是因为控制范围或随机数的产生,因为仅需要一定范围的数字做键值分区.
当然,缺点是在很大的表中有一个必须删除的附加列.
在Oracle7或Oracle8中,通常将并行查询与分区视图或分区联合使用.
通常设置并行程度等于在版本7中组成分区视图表的个数的倍数,或等于在版本8中组成表的分区的数量.
不仅能获得优化器分区消除的优势,而且也能获得在其余那些不能被消除的分区中进行并行查询的优势.
因此,通过使用并行查询,通常在存储大量数据的应用中使用分区.
这些应用倾向于巨型、数据库数据中心或数据仓库.
但是,联机事务进程系统也能受益,因为它们自身有可能是很大的数据库.
4.
4.
2Oracle8分区的实例1.
建立分区的例子在Oracle8中,一个表或索引能够达到64000个分区,分区键是被分区的表或索引上的列.
与主键一样,分区键能够组合,最多达到16列.
在分区表中,既不支持簇,也不支持大对象(如LONG或RAW).
非分区表既能有分区索引,也能有非分区索引.
同样,一个分区表既能有分区索引,也能有非分区索引.
但是,除简单性外,如可管理性和性能等问题也影响到物理设计.
表4-6是一个Oracle8分区的例子.
表4-6在Oracle中创建一个分区表SQL>createtableEMPS2(EMPIDnumber(5),EMPNAMEvarchar2(30),EMPADDRvarchar2(75))3partitionbyrange(EMPID)4(partitionP1valueslessthan(10001),5partitionP2valueslessthan(20001),6partitionP3valueslessthan(30001),7partitionP4valueslessthan(40001),8partitionP5valueslessthan(50001));在表4-6中,假设有50000个员工,员工号是1~50000,在EMPS表创建5个分区,每个分区存储10000员工.
一个表的单个分区能够有不同的表空间和存储参数,见表4-7.
表4-7分区表的表空间和参数SQL>createtableDEPTS1(DEPTIDnumber(2),DEPTNAMEvarchar2(20),2DEPTBUDGETnumber(9)3partitionbyrange(DEPTID)4(partitionP1valueslessthan(51)5tablespaceT1storage(initial10Mnext10M),6partitionP2valueslessthan(101)7tablespaceT2storage(initial20Mnext20M));VALUESLESSTHAN子句指定了那个分区的上限(不含此值).
例如,在表4-7中,分区P1能包含DEPTID值最高为50,但不能是51或更高.
因此在VALUELESSTHAN第4Oracle8数据库介绍153子句中的LESSTHAN的意思是严格地小于.
每个分区自动在分区上创建一个约束.
例如,企图插入一行DEPTID=101会引起ORA-14400错误:"插入的分区键值超过最高合法分区键值",因为最高分区(P2)的最大允许值是100.
为了避免发生这种情况,可以使用关键字MAXVALUE,见表4-8,这是一个对表4-7进行的简单修改.
表4-8分区表使用MAXVALUESQL>createtableDEPTS1(DEPTIDnumber(2),DEPTNAMEvarchar2(20),2DEPTBUDGETnumber(9)3partitionbyrange(DEPTID)4(partitionP1valueslessthan(51)5tablespaceT1storage(initial10Mnext10M),6partitionP2valueslessthan(maxvalue)7tablespaceT2storage(initial20Mnext20M));唯一不同的是在最高分区P2中值101被关键字MAXVALUE替代.
另外,NULL不能用于VALUELESSTHAN语句,当被插入的分区键是NULL值时,它们被分类为大于所有直接量值,但不大于MAXVALUE.
2.
使用分区的例子正如前面提到的,分区键可以由多列组成(也就是复合).
进行比较的顺序是从左到右,如果MAXVALUE被使用,MAXVALUE使用之后的所有值被忽略.
当在一个表上有一组合键时,或者想在频繁连接的表上通过主键和外键组合进行分区时,组合分区能够起作用.
表4-9给出有一个主键的分区表的例子.
表4-10给出了在一个表上有主键和外键组合的分区例子.
表4-9用主键分区SQL>createtableEMPS2(SSNnumber(9),SEQNOnumber(3),3EMPNAMEvarchar2(30),EMPADDRvarchar2(75))4primarykey(SSN,SEQNO)5partitionbyrange(SSN,SEANO)6(partitionP1valueslessthan(333333334,334),7partitionP2valueslessthan(666666668,668),8parititonP3valueslessthan(1000000000,1000));表4-10用主键和外键组合分区SQL>createtableEMPS2(EMPIDnumber(5),ENPNAMEvarchar2(30),3EMPADDRvarchar2(75),DEPTIDnumber(2))4primarykey(EMPID,DEPTID)5foreignkey(DEPTID)referencesDEPTS6partitionbyrange(EMPID,DEPTID)7(partitionP1valueslessthan(10001,21),8partitionP2valueslessthan(20001,41),9partitionP3valueslessthan(30001,61),10partitionP4valueslessthan(40001,81),11partitionP5valueslessthan(50001,101));154Oracle8i数据库开发与专业应用4.
4.
3分区索引有四种主要类型的分区或非分区表,它们是:(1)非分区(常规的)索引;(2)全局前缀索引;(3)本地前缀索引;(4)本地非前缀索引.
为了理解这些索引类型,首先需要学习一些背景知识.
被分区的表能够有分区索引或非分区索引,在索引分区上唯一真正的限制是一个聚簇的索引不能再被分区.
如果索引的最左列正好与分区键具有相同的顺序和数量,该索引认为是前缀的.
另外,索引可以是分区键的超集,而不是子集.
全局索引只能有前缀,但是它的分区分布通常与它的相关表不同.
如果想得到全局非前缀索引,应使用一个常规的索引替代.
Oracle选择不实现这种能力,因为利用它的开销将比使用常规的索引性能差.
全局索引不被Oracle维护.
也就是说,在创建之后,Oracle就不再对在索引分区和表分区之间的特定关系(值范围一致性)进行维护.
全局索引最主要的缺点是Oracle优化器不能利用全局索引进行分区消除.
另一方面,全局索引对分区索引值的范围提供选择,而不是对相关表的值范围提供选择.
这在多索引的情况下是有用的,例如查找使用数据仓库和相关联机分析处理应用的多维数据库.
同时,当存储非常珍贵时,全局索引是有吸引力的选择,因为它们可能比它们相关的表需要更少的分区.
表4-11给出了分区表和相关的全局索引的例子.
表4-11分区表的全局前缀索引SQL>createtableEMPS2(EMPIDnumber(5),SSNnumber(9),3EMPNAMEvarchar2(30),EMPADDRvarchar2(75))4partitionbyrange(EMPID)5(partitionP1valueslessthan(33334),6partitionP2valueslessthan(66668),7parititonP3valueslessthan(100000));SQL>createindexEMPS_IDX2onEMPS(EMPID,SSN)3global4partitionbyrange(EMPID)5partitionP2valueslessthan(50001),6partitionP3valueslessthan(100000));本地索引既可以有前缀,也可以没有前缀.
但是,在索引区和它们相关的表分区之间有一一对应关系.
当建立时,这种关系被认为是等分区的,因此由Oracle维护.
Oracle优化器能够利用分区消除的优势,这样相对于数据条与RAID更能够潜在地提供本质的性能增强.
因此,本地索引最主要的优点是自动等分区维护和相关的潜在性能收益.
用本地索引唯一不利的是,它严格要求必须与它的相关表具有相同的分区模式,不管是否有前缀.
表4-12给出了分区表和相关的本地前缀索引的例子,表4-13给出了分区表和相关的第4Oracle8数据库介绍155本地非索引的例子.
注意,在这两种情况下,将按照完全相同的表声明对它进行同等分区(LOCAL关键字告诉Oracle).
将表4-12、表4-13和表4-11相比较可以看出本地和全局的不同,本地前缀与本地非前缀之间的不同.
表4-12分区表和相关的本地前缀索引SQL>createtableEMPS2(EMPIDnumber(5),SSNnumber(9),3EMPNAMEvarchar2(30),EMPADDRvarchar2(75))4partitionbyrange(EMPID)5(partitionP1valueslessthan(33334),6partitionP2valueslessthan(66668),7parititonP3valueslessthan(100000));SQL>createindexEMPS_IDX2onEMPS(EMPID,SSN)3global4partitionbyrange(EMPID)5partitionP2valueslessthan(50001),6partitionP3valueslessthan(100000));表4-13分区表和相关的本地非前缀索引SQL>createtableEMPS2(EMPIDnumber(5),SSNnumber(9),3EMPNAMEvarchar2(30),EMPADDRvarchar2(75))4partitionbyrange(EMPID)5(partitionP1valueslessthan(33334),6partitionP2valueslessthan(66668),7parititonP3valueslessthan(100000));SQL>createindexEMPS_IDX2onEMPS(SSN)3local4(partitionIP1,5partitionIP2,6partitionIP3);尽管本地索引分区的区别仅在于选择了不同的索引列,但实际上决定它们是否被前缀,全局索引分区的区别取决于值范围的选择不同.
4.
4.
4维护操作有两个基本的语句执行所有的分区操作,它们是ALTERTABLE和ALTERINDEX.
对ALTERTABLE语句的分区扩展语句如下:DROPPARTITIONADDPARTITIONRENAMEPARTITIONMODIFYPARTITION156Oracle8i数据库开发与专业应用TRUNCATEPARTITIONSPLITPARTITIONMOVEPARTITIONEXCHANGEPARTITION对ALTERINDEX语句的分区扩展如下:DROPPARTITIONRENAMEPARTITIONREBUILDPARTITIONMODIFYPARTITIONSPLITPARTITIONPARALLELUNUSABLE对有经验的OracleDBA来说,大多数这些分区操作应该是熟悉的和自我说明的,因为它们通常看上去同平常的表和索引操作(如DROPTABLE和DROPINDEX)一样,但是应该仔细观察那些分区独有的操作(SPLIT、MOVE、EXCHANGE和UNUSABLE),表4-14给出了一个SPLIT的例子.
表4-14SPLITPARTITION维护操作SQL>altertableEMPSsplitpartitionP31at(75000)2into(partitionP3,partitionP4);在表4-14中所发生的是P3分区保持所有的EMPID的值小于75000(但大于在P2分区中的值),并产生一个新的P4分区存储EMPID的值等于或大于75000的行.
正如所见的SPLIT总产生一个附加的新分区.
表4-15给出一个MOVE操作的例子,这只是将一个分区从一个表空间移动到另一个表空间.
表4-15移动分区SQL>altertableEMPSmovepartitionP31tablespaceT3;表4-16显示EXCHANGE语句的一个类型.
EXCHANGE将一个分区表转换为一个非分区表,或将一个非分区表转换为一个分区表.
当想将Oracle7分区视图移植到Oracle8分区表时,很可能使用EXCHANGE.
表4-16将分区表转换为非分区表SQL>altertableEMPS8exchangepartitionP11withtableEMPS72includingindexes3withoutvalidation;表4-16也表明,可以有选择地包括索引列(用一定的限制)和不需要确认被移动的行的范围.
缺省时不包括索引并需要确认.
第4Oracle8数据库介绍157索引分区可以被Oracle标记为索引无效(IU),意思是如果不重建整个索引,也必须重建至少是那些组成这个索引的IU分区.
标志一个索引为IU的几种维护操作如下:(1)SQL*Loader或导入具有忽略索引的选项的分区;(2)ALTERTABLETRUNCATEPARTITION;(3)ALTERTABLESPLITPARTITION;(4)ALTERTABLEMOVEPARTITION;(5)ALTERINDEXSPLITPARTITION.
4.
4.
5并行能力有三种主要的并行能力能够用于分区以增强性能:(1)并行查询(PQ),也称为并行查询选项(PQO)(2)并行定义数据语言(PDDL)(3)并行数据操作语言(PDML)并行查询操作在分区表和非分区表中仅有微小的不同.
在非分区表,仅当表中的行数大于或等于在编译时被检查的内部门限时,表的全表扫描才被并行化.
相反,在分区表中,仅当相关分区总的大小大于或等于那些相同的门限时(该门限不仅在编译时被检查,而且如有需要,在运行时也进行检查,这是因为查询自身的分区限制),才将该表的全表扫描并行化.
如果在检索与查询需要相应的分区值范围(边界)时,优化器在分区消除时,分区不被跳过,就称为是分区相关的.
使用并行查询,并行度由ROWID范围确定,与表的分区无关.
并行数据定义语言被限制为DDL命令中可以并行化的一个很小的子集:(1)CREATEINDEX(2)CREATETABLEASSELECT(3)ALTERTABLEMOVEPARTITION(4)ALTERTABLESPLITPARTITION(5)ALTERINDEXREBUILDPARTITION除了附加的特定分区的操作,这种类型的并行化在Oracle8中与Oracle7中相同.
并行数据操作语言(PDML)可能有点模糊,但基本上,在Oracle中通常指的是INSERT、UPDATE和DELETE操作,不是SELECT操作.
尽管在Oracle之外的数据库的书本和著作中,首字母缩写DML代表数据操作语言,但是Oracle更愿意认为DML是数据修改语言.
如果认为DML是数据修改语言,而SELECT是查询,在Oracle术语中是指并行查询处理SELECT的并行化,而PDML是处理INSERT、UPDATE和DELETE的并行化.
正如想象的,PDML在性能方面的影响通常很少与PQ一样大,特别是在OLTP和DSS系统中.
但是,有时有一些孤立的处理或在这些应用类型中高度易变的表,这些表的增长和收缩十分迅速.
更进一步,表的这些类型在某些应用中有可能变得十分巨大.
当后面这些条件似乎会在你的组织中出现时,PDML应该与PQ一样对你有益,甚至更好.
和使用并行查询一样,PDML的优点依赖于被访问表的行数、这些表所跨的磁盘驱动器数、服务于这些磁盘的控制器数目和类型、CPU的数量和其他软硬件因素.
例如Oracle使用磁盘到数据文件再到分区的映射来帮助将PDML语句的工作分离和分配到它们的伺服器,同时,与并行查询一样,PDML提供一个失败查询水平.
如同所有真正的面向事务的RDBMS一样,158Oracle8i数据库开发与专业应用如果一个PDML伺服器的失败,所有伺服器都回滚,这样全部PDML语句失败,保证了事务的原子性.
这种操作很像一个本地两阶段提交操作.
用PDML时,UPDATE和DELETE操作要求表被分区,但INSERT.
.
.
SELECT不要求这么做,就和用SELECT和PQ时一样.
没有初始化参数要想启用PDML,必须使用ALTERSESSIONENABLEPARTITIONDML.
但是优化器可能由于其他限制,选择不并行DML.
在启用的PDML会话中的每一条语句必须跟随一条COMMIT或ROLLBACK,一ORA-12830错误:"在执行并行INSERT/UPDATE/DELETE返回后,必须提交或回滚".
另外,如果在一个事务(PL/SQL代码块)中的第一条DML语句没有以并行方式执行,所有随后的语句被顺序执行,而不管提示或缺省表的并行度.
4.
4.
6附加的考虑PDML是在Oracle8中与分区有关的一项主要功能.
除此之外,许多其他特性和功能与这些新的分区能力有关.
分区扩展表名就是一个伴随分区的增强,这种语言的扩展是非标准的(也就是非ANSI),因此不得不使用视图来封装代码,来促进标准化.
下面是一个使用扩展名的例子:SQL>select*fromEMPSpartition(p1);分区增加了另一层对Oracle7锁规划的粒度,以支持Oracle8的分区独立的概念.
分区独立的简单含义是能够完全像对待Oracle7中的表一样对待Oracle8中的分区.
使用这种方法,一个DBA能够维护一个分区而不受影响用户访问其他分区.
本质上,分区级锁作为在表级和行级锁之间的锁级别存在.
总之,分区独立的优点是独立管理恢复和备份这些事,这也能被看作高可用性特性,因为一个分区失败时其他分区仍可被访问.
建议在使用分区时不要更新分区键的列,那将引起行从一个分区移动到另一个分区.
在Oracle8分区中,没有自动的行移植.
如果试图做这样的一个更新,将出现错误ORA-14402:"更新分区键列,将引起分区改变".
用Oracle8时,DBA不得不手动移植行.
现在,假设有一个员工表(EMPS),它是使用员工标识符(EMPLID)进行分区的,并有两个分区P1和P2,P1中的值小于51,P2中有51以及以上的值.
表4-17给出两个更新语句例子,第一条语句成功,但是第二条语句失败,并伴随一个ORA-14402错误,如前面所述.
解决这个问题的一种方法是做一个插入和删除,但是对成批操作这是无效的.
在这种情况下,最好使用前面讨论的分区操作,或卸载和重新装载分区.
表4-17分区更新语句SQL>updateEMPSsetEMPID=672whereEMPID=66;/*Thisworksok,sincethisparticularemployeestaysinpartitionP2*/SQL>updateEMPSsetEMPID=672whereEMPID=33;/*Thiswillnotwork,sinceitwouldcausethisparticularemployeetomovefrompartitionP1toP2.
Hence,itwillgenetateanORA-14402error.
*/SQL>insertintoEMPSpartition(P2)2values(33,.
.
.
);SQL>deletefromEMPS2whereEMPID=67;第4Oracle8数据库介绍159最后一个考虑是新的Oracle8格式与Oracle7是相对的.
在Oracle8中,ROWID被扩展,主要用于调节分区,但是也被应用于调节对象选项.
4.
5面向对象的特性4.
5.
1面向对象的背景面向对象的DBMS(OODBMS),也就是那些非主流型的关系型(RDBMS)的DBMS,是面向对象程序语言(如Actor和SmallTalk)的直接继承.
永久存储的需要是促使DBMS和RDBMS的出现来替代第三代语言(3GL)/基于文件的信息系统的最基本的原因之一,也促使OODBMS的产生来替代面向对象的编程语言信息系统.
很有趣的是,喜好面向对象系统的人通常认为,面向对象系统提供了比关系数据模型的派生物(如实体关系模型)更有力的语义模型,并具有更高的层次.
然而,与此同时,反对面向对象系统的人认为,由于它们关注3GL/基于文件的信息系统,它们的实现和语言要素偶尔会下降到十分低的层次(按C/C++指针方式).
从本质上讲,它们采取导航的或过程化的查询,这也与前关系型系统(如基于COBOL的分层和网络DBMS)十分相似,而在基于SQL的RDBMS系统中的查询大多是描述性的和声明的.
当用任何RDBMS厂商的产品时,为了估计它的面向对象能力,必须考虑几件事情:对面向对象概念和结构的信任;面向对象到关系的映射概念和结构;仿真、完全或混合实现;性能的降低或加强;使用现有RDBMS子系统的能力.
希望RDBMS具有面向对象的接口的一个主要的原因是,这样做面向对象应用的程序就可以与RDBMS中的面向对象部分直接进行通信,这与在程序代码中必须动态地处理对象-关系型映射(分解和重组)相反.
例如考虑嵌入型SQL,这里SQL是基于集合的语言,必须与一个基于记录的主机3GL(如C)交互.
这是不希望的情况,称为阻抗失配,可以通过诸如游标的结构和诸如预编译的软件(如Pro*C)来进行补救.
一个基于面向对象的程序语言的应用与一个RDBMS的交互,情况与此相似.
Oracle8特别地帮助缓解面向对象的开发和RDBMS后端的情况,方式是提供一些强有力的内建的面向对象能力,表现为:关系作为数据类型;继承;集合作为数据类型,包括嵌套;用户定义(可扩展的)数据类型;改进大对象(LOB).
和使用任何OODBMS或对象-关系DBMS(ORDBMS)一样,使用Oracle8时,能够利用面向对象模型的特点.
面向对象模型是比关系型模型更高层次的抽象.
换句话说,能够抽象出事物的模型作为一个整体来比较接近地反映"真实的"世界.
例如,在OODBMS中,可以具有一个称为CAR的复杂对象,它很可能是RDBMS中的几个表,如MAKE、MODEL、ENGINE、PARTS等等.
面向对象模型与关系模型在"自然性"方面的注释是不同的.
用RDBMS时,必须连接在前一次通过规范化分开的部分.
关系设计者知道这种情况,这就是这类事情作为非规范化而存在的原因.
大多数面向对象的主要强度为:建模(业务级抽象);重用性(生命周期的代码重用可以在很大程度上节约成本);复杂性(没有数据类型限制;多媒体数据;嵌套);可扩展性(反映建模的用户定义数据类型);性能.
160Oracle8i数据库开发与专业应用Oracle8通过提供特定的能力和如继承、集合、容器和用户定义数据模型满足了这些需要中的很大一部分.
然而,性能是难以决定的,更多地依赖于整个数据库物理的和逻辑的设计.
但是适当地应用分割并配合实验、迭代测试(基准程序),能够帮助判断是Oracle8使用面向对象,还是只用Oracle8能够更好地满足你特定应用的性能需要.
4.
5.
2面向对象技术1.
对象的定义面向对象技术的一个主要问题是在面向对象团体中总是缺少一个标准定义,也就是什么是对象.
相比之下,关系技术实质上对于什么是关系,在关系团体中从没有任何争论.
Oracle8定义对象作为对象类型的实例,一个对象类型作为基本面向对象模型的组成块通常直接指向真实世界的业务项目.
因此,类似于表中的行,对象是数据,而对象类型是结构,与其他数据结构(例如记录)很相似.
在许多其他面向对象语言和系统中,Oracle对象类型等于对象类.
一个Oracle8对象类型有两部分:属性——基本的数据类型或其他对象类型,有时称为对象类型的结构化部分;方法——组成在对象类型上允许的集合操作的PL/SQL(或C)子程序,有时称为对象类型的行为部分.
2.
多态性和继承在面向对象技术中,其他的重要概念包括继承和多态性.
继承是一个对象包括来自另一个对象类型的属性或方法的能力.
方向是从一般到特殊,正像关系型模型中的子类型.
例如,有一个雇员对象类型和一个经理对象类型(雇员类型的子类型).
所有雇员有名字、地址、社会保险号等等,还有雇佣日期、薪水雇佣比例等等.
所有这些代表一般的或普通的属性,能从雇员对象类型继承到经理对象类型.
这意味着有两件事与效率有关:所有雇员(包括经理)的共同属性和方法只需要存储一次;经理对象类型仅需要存储它自己特有的属性和方法.
因此继承可以基于属性(结构)或方法(行为).
上面所描述的经理对象类型从雇员对象类型中继承属性和方法,称为单继承.
另一种类型的继承称之为多继承.
单继承是子类最多有一个父类的形式,多继承允许一个更一般的模型——网络模型,也就是子类型能够有多个父类型,像在真实世界中的情况一样.
与雇员到经理的单继承对比,考虑也包含官员的多继承方案:经理从雇员和官员中继承属性和方法,从一般到特殊.
多态性像继承性一样可以是结构的或行为的.
考虑一个没有经理对象类型的雇员对象类型,雇员只简单地是一个雇员,而不是经理.
如何从一个雇员类型获得经理类型呢事实上,这是一个旧的程序结构,在不同的编程语言中有不同的术语,在这里是为了全面将它描述为变量记录.
一个变量记录依赖于被输入的记录类型能够包含一些共同(继承)的数据,也能包含一些附加的域.
这种情况对非规范化表是模棱两可的,可能同时包含经理和雇员.
与属性类似,方法是否可见依赖于具体被说明的对象(雇员或经理).
上面所述的是常见的结构多态性,下面说说行为多态性.
在面向对象中,当一种方法被调用时,称为向它发送了一条消息(进行执行).
当向方法发送一条消息时,它可能有不同的执行,取决于它当前属于的对象类型或被影响的实例.
例如,如果调用一个hire方法,它构造(创建)一个新的雇员或经理.
尽管调用的是同一个hire方法,这里实际上有构造一个实例(实例化一个对象)的两种不同实现方法:通过为雇员填入共同雇员属性,或通过为经理填入共同雇员属性和特定的经理属性.
面向对象系统能够通过简单IF/THEN逻辑第4Oracle8数据库介绍161在单个程序内或通过定向化实现这个变化的程序,定向是IF/THEN逻辑加一个对所有可能程序之外的一个必要程序的调用.
多态性也称为重载.
稍后捆绑(运行时捆绑)使多态性在现代语言和系统中成为可能.
在面向对象中,每一个类型总是至少有一种方法——它自身的构造方法.
另外一个重要的概念是对象ID(OID),它表示一个在对象创建以后唯一代表该对象的统一标识符.
这意味着它在所有的,甚至在Oracle之外的面向对象系统和语言中是唯一的.
在Oracle8中产生OID是Oracle公司的一个秘密,但是唯一性好像是以某种方式被链接到CD-ROM介质上.
对那些熟悉本地网络的以太网的人来说,OID应该是唯一的,这就像以太网卡的以太网地址一样,在工厂中被固化.
ID在它自身系统之外也是唯一的概念,与关系模型中的主键和代理这些是不同的.
然而,它在某种程度上像一个分布式数据库中的主键,它们必须在多个系统中是唯一的.
4.
5.
3Oracle8对象选项Oracle8扩展它已有的复杂的多用途的RDBMS如下:(1)对象类型:本质上是记录或类;(2)对象视图:把许多规范化的表放在一起形成一个项目;(3)对象语言:对OracleSQL和PL/SQL语言的扩展;(4)对象API:通过Oracle预编译器(例如Pro*C)支持的对象;(5)对象可移植性:通过对象类型翻译器(OTT),它可以建立Oracle8对象类型到C++类的接口这样的东西.
但是,即使有了这些进步,Oracle8还是不支持多继承、多态性或在对象属性(如引用一致性)上的约束.
Oracle8开放式类型系统(OTS)是一个所有Oracle8对象类型的知识库,也是其他语言系统中的外部对象类型的知识库.
在开放式类型系统中,有一个数据类型层次,作为它的底层的是内建的Oracle8数据类型.
Oracle8还增加了大对象,形式是BLOB、CLOB、NCLOB和BFILE,还增加了VARRY(变量数组)和嵌套表形式的集合类型和REF(引用)形式的对象ID.
另外,用户定义数据类型能够被创建在任何内建的数据类型和已有的用户定义数据类型上,唯一的例外是它们不能被创建在LONG、LONGRAW、ROWID或%TYPE上.
当在Oracle8中创建用户定义的对象类型后,可以将它用于多种用途,包括:(1)作为关系型表中的一列;(2)作为另一个对象类型的一个属性;(3)作为关系型表的对象视图的一部分;(4)作为对象表的基础;(5)作为PL/SQL变量的基础.
用于管理对象类型的扩展OracleSQL包括:CREATETYPE、ALTERTYPE、DROPTYPE和GRANT/REVOKETYPE.
和表的列一样,属性在一个对象类型中必须唯一,但是在其他对象类型中该属性名可以被再用.
与表中的列一样,总能在一个对象中通过它的名字访问其属性.
没有能力进行位置或偏移量访问.
任何给定的对象类型可以是简单的、符合的或自我引用的.
简单对象类型就是它自身;符合对象类型至少包括一个其他对象类型;自我引用对象类型至少包含162Oracle8i数据库开发与专业应用一个引用对象类型自身的属性.
表4-18和表4-19给出了两个创建和使用对象类型的例子.
表4-18创建一个雇员对象类型SQL>createtypeemployee_typeasobject(1ssnnumber(9),2namevarchar2(35),3addressvarchar2(70),4resumeCLOB);表4-19使用一个对象类型作为关系型表中的一列SQL>createtablemanager_candidates(1positionvarchar2(40),2vacancyCLOB,3employeeemployee_type);SQL>insertintomanager_candidatesvalues(1'TechnicalManager',empty_clob(),2employee_type(123456789,'JohnDoe','123MapleSt:3Metropolis:NY:12762',empty_clob()));SQL>selectmc.
employee.
namefrommanager_candidatesmc1wheremc.
employee.
ssn=123456789;注意必须使用一个别名和点符号来查询一个表中的对象属性值.
同时还要注意当进行插入时,为命名为employee_type的对象类型调用命名为employ_type的构造器方法.
所有的构造器具有与它们相关的对象类型相同的名字.
下面的语句使用一个对象类型创建一个对象表:SQL>createtableemployeeofemployee_type;创建这个表也为一个对象实例(行)创建一个包含对象ID(OID或REF)的列.
这与创建一个关系型表,这个表在一个列中具有一个对象类型形成对照.
在关系表中的对象类型没有OID.
4.
5.
4REF属性在Oracle8对象世界中的关系与在Oracle关系世界中的关系实际没有什么不同,都是指明对象之间如何相关.
Oracle8仅支持一对一单向的关系,它可能足够也可能不够将业务模型化.
当声明一个对象类型中的属性是REF时,它代表对其他一些对象类型的引用,这是个最基本的关系.
REF代表了一个对象的关系.
一个REF本质上是一个指针.
可以限制一个REF实际指引的范围,在SQL3中包括范围的概念.
SQL3是ANSISQL标准的最新版本,它包含一些面向对象的特性.
像RMT(关系模型2)中的代理键一样,Oracle8中的对象引用(REF)是一个系统产生的值,在所有对象中(任何地方)是唯一的,指向一些永久不变的对象.
一个REF实际上引用一个对象——对象表中的一行(实例),而不是真正的对象类型.
一个给定的REF是对象OID+对象的表ID+对象表的数据库ID的组合.
表4-20显示如何创建一个包含引用已创建的employee_type的REF属性的对象类型,并创建基于这一个对象类型的对象表,再插入一行(实例化一个对象).
第4Oracle8数据库介绍163表4-20创建一个包含引用REF属性的对象类型SQL>createtypeinsured_employee_typeasobject(1control_numbernumber(9),2contractCLOB,3employee_refrefemployee_type);SQL>createtableinsured_employee(1ofinsured_employee_type2scopefor(employee_ref)isemployee);SQL>insertintoinsured_employee1selectcontrol_sequence.
nextval,2empty_clob(),3ref(e)fromemployeee4wheree.
ssn=123456789;4.
5.
5方法一个对象类型可以有零个或多个成员方法.
一个成员方法是一个能够操作任何对象类型(不仅仅是定义它的那个类型)的数据(属性)的子程序.
当然,方法简单地说就是PL/SQL过程或函数.
正像使用任何PL/SQL封装的子程序一样,应为每个方法创建一个接口(声明)和一个实现(体).
当访问一个方法时,应使用点表示法(对象.
方法).
表4-21给出在一个对象类型内创建方法的例子,跟随其后的是该方法的一些PL/SQL代码.
表4-21在一个对象内创建方法SQL>createtypeauto_typeasobject(1vinvarchar2(80),2makevarchar2(30),3modelvarchar2(40),4memberfunctiongetcost5returnnumber,6pragmarestrict_references7(getcost,WNPS));SQL>createtypebodyauto_type(1memberfunctiongetcost2returnnumberis3begin4return(cost);5end;);/*createobjecttableandinsertsomedata*/SQL>declare1aauto_type;2cnumber;3begin4selectvalue(a)5intoa6fromautoa7wherea.
vin=1VWF637FB9093871AF21;8c:=a.
getcost();9/*dosomethingwithc*/10end;164Oracle8i数据库开发与专业应用注意函数使用pragma设置为WNPS.
WNPS代表"写无包状态",它的意思是函数被设置为不能修改自身内的任何参数(否则产生负面影响).
为了比较或排序对象类型,可以定义一个MAP或一个ORDER函数来比较两个对象.
当使用这些比较函数时,指定对象分类语法,用于条件和分类.
4.
5.
6集合、变量数组和嵌套表集合是排序的或未排序的一组事物,变量数组是排序的,而嵌套表是未排序的.
嵌套表是在最新的ANSI标准中,但变量数组是非标准的.
任何主从(一对多)关系能帮助对比这两种类型的集合.
用某种顺序列出的主表项目能够使用变量数组(VARRY),对每一个主表行的每行项目细节可以在变量数组中使用嵌套表.
并行查询、并行DML、复制和分布数据库函数都不支持集合.
和许多数组一样,Oracle8变量数组有一个隐式的顺序.
每一个元素在数组中有一个从数组起始位置开始的偏移量,能够通过偏移量直接访问.
变量数组是按行存储的(在表的行中),直到存储单元超过4KB(该点被存储在数据库之外).
和许多数组一样,每一个变量数组有数量和限制.
数量是当前有多少元素存储在变量数组中,而限制是能够存储在变量数组中的最大元素数.
可以通过在PL/SQL和3GL中使用下标访问单个元素,但是不能在简单的SQL中访问它们.
嵌套表能很好地适合主从(一对多)关系.
嵌套表在Oracle8中实际上是用户定义类型或表类型,能够在一个表中作为一列使用,在对象类型中作为属性,或者作为PL/SQL变量.
嵌套表被使用STOREAS语句存储在主表之外的存储表中.
嵌套表有一些优点和缺点.
优点包括能够对它们进行索引(与对象表相反)和不需要连接(与簇类似).
缺点是,尽管有级联删除形式(主行删除时将删除所有从属行),但是引用约束是不可能的.
表4-22中给出了一个创建和使用变量数组和嵌套表的例子.
表4-22创建和使用变量数组和嵌套表/*VARRY*/SQL>createtypetax_typeasobject(1yeardate,2taxes_paidnumber);SQL>createtypetax_array_typeasVARRAY(3)1oftax_type;SQL>createtypeclient_typeasobject(1cidnumber,2namevarchar2(35),3addressvarchar2(80),4taxestax_array_type);SQL>createtableclientsofclients_type;/*nestedTABLE*/SQL>createtypechild_typeasobject(1child_idnumber,第4Oracle8数据库介绍165(续)2child_namevarchar2(35));SQL>createtypechild_nest_typeasTABLE1ofchild_type;SQL>createtableparent(1parent_idnumber,2parent_namevarchar2(35),3parent_addressvarchar2(80),4childrenchild_nest_type)5NESTEDTABLEchildrenstoreaschild_nest_store;总的来说,当在程序中使用数组时使用VARRY集合;当在程序中使用一个记录(在一个记录里)时使用嵌套表集合.
对这些程序数据结构来说,这些Oracle8集合结构是模糊的.
4.
5.
7对象视图关系表的对象视图提供给用户和开发者许多好处,如建立面向对象的前端应用到关系的后端存储之间的联系、协调多个面向对象的前端模式为一个关系型的后端模型和并发开发新的面向对象的应用和当前的关系型应用.
后面这一项是对象视图方便地移植到面向对象技术的一种说法.
对于用户,整个系统从表面上看似乎是基于面向对象的,但是实际上数据是关系型的.
然而,这是透明的.
当然,一般地说因为对象视图是视图的特例,它们有与一般视图相同的优点:为不同用户和不同目的提供相同数据的不同视图.
正确地创建对象视图的一般顺序为:(1)创建表;(2)创建对象类型;(3)创建对象视图;(4)创建INSTEADOF触发器.
INSTEADOF触发器可以插入、更新或删除对象视图所基于的关系型表,而不是直接试图修改对象视图.
表4-23给出了一个创建对象视图的例子.
表4-23创建对象视图SQL>createtabledepts(1deptidnumber,2deptbudgetnumber);SQL>createtablebranches(1branchidnumber,2branchbudgetnumber,3deptidnumber);SQL>createtypefunding_typeasobject(1deptidnumber,2deptbudgetnumber,3branchidnumber,4branchbudgetnumber);166Oracle8i数据库开发与专业应用(续)SQL>createorreplaceviewfunding_objvas1selectfunding_type2(deptid,deptbudget,branchidbranchbudget)funding,3fromdeptsd,branchesb4whered.
deptid=b.
deptid;SQL>createtoreplacetriggerfunding_trigINSTEADOF2begin3insertintodeptsvalues4(:new.
funding.
deptid,:new.
funding.
deptbudget);5insertintobranchesvalues6(:new.
funding.
branchid,:new.
funding.
branchbudget,7:new.
funding.
deptid);8end;9/4.
6Oracle8i概述OracleRDBMS的最新版本Oracle8i是在企业内和因特上开发的、部署和管理应用高移动性和可伸缩性的数据库.
它被设计成用来支持很大和大容量的事物处理和数据仓库应用.
Oracle8i最主要的新特性是在数据库中包括Java和因特网能力.
与数据库服务器集成的是称为OracleJSever的Java虚拟机(JVM),因此开发者现在能够用Java、PL/SQL、C或OCI创建应用.
它使开发者能够用Java编写存储过程、数据库函数或触发器.
因为Java是平台独立的,因此用它开发的应用能够很容易地部署在任何支持Java的服务器中,而无需重写和再编译.
Oracle8i的另一个主要特性是因特网文件系统(iFS),它使数据库能存储和管理关系和非关系数据文件.
Oracle8i还包括能够管理和访问多媒体(视频、音频、图像、文本、空间)的OracleinterMedia.
Oracle8i还包括OracleWebDB.
这个Web开发环境使开发者能建立使用标准的Web浏览器和Oracle8i数据库的动态的、数据驱动的Web网站.
4.
6.
1Oracle8i中的Java能力图4-7说明了Java虚拟机结构.
在数据库中有Java使开发和部署internet/intranet应用变得更容易、更快、代价更少和更高效.
Java程序语言使开发者能利用容易获得的大量开发工具,与C或C++这样的语言相比,Java代码在数据库服务器中执行是安全的,因为它不能操作指向内存位置的指针.
Oracle8iJava虚拟机的内存管理器自动分配和释放内存,因此它使在数据库中内存越界所引起的数据损坏问题减至最小.
在Oracle8i之前,没有企业级的用于开发大规模应用的Java服务器集成到RDBMS中.
许多应用服务器和数据库服务器厂商使用来自JavaSoft(JDK)的Java虚拟机来运行服务器端Java应用.
JavaSoft中Java虚拟机被开发作为客户端虚拟机运行在单用户环境下,它不提供在企业范围内应用需要的高可伸缩性.
Oracle的Java虚拟机与数据库有很高的集成度来满足关键任务应用的需要.
Oracle8iJava虚拟机包括集成的Java数据库连接(JDBC)、驱动器、第4Oracle8数据库介绍167图4-7Oracle8iJava虚拟机体系机构SQL翻译器,并提供如下特性:高性能、可伸缩性、高的可用性、管理能力和符合标准以及Java运行支持.
Java虚拟机符合JDK1.
1.
6特性并支持所有标准的JDK库.
Java虚拟机有足够的内存管理能力,对于一般的Java会话减少用户内存需求到80KB~150KB之间,它与数据库内核运行在同一进程和地址空间,共享大量内存堆并为优化性能进行直接访问数据库的缓冲区.
因为Java虚拟机从数据库的SGA中分配共享内存池,所以为适应Java虚拟机,应设置较大的SGA.
能够扩展到几万个并行的Oracle多线程服务器结构(MTS,从Oracle7版本开始提供)是Java被集成到服务器的地方.
MTS基于一种结构系,即数据库监听器路由用户连接到一组与处理数据库连接的服务器进程交互的调度程序.
Oracle8i的目的是在因特网应用中支持大量并行用户.
Java虚拟机被设计成更快速、更安全和更可靠地运行Java应用.
由于Java虚拟机被集成到数据库,它可跨所有Oracle支持的硬件和操作系统平台.
因此实现Java的承诺:"一旦编写,任何地方皆可运行".
1.
Java虚拟机的主要部分(1)库管理器提供方便地装载、存储和管理在数据库中的Java程序.
用户导出或导入Java对象能用三种形式:源、二进制和资源(或归档).
(2)类装载器定位、装载和初始化本地DBMS存储的Java类以响应来自Java虚拟机的请求.
它读取.
class文件信息,产生Java虚拟机运行Java代码所需要的所有数据结构.
(3)内存管理器负责自动地管理Java虚拟机的内存堆和有效地分配和收集对象内存.
内存被分配为称为对象内存的标准大块.
每一个标准对象内存是作为单一单元被分配和收集的一个内存池,在每个单元内所有对象共享同一生命时间和格式.
(4)Java至C编译器(NCOMP)是一个嵌入Java虚拟机的本地编译器.
它的解释标准Java.
class二进制文件,产生能被编译成C可执行文件的特殊C程序.
(5)Java存储过程和触发器能够被Java本地编译器编译并存储在数据库中作为与PL/SQL存储过程类似的数据库对象.
用Java写的过程能够调用用PL/SQL写的过程,反168Oracle8i数据库开发与专业应用之,用PL/SQL写的过程也能调用用Java写的过程.
因为存储过程在数据库中执行,所以它们使在应用和数据库之间的网络业务量最小化.
现在可以在传统使用PL/SQL的地方使用Java.
整个Java存储结构如图4-8所示.
图4-8在Oracle8i中Java存储过程2.
编写Java存储过程编写Java存储过程要求的步骤如下:(1)编写的Java代码首先,编写和测试Java程序,然后把它装入到Oracle8iJVM中并解决所有引用.
装入到数据库的Java程序被存储在数据库概要中做为库单元,它与被存储的PL/SQL程序单元类似.
下面是一个称为student.
java的简单Java程序,它在计算机屏幕上打印一行"StudentList":publicclassstudeng{publicstaticvoidmain(stringargs[]){system.
out.
print("StuentList");}}一旦编译并运行这个简单例子,Java环境就正确地建立了.
(2)装载和解决代码可以用两种方法装入Java源代码、二进制或资源文件.
一种方法是在SQL*Plus中新的DDL命令:"CREATEJAVA{SOURCE|CLASS|RESOURCE}"使用这个语句能从一个二进制文件或通过使用在数据库中的LOB列导入Java代码.
第二种方法是借助Oracle8i提供的LOADJAVA工具.
这个工具自动装入Java到数据库中.
它把Java文件装入到数据库中名叫create$java$lob$stable表中,然后运行SQL"CREATEJAVA.
.
.
"命令.
还有用于从数据单元中删除Java程序的DROPJAVA工具.
当指定解决选择时,LOADJAVA使用SQLALTERJAVACLASS.
.
.
RESOLVE语句来解决现在被装载的Java类外部引用,否则ALTERJAVA语句在运行时隐含执行.
第4Oracle8数据库介绍169下面是一个用于解决一个Java类的语法例子.
它装入exam.
jar文件到用户SCOTT的概要中,然后解决外部引用:loadjava-userscott/tiger-resolveexam.
jarloadjava也能列出一项或多项解决项目,每项由名字说明和概要说明组成,它的查找按列表顺序.
下面是一个使用LAODJAVA工具用RESOLVE特性来装载student.
class文件到在数据库MYSID中的用户PETER概要中的例子.
它在概要中查找以home.
java开头的类名,然后在PUBLIC概要中查找:loadjava-userpeter/page@tysons1:5521:mysid-reslover'(("/home/java/*"PETER)(*PUBLIC))'student.
class下面是在操作系统级使用二进制文件来装载Java代码的例子:/*Createadirectoryontheserver'sfilesystem.
*/SQL>CREATEDIRECTORYb_dir2as'/home/user/oracle8/student';Statementprocessed.
/*Thenloadthejavaclassfileusingthe"CREATEJAVACLASS.
.
.
"command.
*/SQL>CREATEORREPLACEJAVACLASS2USINGBFILE(b_dir,'student.
class');Statementprocessed.
(3)发布代码在Java程序被装入数据库之后,代码需要被发布.
这是用SQL注册程序来实现的,但仅有顶层Java项目点需要被注册.
顶层Java项目点是Java类或用SQL初始化调用SQL的方法.
Java代码通过使用调用说明被发布.
一个PL/SQL子程序被说明为一个Java方法实现.
下面是一个对类employee.
emp的app_bonusJava方法的调用说明的例子.
SQL>CREATEORREPLACEPROCEDUREA_BONUS(C_SALINNUMBER,BONUSNUMBER)2>ASLANGUAGEJAVA3>NAME'employee.
emp.
appr_bonus(float,float,float)';4>/5>Statementprocessed.
(4)运行代码最后一步通过SQL调用运行Java代码.
实现这一步有两种方法.
一种方法是使用CALL语句:SQL>VARIABLECSALNUMBERSQL>VARIABLEBONUSNUMBERSQL>EXECUTE:CSAL:=20000;Statmentprocessed.
SQL>CALLA_BONUS(:CSAL,:BONUS);Statementprocessed.
170Oracle8i数据库开发与专业应用另一种方法是从SQL查询中调用Java存储函数:CALL-specfors_gradejavamethodofclassstudent.
stud-SQL>CREATEORREPLACEFUNCTIONSGRADE(GRADINNUMBER)RETURNVARCHAR22>ASLANGUAGEJAVA3>NAME'student.
stud.
s_grade(float)returnjava.
lang.
String';4>/Statementprocessed.
以下例子是使用SQLDML语句来调用Java存储函数SGRADE:SQL>SELECTSNAME,GRAD,SGRADE(GRAD)FROMSTUD;PL/SQL能够直接通过简单包含PL/SQL程序调用说明来调用Java存储过程.
下面是PL/SQL直接调用Java存储过程的例子:DECLAREsalnumber;bonusnumber;BEGIN.
.
.
A_BONUS(sal,bonus);.
.
.
END;在Java中,远端方法请求(RMI)调用中简单的是特定的远端过程调用(RPC).
Oracle8i使用RMI作为在因特网内部ORB协议(IIOP)之上的传输协议.
正如预期的,这个已存在的技术"式样翻新"是一个面向对象和网络编程的扩展.
3.
Oracle8iJava预处理器(SQLJ)SQLJ是一个新的编程语法,它是用于JDBC的Oracle预编译器,它可以被认为是Pro*Java.
它使开发者可以在Java程序中嵌入SQL语句,与Oracle的其他预编译器(例如Pro*C)类似.
与既支持动态又支持静态的SQL的Pro*C不同,SQLJ只支持静态SQL.
Oracle与其他软件商共同开发SQLJ,这些合作者包括IBM、Tandem(现在的Compaq)和Sun,在1998年12月SQLJ被采用为ANSI标准.
它被设计为独立于目标数据库使用,因此如果其他厂家的数据库支持SQLJ,那么在其中使用OracleSQLJ存储过程将是可能的.
用嵌入式SQL语句写一个Java程序,然后用SQLJ转化器处理它,SQLJ运行时调用替代SQL语句.
然后任何Java编译器能够被用来编译产生的Java程序.
SQLJ由一个转换器和一个运行组件组成.
转化器检查嵌入式SQL的语法和标点符号,产生一个Java源文件以及一个或多个SQLJ环境资源文件.
SQLJ资源文件包含关于SQL操作以及被访问数据的类型和模式的详细信息.
然后,SQLJ自动地调用Java编译器,从.
Java文件中产生.
class文件.
SQLJ还自动调用定制器以适应连接的数据库的资源文件.
在缺省的情况下,Oracle定制器被用于增加Oracel特定的扩展特性的支持.
SQLJ运行库环境有一个SQLJ运行库,这个库使Java调用JDBC驱动器来连接正确数据库.
图4-9说明了SQLJ开发过程.
开发SQLJ应用有四个基本步骤:第4Oracle8数据库介绍171(1)使用SQLJ转换器转换SQLJ代码,用产生带有SQLJ的运行时调用的Java源文件.
(2)使用Java编译器编译Java源文件.
(3)定制Java.
class文件.
(4)使用SQLJ运行库应用.
图4-9SQLJ开发过程这里有一个SQLJ程序中嵌入一个SQLselect语句的例子.
符号#sql放在SQL语句前,跟随内容包含在大括号内部:#sql{selectdeptnointo:deptnofromempwhereempid=:emp};运行SQLJ程序的唯一要求是一台Java虚拟机,这个Java虚拟机上必须具备SQLJ运行库、一个JDBC驱动器和程序.
SQLJ比JDBC强,因为它在转换时检查SQL的语法和标点符号,而不是在运行时进行.
不必在SQLJ或JDBC之间做出选择,这些API是JDBC的预处理器,它可以被认为是PRO*Java.
它使开发者可以把SQL语句嵌入到Java内部.
下面是SQLJ和JDBC对相同的SELECT语句的程序片段.
SQLJ代码比较短,因为它使用主变量来将参数传递到SQL语句,而JDBC使用分开的语句绑定每一个参数并获得每一个结果:###SQLJjava.
sql.
DATEa;intb;stringc;.
.
.
#sql{SELECTcol1INTO:aFROMEMPWHEREcol2=:bandcol3=:c};###JDBCjava.
sql.
DATEa;intb;stringc;PreparedStatementx=connection.
prepareStatement("SELECTcol1FROMEMPWHEREcol2=andcol3=");x.
setint(1,b);x.
setstring(2,c);ResultSety=x.
executeQuery();y.
next();a=y.
getDate(1);y.
close();x.
close();4.
企业级JavaBeans支持企业级JavaBeans基本上是实现一系列用于事务处理功能的预定义Java接口的分布的172Oracle8i数据库开发与专业应用Java组件.
它们使开发者能够设计并把应用程序封装在组件内,这个组件可以和其他开发者编写的部件装配在一起.
基于组件的程序已经变得更加流行,因为它可再用应用代码,不同厂家的应用容易装配,布置灵活.
更多的组织正在为新的应用使用基于组件的开发,这是由于传统的应用不能再用它们的代码.
优点包括更好的设计,代码再用,更容易维护和在多层的环境中更容易跨层布置.
JavaBeans已经正在被广泛用于装配到基于GUI的应用,但主要作为客户端应用.
不同于客户端组件,服务器端的组件(如EJB)一般是事务性的,它们封装业务逻辑并需要运行在服务器环境中.
Oracle为基于组件的分布计算选择EJB作为它们的结构.
当前服务器端部件有三种模型:EJB、CORBA和DCOM.
由JavaSoft创建的JavaBeans特性将Java扩展到支持跨平台对象技术.
分布式组件对象模型(DCOM)是用于建立在桌面上跨网络互操作的组件的Microsoft组件模型.
DCOM是COM的扩展.
COM作为Windows操作系统的一部分已经许多年了,有了它作为基础结构,OLE和ActiveX才成为可能.
通用对象请求代理结构(CORBA)3.
0是最新特性,在1999年12月由对象管理组发布(OMG).
这个模型指定一个传输机制——因特网Inter-ORB协议(IIOP),它允许在不同硬件上运行的不同操作系统互操作.
它也指定用于指定接口到对象的接口定义语言(IDL).
EJB在一个容器内执行,容器提供这些部件在其中运行的操作系统进程或线程.
容器类型有Web服务器、事务处理(TP)监控器或数据库系统等.
开发和布置企业JavaBeans包括如下步骤:一个开发者需要为客户应用定义四个项目,以能够请求包含业务逻辑的块(bean)方法.
(1)定义远端接口远端接口列出所有方法或客户能调用的公共接口块,下面是一个用于Stock块的远端接口的例子:publicinterfaceStockextendsjavax.
ejb.
EJBObject{floatgetPrice()throwsjavax.
rmi.
RemoteException;voidbuy(floatamount)throwsjava.
rmi.
RemoteException;}(2)定义主接口主接口作为使客户能够创建块实例的机制,以下是Stock块的主接口:publicinterfaceStockHomeextendsjavax.
ejb.
EJBHOME{Stockcreate()throwsjava.
rmi.
RemoteException,javax.
ejb.
CreateException;}(3)定义块块自身是标准的实现业务逻辑的Java代码,下面是一个块自身的例子:publicclassStockBeanimplementsjavax.
ejb.
SessionBean{publicfloatgetPrice(){ADDANYBUSINESSLOGICHERE.
.
.
}第4Oracle8数据库介绍173publicvoidbuy(floatamount){ADDANYBUSINESSLOGICHERE.
.
.
}(4)定义接口布置描述器它将所有块组件连接在一起.
其语法很像Java类,用SessionBean语句开始.
下面是为Stock块创建一个布置描述器的例子:SessionBeanStockBean{BeanHomeName="bn=myStock";AttributeRemoteInterfaceClassName=Stock;AttributeHomeInterfaceClassName=StockHome;.
.
.
}这些步骤完成以后,需要编译和封装Java代码.
用如下语句编译EJB、它的远端接口和对Java类的主接口:%javacStockBean.
javaStock.
javaStockHome.
java.
.
.
然后,用下列语句在EJB包(一个Java归档或JAR文件)中封装类文件:%jarofStock.
jar*.
class接下来,用Oracle提供的CREATEEJB工具增加块的布置描述器:%createejbStock.
jar-descStock.
dsc最后,在Oracle8i服务器上使用Oracle提供的DEPLOYEJB工具布置EJB.
下面是用用户SCOTT概要布置EJB和创建一个jar文件的例子:%deployejb-uscott-ppasswd-s-genStockclient.
jarStock.
jar在成功地布置EJB之后,可以从一个客户端应用激活它.
5.
Java和CORBACORBA(通用对象请求代理结构)是使用不同语言编写的分布式程序可在网络(包括因特网)上进行通信的面向对象的协议.
CORBA由对象管理组(OMG)定为一个基于标准的分布式组件模型.
它是建立和布置跨平台管理可互操作的分布式对象应用的标准.
CORBA2.
0对象使用OMG的InternetInter_ORB(IIOP)协议通信.
IIOP是在两个或多个运行在因特网、intranet和企业计算环境中分布式对象之间进行通信的另一个OMG标准.
用不同语言编写和运行在不同平台上的CORBA组件能够通信和互操作.
因此,客户和服务器代码能够用任何语言编写并被编译为本地机器代码.
Oracle8i使用Java作为它的CORBA实现语言.
Oracle8i集成基于Java的CORBA2.
0对象请求代理(ORB),它使用户可以利用IIOP调入调出数据库.
这个ORB基于来自InprisesVisiBrokerforJava的代码.
Oracle8i带有一整套用于开发CORBA应用的工具,使用这些工具能编译IDL说明,或装载Java源文件或类到数据库中.
6.
Oracle的Java开发工具JDeveloperJDeveloper2.
0是一个基于Windows的Java编程工具,它带有集成的项目导航、一个174Oracle8i数据库开发与专业应用代码编辑器、一个程序调试器和一个编译器.
SQL转换器和调试器也是JDeveloper中的嵌入部分.
JDeveloper被设计供开发者建立多层Java应用.
开发者创建、调试并布置Java存储过程、企业级JavaBeans、SQLJ和CORBA对象以及HTMLWeb应用.
项目导航器使开发者能在一个会话的不同层中管理多个项目.
有许多代码产生向导来帮助快速开发应用.
企业级JavaBeans向导能自动创建新的EJB.
在Servlet向导和Java服务器页(JSP)向导帮助下,Servlet和JSP能够很容易产生.
数据格式向导指导创建单表或主从格式.
开发者能使用PL/SQL到Java向导来从被选择的存储过程产生Java类定义.
几个JDBC驱动器随JDeveloper被提供,用于访问其他数据库,尽管它不是与Oracle集成最紧密的.
4.
6.
2因特网文件系统(iFS)现在用户能使用新的因特网文件系统将Web页、文献、扩展页、字处理文件、图像和其他传统文件存储在数据库内.
它表面上作为另一个文件系统并能够像任何其他网络目录一样被访问.
iFS把它的内容组织到文件夹里,它们呈现给客户任何文件夹或目录应用的方法.
存储在iFS中的文件可得到Oracle数据库提供的所有可靠性和安全性,这是与其他文件夹或目录不同的.
系统管理员的工作比较容易,因为他们仅需维护、管理、备份和装载单个系统而不是几个系统.
除了在数据库中提供比较容易的文件存储,iFS还提供关系和非关系数据的完整性.
用户能用多种协议访问iFS,对它们的数据提供广泛的访问.
被授权用户能查找和查看他们存储在iFS中的任何文件,他们可以从任何计算机上通过标准Web浏览器、MicrosoftWindowsExplorer、FTP客户或email客户进行上述操作.
iFS使用Java编写,作为特殊的解释器和翻译器.
iFS使用XML来解析和翻译文件,XML是下一代因特网标识语言.
它使数据库能使用文件过滤器将已知的文件类型的内容转换为XML文件.
XML能够存储在数据库表中.
当被客户请求时,翻译转换存储的XML格式到文件格式(HTML、XML或初始化文件格式).
用户通过WindowsExplorer用拖曳方法能够很容易地移动文件进出iFS.
在iFS内双击它们能够直接编辑并启动适当的应用.
当增加或更新一个文件时,iFS使用ConText技术来创建一个基于内容和文件的外部属性(作者、题目、日期等)的关键字索引.
随后,iFS能够使用预构造的索引快速完成查找.
iFS的关键特性包括如下:(1)高级查找:文件自动按内容和文件属性进行索引以提供关系查询和基于ConText的查询.
(2)检入、检出(CICO):当检出时文献被锁存,直到返回检入.
(3)访问控制列表(ACL):基于ACL模型的安全和特性.
(4)版本化:使用多版本文献.
(5)改变通知:email通知可以在文件的插入、更新或删除时获得.
(6)自动过期截止:文件在经过一定期限后被清除.
(7)XML支持:它通过文献解析和翻译获得.
(8)广泛访问:它被通过SMB、HTTP、FTP、SMTP、IMTP和POPS协议提供.
(9)Java、CORBA、PL/SQL编程API:用于编写基于iFS的应用.
第4Oracle8数据库介绍1754.
6.
3OracleinterMediaOracleinterMedia包含五个管理块来处理数据库内的多媒体.
建立在OracleConText技术上的OracleinterMedia文本,使用户可以使用高级查询和自然语言查询搜索文本.
OracleinterMediaImage管理二维静态、数字图像并支持基本的操作函数,如缩放和剪修.
因为它支持多数桌面发布图像文件格式(TIFF、JPG、BMP、PCX、TRAGA、GIF、PICT、CALSRaster、Flashpix、SUN和RPIX),不是图像文件格式专家的用户也能够使用OracleinterMediaImage存储和获得图像.
OracleinterMediaVideo和interMediaAudio能够从不同源(例如,OracleVideoSever、Oracle8i和Web站),导入基于浏览器的视频和音频.
如下工业标准的视频和音频格式被interMedia支持:AIF、AUFF、AIFF-C、AVI、WAV、Quicktime、MPEG和RealNetworks.
应用可以像对传统关系数据一样查询并获得多媒体数据.
OracleinterMediaLocator处理定位查询,例如查找存储、分布点和基于给定空间数据的事件(例如某一地址的位置或距离).
因为interMedia完全集成在Oracle8i中,开发者通过SQL调用而不是专用接口,具有高级文本查找能力.
OracleinterMediaText使用文本索引.
文本索引能够在几乎所有数据库的任意列或者对象上创建来完成查找.
文本查找利用在数据库内的索引执行并返回一个匹配文档列表.
尽管被interMedia查找的文献能够存储在文件系统或任何URL地址的Web上,但数据库存储和管理所有文本索引.
interMedia能够用单个SQL命令处理混合查询(数据库中的全文或结构化数据).
例如,能够查找包含"Internet"的文档并结合存储数据中的其他信息(作者、日期或文件类型).
SQLCONTAINS函数使用户能从任何支持SQL或PL/SQL的工具或环境中运行文本查找查询.
interMedia提供全文搜索能力,它包括精确单词或短语查找、布尔特性、模糊查询、通配符、大小写敏感和部分查找.
它通过使用大约50万个单词的主题内容识别文档能力.
还有根据主题查找文档,这可通过使用优化组合全文、基于语言和基于主题技术来进行.
下面的例子将对bdate列进行查找.
然后结果与CONTAINS函数合并,这个函数搜索包括"Internet"字并和浏览器有关的文档的文本索引:SELECTauthor,isbn,bdatefrombooksWHEREbdate>'01-MAR-1999'ANDCONTAINS(btext,'InternetANDABOUT(Browser)')>0;OracleinterMedia使用与Java或C++类似的对象数据类型,称之为ORDAudio、ORDImage和ORDVideo来描述声音、图像和视频数据.
这些数据类型的一个实例由诸如元数据、多媒体数据和方法等属性组成.
元数据是关于数据的信息,多媒体数据是实际的声音、图像和音频,方法是能够在对象上执行的过程(例如store、deliver和compress).
多媒体数据能够在数据库中作为BLOB类型保存,或者在外部保存并能够很容易地导入到数据库中.
多媒体数据能够存储在其他源中,如BFILE(大对象的操作系统)、基于HTTP服务器的URL、特定的媒体服务器(例如OracleVideoServer)或用户定义的源.
这些数据类型的元数据和方法总是在数据库中进行存储和管理.
interMedia使媒体数据能通过标准查询或关系数据(例如学生姓名)和对象的元数据(例如学生照片)来定位.
当定位后,媒体数据能够通过ORDAudio、ORDImage和ORDVideo数据类型,像其他关系数据一样使176Oracle8i数据库开发与专业应用用SQL对它进行访问.
OracleinterMediaLocator支持用于定位应用和近似查询的连机地理位置编码功能.
使用Oracle8i空间组件创建它.
它在Oracle8i数据库中支持地理编码、存储和地理编码数据查询.
地理编码使用点代表地址和位置信息(例如,邮政编码).
和第三方地理编码和绘图工具相结合,interMedia能够完成地理编码数据的距离查询.
在数据被地理编码后,interMedia在应用中能计算距离和图形化表述它的位置.
例如,能查询数据库来定位距离工作点最近的加油站.
4.
6.
4OracleWebDBOracleWebDB提供包括HTML服务器的一个完整的开发环境,因此它能处理HTTP请求和服务Web页.
不需要在每个用户的机器上安装软件,也不需要使用FTP进行远端文件管理,或者进行复杂的软件升级.
开发和布置应用的客户软件时,唯一需要的是Web浏览器(NetscapeNavigator3.
2或更新的,或者MicrosoftInternetExplorer4.
0或更新的).
WebDB被设计成方便使用、方便访问和方便管理.
它是完全包含在Oracle数据库(版本7.
3.
3或更新的)PL/SQL过程的集合.
它也包括作为Web服务器和PL/SQL到数据库的接口的轻量监听器.
WebDB将全套基于浏览器的用于开发Web的HTML工具与HTML接口相结合.
通过使用指导用户经过创建组件(也就是表格、报告、图表、菜单、日历和分层)的整个过程的简单向导,可以实现快速开发.
向导可以替你写PL/SQL代码,也可以绕过向导自己编写代码.
当开发者创建一个组件时,它被赋予一个URL.
用WebDB进行布置与增加URL到HTML文本一样容易.
在WebDB中包含所有管理和构造数据库的工具.
管理员能够从浏览器管理授权和监听器设置或监控端用户和数据库活动.
通过Web浏览器可以创建、查看、编辑和拖动任何数据库对象(表、分区、重做日志等).
WebDB有高级性能追踪能力,这有助于解决性能问题.
能够监控用户因素包括:响应时间、按组件名称的请求、按天和小时的请求、按浏览器类型的请求和按IP地址的请求.
使用WebDB创建的Web站点被分成叫做角(corner)的几个部分.
角包含与特定主题相关的条目.
站点管理员为角指定负责管理该区域的拥有者.
角的拥有者能将对它们的角的内容进行不同类型访问(例如增加、编辑和删除)的特权授予其他用户.
内容的作者能够更新Web站点的角,只需点击界面而无需任何其他软件.
当维护集中控制的Web站点时,它分散内容的管理.
4.
6.
5Oracle8i的可用性和可恢复性Oracle8i的高级特性和能力提供随时可获得的增强,包括并行服务器的改进、一个新的快速启动的失败恢复、连机备份、恢复和透明的ApplicationFailover.
Oracle并行服务器使多个Oracle实例能运行在一个簇的节点上,以并行访问单一数据库.
这种共享访问帮助删除任何单个失败点,因此一个系统中一个节点毁坏,其他节点能够继续工作.
在Oracle8i中,并行服务器通过使用缓存熔合聚簇结构体系和簇负载平衡来支持成千个用户.
缓存熔合使用专用高速互连直接在节点间为虚拟无限制规模传递数据.
这个技术使在簇中一个节点缓冲区可直接向其他节点的缓存发送数据块,因此可减少磁盘I/O.
簇负载平衡自动将用户连接到利用率最低的系统节点,因此减少了用户访问时间,并增加了可被服务的用户数.
第4Oracle8数据库介绍177自动化和只读独立数据库使Oracle可自动维护一个或多个用于灾难恢复的成品数据库拷贝.
独立数据库最初通过复制成品数据库创建.
复制能够驻留在同一位置或不同位置.
在独立数据库创建之后,成品数据库的更新和改变被传播到独立数据库,因此数据库保持同步.
独立数据库使用加强恢复模式.
当在成品数据库产生归档重做日志以后,它们Net8连接传输到独立数据库.
在独立数据库接收归档重做日志后,它们被自动运用以使两个数据库保持同步.
这样就不必手动维护独立数据库,但也可以手动维护.
如果网络发生错误或者发生空间溢出问题,阻止日志文件成功创建,那么,在特定的时间间隔后,自动重试归档操作.
以前,如果没有随后创建的成品数据库产品的另一个拷贝,当前的独立数据库不能被打开或使用.
在Oracle8i中,DBA现在可以只读模式打开独立数据库.
这提供了正当对成品数据库卸载一些进程时查询和产生独立数据库报告的一种方法.
在这一模式下,独立数据库能够连续自动接收来自成品数据库的归档重做日志,然后,当独立数据库被返回到加强或手动恢复模式,排队的日志被应用.
联机数据库重组和碎片消除是另一个特点.
Oracle8i现在在数据库重组与索引创建和重建期间,用户可以完全访问数据库.
当表和索引完全联机且没有中断任何正在进行的对基础表的改变时,DBA能够执行维护.
当在创建索引时,用户能够连续访问和更新基础数据表.
在创建期间任何对基础表索引的改变被记录在日志表中,并在操作结束后应用到新索引中.
索引也能被联机重建,提供高的数据库可用性.
当索引创建时,使用日志表来记录在重建操作期间对基础表所做的改变.
除了碎片消除不需要附加的存储空间外,联机索引碎片消除和合并很像两机索引重建.
索引碎片消除进程将单块合并到相邻的小于一个数据块的索引块中.
Oracle8i当用户可索引组织表(IOT)时,IOT可以被移动和重组.
对表所做的改变记录在日志表中,在进程结束时合并表.
这些联机重组能够在单个IOT或在被分区的IOT的单个分区中进行.
快速启动的失败恢复是一个旨在使系统失败恢复尽可能快,并减少数据库不可用时间的新特性.
它是很迅速的,恢复时间能够由管理员设定.
在一个系统崩溃后,数据库一般做向前回滚提交过的改变和回滚未提交的改变.
Oracle8i有一个新的快速启动检查点结构.
检查点进程不断地写被修改的块到磁盘中.
DBA指定多长时间向前进行回滚取代应发生多少次检查点.
回滚处理希望通过使用称之为非块回滚的技术进行消除.
现在,新的事务能够在向前回滚完成之后马上开始.
如果一个新事务访问被死亡事务锁定的一行,只有阻塞它的进程的改变被回滚.
同时,数据库有能力并行回滚死亡事务.
扩展备份和恢复用恢复管理器提高性能.
恢复管理器是一个管理创建和还原数据库备份的进程的工具,它现在有一个能够代表数据库引导备份软件完成复制操作的集成的媒体管理API.
它也能在自己目录上针对媒体管理软件目录和过期标注备份进行交叉检查.
恢复管理器使DBA能在恢复/还原操作发生之前预览即将发生的事.
另外,恢复管理器现在能多路备份到多个I/O设备.
Oracle使用TransparentApplicationFailover能增强从系统崩溃中恢复的能力.
当数据库连接中断时,客户程序能够自动重新连接.
同时,任何在崩溃时正在被处理的查询能够自动重启,返回程序的数据将从失败发生点恢复.
4.
6.
6安全性Oracle8i提供一个布置和执行分布式Java应用的安全平台.
过程、CORBA服务器和178Oracle8i数据库开发与专业应用企业级JavaBeans组件都能够在OracleNet8和CORBAIIOP上通过因特网标准的安全套接字层(SSL)进行访问.
Oracle8i提供单个符号加密,使用户可在internet/intranet环境中认证他们自己,这样可以缓解有太多口令的问题.
基于单个符号加密的公用密钥结构(PKI)使用X.
509(版本3)证书在SSL上认证.
OracleWallet管理器是一个由Oracle提供的用来保护和管理用户证书、密钥和信任点的工具.
Oracle8引入了企业角色,这是一个或多个跨越一个或多个数据服务器、被集中管理和维护的全局角色.
Oracle8i通过在Internet目录源中存储和管理用户信息,而不是用专用数据存储来提高这些能力.
Internet目录符合轻量目录访问协议(LDAP)版本3标准.
单站管理是通过Oracle企业安全管理工具的增强得到的.
现在,管理员能够从单个控制台在多个Oracle8i数据库中创建一个账户,或者跨多个数据库创建企业角色.
Oracle8i引入单个企业用户,在整个组织为每个用户创建一个账户,而不是为每个用户创建多个账户.
现在,要管理的用户账户更少,安全更容易通过使用Internet目录来加强.
Oracle8i提供强迫的、灵活的、好的访问控制行以及安全的应用环境.
通过一个或多个在表或视图上的安全策略使它们可用.
用访问控制,在访问数据时有更好的粒度.
对不同类型的访问(也就是select、update和delete)有不同策略.
现在,能指定谁能访问表中的特定行,区分数据访问到单一级别.
访问能够基于用户(例如,一个用户角色是经理还是职员)或基于应用(例如是用户正在访问一个人力资源应用,还是顾客正在创建一个定单).
下面的例子中,表ACCOUNT有一个策略,银行的顾客仅能看他们自己的账户,一个顾客通过发出如下命令访问表:SELECT*FROMACCOUNT;这个SELECT语句使数据库调用策略函数,然后透明地和动态地通过附加的WHERE语句重写这个查询:SELECT*FROMACCOUNTWHEREID=(SELECTIDFROMCUSTTABWHERECNAME=USERENV('user'));安全应用环境是在Oracle8i中基于访问控制策略提供的.
应用环境是由用户作为他们的属性定义,每一个应用能够有不同属性的安全策略.
据此,数据库将通过使在经理位置上的用户只能更新他自己部门里的职员的记录,以执行这个策略.
4.
6.
7其他特性Oracle企业管理器2.
0版是Oracle8i提供的最新版本的系统管理工具.
提供的一些特性有:从任何虚拟环境管理的能力、在企业中管理每件事的能力和最少化手工管理系统的"设置和忘记"管理.
它是基于Java的应用并能够从浏览器中访问.
管理员能够从一个中心控制台管理多个机器.
仓库现在是一个共享的公共知识库,它可供多个OEM管理员使用.
最初有一个缺省的超级用户SYSMAN,SYSMAN能创建其他超级用户和管理员并分配给它们适当的职责和特权.
每个新的管理员被给予一个完成管理任务需要的访问控制台口令.
因为每个管理员有特定的职责,所以他们能为其他管理员定义对他们创建的组、工作和事件的允许级别.
允许级别包括无、视图、修改和完全.
LogMiner是一个让DBA使用SQL来读、分析和解析重做日志文件的数据库分析工具.
第4Oracle8数据库介绍179LogMiner要求访问被分析的数据库的数据字典并用来自Oracle8.
0的重做日志文件继续工作.
正被分析的日志文件被映射到动态性能视图(V$logmnr_contents).
在这个表中的每一行代表数据库中完成的一次逻辑操作的信息.
对每个操作,由给定的REDO和UNDOSQL语句描述在数据库中所做的改变.
SQLREDO语句显示在数据库中所做的原始操作,而SQLUNDO语句显示能回滚这些改变的语句.
这个例子给出的查询要查找Benlin对表SAVINGS所做的修改:selectsql.
redo,sql_undofromv$logmnr_contentswhereusername='Benlin'andseg_name='SAVINGS';查询结果如下,它显示出Benlin首先删除他的存储记录,然后用更高的量重新创建这个记录.
Benlin所做的回滚改变的语句显示在SQL_UNDO列.
SQL_REDOdelete*fromsavingswhereid=999androwid='QSDFJKKJKAA';insertintosavings(name,id,amt)values('benlin',999,500);SQL_UNDOinsertintosavings(name,id,amt)values('benlin',999,10);delete*fromsavingswhereid=999androwid='QSDFJKKJKAA';数据库资源管理器是在Oracle8i中在数据库用户和应用之中分配和管理CPU资源的一个新工具.
过去,所有用户和应用对数据库进行同等访问.
现在能对更重要的任务分配更多的资源.
使用这个工具,用户和组被分配到资源消耗组.
管理员建立一个资源计划指定如何在不同资源消耗组中进行资源分配.
分计划进一步细分资源,它能在资源消耗组中进行定义.
对于分配资源最多能定义八个级别.
使用数据库资源管理所做的改变能够动态地在数据库上改变,不需要关闭后重新启动系统.
管理员能够有许多不同的资源规划和资源消耗组,所有这些都保存在数据字典中.
并行自动化程度(ADOP)特性也被集成在数据库资源管理器中来优化系统使用.
这个特性限制并行查询操作的并行化程度.
分区使用户将表和索引分成更多的可管理单元.
Oracle8i引入了对表的范围分区,在范围分区里数据是基于分区键的值的范围被分开.
在Oracle8i中,现在有哈希分区和合成分区.
哈希分区使我们能够跨设备分离数据,因为行按一个分区键的哈希值分开.
合成分区是范围和哈希值的合并.
首先,数据被按照值进行范围分区.
然后,每一个分区再细分为几个哈希分区.
Oracle8i也支持面向关系和LOB列的类型.
分区能够独立地从表或索引的其他分区中被备份和恢复,不妨碍未受影响分区的访问.
具体化视图是一个新的数据库对象类型.
它是用于创建、维护和使用总和表的优化特性.
总和表也称为集合表,在其中求总和及连接操作被预算,结果被存入数据库中.
通过访问总和表而不是每次根据数据求和,性能得到很大提高.
管理员能够指定如何和何时刷新这些表(也就是同步、当新数据被装入时、每周等).
同时,总和咨询向导帮助管理员创180Oracle8i数据库开发与专业应用建和维护总和表.
可传输的表空间使我们能在数据库之间移动空间,而不用做完全的导入/导出.
DBA能够在相同的系统之间(硬件结构)复制表空间的数据文件,因此转移数据既容易又迅速.
要传输的表空间必须被自我包含,也就是没有从表空间内部到表空间之外的引用点.
这里有一个称为transport_set_check的PL/SQL过程,用于检查一系列表空间是否是自我包含的.
首先,被移动的表空间被置为只读模式来保证被捕获的数据相一致.
然后,导出表空间的元数据,这是迅速的,因为数据量很小.
接下来对表空间的数据文件进行复制,使用操作系统应用将其复制到新的系统中.
在新的系统中,导入表空间的元数据.
这也同样迅速,也因为量很小.
还有另一种方法在表空间上执行按时间点恢复,通过移动一个好的表空间的拷贝到成品数据库中,恢复能够被迅速归档.
本地管理(位映射)表空间是在数据库中提高空间管理和最小化区间碎片的一种新的表空间类型.
一个区间是由一个或多个相连的数据块组成的逻辑存储单元.
在Oracle8i之前,管理自由区间和使用过的区间是通过数据字典来完成的.
现在,有位映射选项能指明表空间中使用过的块和空闲的块,因此最小化了对数据字典的访问.
这些表空间使用带有EXTENTMANAGEMENTLOCAL子句的CREATETABLESPACE命令创建.
这种类型的表空间将自动调节所有新区间的标准大小,既可用autoallocate选项又可用uniform选项.
在autoallocate选项下,系统将自动创建变化区间尺寸并能指定初始区间的尺寸,然后系统将决定附加区间尺寸.
在uniform选项下,所有区间创建是相同尺寸的.
如果不指明EXTENTMANAGEMENT子句,缺省是EXTENTMANAGEMENTDICTIONARY,它不指明这个表空间将由系统通过数据字典进行管理.
如果使用LOCATE子句,就不能在CREATETABLESPACE命令中使用缺省的存储语句、MINIMUMEXTENT或TEMPORARY参数.
下面是创建本地管理表空间TS的例子.
它的每个区间分配为64KB,在位映射中的每位表明32块(假设每块为2KB).
SQL>createtablespaceTS2datafile'/u01/oracle/mysid/ts.
dbf'size10M3extentmanagementlocaluniformsize64K;现在能够在用户临时表空间中创建临时表.
临时表仅在事务或会话期间保持,只对向它们插入数据的会话可用.
临时表不能被分区、索引组织、聚簇或者包含嵌套表或变量数据类型的列.
这些表不能有外键约束定义.
下面语句创建临时表stocks:SQL>CREATEGLOBALTEMPORARYTABLEstocks(stocknamevarchar2stockpricefloat);Dropcolumn命令提供从一个表中删除一列而不必重新创建该表和它的相关索引和约束的能力.
下面这个SQL语句将从表census中删除列描述符col_1和与col_1相关的每一行数据,在该列上定义的所有索引或约束也都被删除:SQL>ALTERTABLEcensusDROPcol_1;第4Oracle8数据库介绍1814.
7Oracle8i的附加主题在Oracle8.
x中有几个新特性或功能增强.
本节主要介绍的有新的ROWID(行内部地址)格式、新的口令管理功能、恢复管理器和高级队列,也简要地包含国家语言支持、约束和sys安全性的改进.
4.
7.
1新的行内部地址(ROWID)在Oracle8.
x中,新的ROWID格式已改变,主要是为了适应分区和对象的新特性以及增加数据库限制,提供比Oracle7.
x更多的数据库文件和表空间.
ROWID是Oracle中所有存储地址的基础,因此这个改进很重要.
ROWID被用做在规则的Oracle索引(B-树)中唯一识别一行,并在整个Oracle8的内核中使用.
在Oracle7.
x中,ROWID包括文件号、块号和行号.
它仅用一个号一致性地识别文件.
换句话说,在Oracle7.
x中文件号是绝对的,在Oracle8.
x中文件号是相对的.
一个Oracle8.
x数据文件的文件号由两部分组成:(1)绝对部分在数据库内(和在Oracle7.
x中一样)唯一,由dba_data_files表的FILE_NO列代表.
(2)相对部分在表空间唯一,由dba_files表中的RELATIVE_FNO代表.
因为文件号对表空间是相对的,新的ROWID也必须存储段的一些指示.
在Oracle8.
x中,这是用来识别表或分区的数据对象号.
通过确定这个段,Oracle8能确定包含的表空间,和使用dba_tablespaces一样.
能够确定数据对象号,例如从dba_objects的DATA_OBJECT_ID列中确定.
这个数据对象号不是对象标识符,它被包括在每一块中,并且是唯一的.
当一个表被截断或分区被移走时,数据对象号的版本增长.
使用这种方法,Oracle8能验证在块中的号匹配(也就是正确版本),也能够用它与回滚段中的块做比较来保证版本的准确性.
新的ROWID格式使用基于64位的编码,它的字符宽度是18.
这就意味着在任何给定的Oracle8数据库中有6418个可能的行.
新的Oracle8.
xROWID组成见表4-24.
表4-24新的Oracle8.
xROWID组成数据对象号相对文件号块号位置段(行)号000000FFFBBBBBBSSS从左到右,前六个字符代表数据对象号,接下来三个字符代表在表空间中的相对文件号,再接下来的六个字符代表在一个文件中的块号,最后的三个字符代表块中的位置段(行)号.
与Oracle7.
x对比,真正的不同之处是数据对象号和相对文件号.
在表4-25中,列出了Oracle7.
xROWID的格式.
表4-25Oracle7.
x的ROWID的组成块号行号文件号BBBBBBRRRRFFFF182Oracle8i数据库开发与专业应用从左到右,前六个字符代表在文件中的块号,接下来的四个字符代表块中行号,最后四个字符是绝对文件号.
除了在分区表中涉及到全局索引(因为分区能跨多个分区表空间)外,这种类型的ROWID在多数情况下是足够的.
表4-26比较了Oracle7.
x的ROWID和Oracle8.
x新的ROWID之间的不同.
表4-26Oracle7.
x和Oracle8.
x的ROWID的比较版本描述字节数显示文件号7.
x限制62点绝对8.
x扩展10无点相对相对表空间寻址是OracleVLDB支持的基础.
Oracle8使用10个字节来存储这个新的ROWID,而Oracle7.
x使用6个字节.
当相对ROWID已足够时,限制ROWID被使用.
当绝对ROWID被要求(如在分区表中用全局索引)时,扩展(完全)ROWID被使用.
对于无分区表上的无分区索引、在分区表上的相等分区索引、跨块的链接移植指针,使用限制ROWID已足够.
扩展ROWID用于分区表上的全局索引、内核的使用和存储ROWID的格式.
当Oracle8获取Oracle7ROWID时,ROWID以限制的格式出现,如同它们在Oracle7.
x中一样.
当时,当从Oracle7.
x获取Oracle8.
xROWID时,需要使用DBMS_ROWID包来解释扩展格式.
Oracle7的表可以被导出到Oracle8中,但是包含有新ROWID格式的Oracle8.
x表不能被导出到Oracle7中.
更进一步,如果ROWID被以任何存储格式保持,在它们导入之后,需要重新计算,因为它们的内容将是过时的,需要更新.
只在应用是部分存储或获取ROWID行时,发生应用可移植性问题.
另一方面,在整体上,使用ROWID的这些应用将受影响.
当Oracle7表被导出或被移植(使用移植工具)到Oracle8时,存储ROWID的列的宽度自动地变宽以适应新的比较宽的Oracle8.
xROWID.
前述的DBMS_ROWID包由dbmsutil.
sql脚本创建,被catproc.
sql脚本调用.
表4-27列出了DBMS_ROWID包的函数和返回值.
表4-28显示了从限制ROWID转换到扩展ROWID的例子.
表4-27DBMS_ROWID包的函数功能返回rowid_create一个新的ROWIDrowid_info类型和组成rowid_type类型(0=限制,1=扩展)rowid_object数据对象号(段)rowid_relative_fno相对文件号rowid__block_number块号rowid_rew_number行(位置)号rowid_absolute_fno绝对文件号rowid_to_extended扩展ROWIDrowid_to_restricted限制ROWIDrowid_verify0=可以被扩展,1=不能被扩展第4Oracle8数据库介绍183表4-28从限制ROWID转换到扩展ROWID的例子SQL>select*frommytablewheremykey=12;mykeymyROWIDmyvalue1200000001A.
0011.
0009102SQL>updatemytablesetmyrowid=1dbms_rowid.
rowid_to_extended(myrowid,'JOHN','MYTABLE',0)2wheremykey=12;mykeymyROWIDmyvalue12AAAAbcAACAAAAAbAAAA102rowid_to_extended函数接受旧的(限制的)ROWID、拥有者、表和转换类型(conversion_type).
这个转换类型既可以是0用于存储(内部)转换,又可以是1用于显示(外部)转化.
它返回一个新的(扩展)ROWID.
4.
7.
2口令管理的增强在Oracle8中提供的口令管理的增强包括账户锁定、时效和到期、历史机制和复杂的验证(激活检查).
为了启用口令管理,运行utlpwdmsg.
sql脚本.
它能建立环境资源文件并将用户指定给它们.
然而,它不能像在init.
ora文件中那样用resource_limit参数打开和关闭对资源的限制,口令限制总是被强迫执行.
用账户锁定,在指定数量的登录失败后,企图再次登录时,Oracle8自动锁定账户.
可以基于用户或组设定这个数.
在超过一定的时间间隔或者手动解锁之后,账户锁定被打开.
可以根据需要手动锁定,在这种情况下,只能使用手动解锁(不是通过一个时限解锁).
使用口令时效和到期,能指定一个截止周期或活动时间,它对应于口令保持多长时间的有效性.
也能指定一个宽限期来使用户有时间在口令到期时改变它的口令.
这些特性可以被建立在用户或组上.
例如A组可能有90天期限加上5天宽限,而B组可能有30天期限加上1天宽限,另外用户C可能有单独的期限和宽限,分别是60天和10天.
使用口令历史机制,一个用户不能再用过去的时间间隔中使用过的任何口令,这个时间间隔被指定在该用户的环境资源文件中.
另外,要记住的重要的一点是,和资源限制不一样,它和其他口令限制总是被强迫执行(除非被修改).
激活口令检查是通过一个缺省的SYSPL/SQL函数提供的.
用户可以增加改进的PL/SQL函数替换它,缺省的函数提供复杂的验证来检查每一个口令,如下:(1)至少4个字符长度;(2)不等于用户ID;(3)至少有以下每一种字符中的一个:字母、数字和标点符号;(4)至少有3个不同于老口令.
自己的口令检查函数在SYS视图中创建,依附在用户或组的环境资源文件中,并且必须附加如下声明:myfunction(p_useridINvarchar2(30),184Oracle8i数据库开发与专业应用p_new_passwordINvarchar2(30),p_old_passwordINvarchar2(30))returnboolean;CREATEPROFILE和ALTERPROFILE语句处理所有前述的口令限制的设置,对CREATEPROFILE语句的缺省口令设置见表4-29.
表4-29CREATEPROFILE的缺省口令设置设置缺省值单位failed_login_attempts3次password_life_time60天password_reuse_time180天password_reuse_max无限制个password_lock_time1个password_grace_time10天password_verify_function缺省函数这些设置中的大部分已经在前面的段落中介绍过,现在来讨论一些不太清楚的地方.
password_reuse_max代表在一个口令能够再被使用之前,改变口令的最大个数,缺省值是无限制,但是口令再使用还受password_reuse_time控制.
这两个参数都被设置为无限制,然而,实际上仅有一个能被设置为数值.
在这方面,它们之间的设置是互斥的.
password_lock_time代表在特定次数的企图登录失败之后,用户账户被锁定的天数.
用缺省的设置,如果用户三次登录失败以后,用户账户将被锁定一天.
最后,缺省的password_verify_function的实际名字是简单的verify_function.
表4-30给出一个创建环境资源文件,设置口令的限制,然后创建一个用户以拥有这个环境资源文件的例子.
表4-30为用户创建口令环境资源文件的例子SQL>createprofilesecure90limit2password_life_time903password_reuse_time3664password_grace_time5;SQL>createuserjohn2identifiedbyall4one3defaulttablespacescratch4temporarytablespacetemp25quota10Monscratch6passwordexpire7profilesecure90;注意:CREATEUSER语句在为新用户账户john预定截止日期之前,CREATEUSER和ALTERUSER语句将定制的环境资源文件用于一个特定的用户.
也可以用组来替代这个用户.
还有ALTERUSER语句被用来手动加锁和解锁,如下所示:第4Oracle8数据库介绍185SQL>alteruserjohn2accountlock|unlock;DBA_USERS和USER_USERS包含反映这些新的口令管理特性的新列,见表4-31.
表4-31新的用户口令管理特性新列意义account_status锁定、截止或打开grace_data改变的日期+password_grace_timelock_data锁定的日期expiry_data创建的日期+password_life_time4.
7.
3恢复管理器概念恢复管理器(RMAN)是对Oracle8备份、恢复和重建进行管理的一段软件.
RMAN可以是独立的或分布的.
RMAN对Oracle8服务器使用PL/SQL接口,它调用三个主要函数:BACKUP、RECOVER和RESTORE.
RMAN使用一个称为恢复目录的知识库.
在Oracle8.
0.
4版本中,第三方存储子系统如EMC/Epoth、Legato、IBM等等能够被集成到RMAN解决方案中.
例如,磁带驱动器以自动方式使用,能够以并行方式使用诸如那些来自Exabyte的磁带单元.
RMAN结构的四个基本结构块是RMAN接口(一个OEMaplet图形接口或命令行解释器,它能在OEM1.
4或更高版本中获得)、BACKUP/RECOVER/RESTORE服务器函数、恢复目录和存储子系统(操作系统的、第三方的或两者都是).
使用RMAN管理Oracle8备份,是因为它能自动执行许多管理功能和职责.
备份能发生在多级上:数据库、表空间或者数据文件级.
数据文件能够被特指为基于用户定义容限的备份.
最重要的是,真正的增量备份是可能的,换句话说,在任何级别的备份能够执行只对已改变的块备份,更进一步说,未被使用的块不被备份.
备份能够很容易地建立时间表和控制.
存储子系统处理更容易管理,它的操作可能被并行化,另外,RMAN能够与已经建立起来的第三方厂商硬件或软件集成.
RMAN有两个主接口:命令行解释(CLI)接口和OEM图形用户接口(GUI).
CLI接口是一个与SQL*Plus相似的应用,能够用交互或非交互的方式执行.
GUI在OEM中被集成,提供能够与第三方应用(例如存储子系统)相链接的API库.
1.
恢复目录恢复目录由catrman.
sql脚本创建,通常在专用数据库中对它进行存储,它十分像OEM知识库.
恢复数据库是存放恢复目录的数据库,目标数据库是任何RMAN要备份的目标数据库的应用或用户数据库.
恢复目录必须和其他数据库一起备份.
为备份恢复数据库,必须反转它的一个目标数据库的角色,一个目标数据库于是成为恢复数据库的备份数据库,它是暂时的目标数据库,另一些目标数据库是恢复数据库,这意味着它至少有两个恢复目录——一个是所有用户数据库的目录,另一个至少有一个为恢复目录自身的目录.
应把主要的RMAN知识库放入分开的(恢复)数据库中,并存放在与核心应用(目标)数据库分开的机器上.
另外可以只为处理重要的RMAN仓库在一个应用数据库中创建一个RMAN知识库.
用这种方法,能够在失去任何数据库后恢复它,包括数据库自身.
186Oracle8i数据库开发与专业应用恢复目录维护在它的数据库仓库中的信息,这些信息包括数据文件备份信息、归档日志备份设置、备份块、数据库文件拷贝、归档重做日志、归档重做日志拷贝、目标数据库的控制文件信息(也就是它们的物理结构)和通常可获得的命令.
RMAN静态地存储关于所有它的目标数据库的控制文件信息.
当备份操作发生时,RMAN与需要备份的服务于目标数据库上的Oracle8服务器进行通信,在它的核心里已经有了备份功能.
RMAN初始化和管理备份,但是实际上每一个目标数据库备份它自己.
因此,当任何目标数据库结构改变(例如,一个数据文件被增加或重命名)时,在下一个备份操作发生之前,几乎所有对更新恢复目录必要的信息都能在目标数据库的控制文件中找到.
然而RMAN能够在没有恢复目录时进行操作,当仅有一个或少量几个备份数据库,或者表空间按时间点恢复(PTR)不是本质的时,这是适合的.
回滚段信息应该存储在恢复目录中,它被从目标数据库中查询,但是没有恢复目录,这儿可以没有PTR.
对无恢复目录操作的其他限制包括不能使用存储脚本(它应该被存储在目录中)并且当控制文件被丢失或毁坏时自动恢复不一定可行(只是部分如此).
2.
RMAN命令和功能恢复管理依赖于(目标)服务器备份功能,这个功能驻留在包括所有必须的备份、恢复和复原子程序的数据库包中.
RMAN的前期产品,External(或Enterprise)BackupUtilility(EBU)仅能调用第三方工具.
集成是最高的程序层.
现在RMAN能通过API功能控制操作系统(OS)和第三方存储子系统.
集成是最低的功能层.
RMAN命令包括注册一个目标数据库、重置目标数据的状态(甚至对以前备份过的版本)、当目标数据库改变时更新恢复目录(甚至以前备份过的控制文件的状态)的能力.
目录同步是周期性更新目标数据库信息:所有控制文件和回滚信息.
这是重要的,不仅因为可能已有结构性变化,而且因为日志文件现在记录在控制文件里.
在Oracle8.
x中,控制文件改进为追踪日志文件转换和归档重做日志文件拷贝,因此同步变得十分重要.
RMAN提供直接使用BACKUP、RECOVER和RESTORE命令或在脚本中嵌入的能力.
RMAN脚本被RUN命令调用.
CREATESCRIPT命令被用来创建脚本(把它存储在恢复目录中).
为了安全起见,每个备份的脚本都保存在一个操作系统拷贝中(例如用于丢失恢复目录的情况).
REPORT和LIST命令提供恢复目录信息和RMAN状态的日志输出,REPORT报告基于用户容量相关的冗余、增量或时间可能需要备份文件的数据库文件.
备份文件可能被删除而且不能恢复.
LIST列出关于在备份集或复制中用户特定数据文件的信息,部分或全部匹配查找准则.
3.
RMAN术语备份集是数据文件(可能还包括控制文件)或者是归档日志的集合.
换句话说,多个文件被写入单个备份集中.
它与单个文件简单地被复制为镜像是相对地.
在备份集中被备份的文件在能够被使用之前必须被恢复(和提取).
而镜像能够直接使用,只是简单地重新命名为丢失的数据文件.
备份集支持完全或增量备份.
并行化能够被指定以匹配可获得磁带驱动器数.
备份集能够从磁盘到磁带运行,在恢复时相反执行.
数据文件能够被保存在包括多个磁带的备份(多磁带卷)之中,并被多路复用,在每个数据文件中有用户指定的块数.
控制文件块首先被完全写入,如果被包括,它不能在使用数据文件块时交织使用.
备份集能够被写入磁带或磁盘中.
备份块是属于备份集的单个文件.
这个文件能包含来自多个数据文件的块并能够被指第4Oracle8数据库介绍187明作为操作系统文件或磁带卷.
备份集是它的所有备份块之和.
镜像复制仅能够写入到磁盘,它与源文件形成一对一的对应.
如果所有的镜像文件的总和包含这个数据库,那么就有一个完全的冷备份.
它也能注册外来设备,也就是说,这些镜像文件可以不是RMAN创建的.
完全备份包含要备份的所有特定的数据块.
增量备份仅包含自上次备份以来被修改的块.
累加增量备份是可能的,但是它们浪费空间和时间,因此它们的优点被量的累积所消除.
也可以做一个完全备份作为基准,它被所有随后的增量所忽略.
多级增量就像UNIXufs备份规划.
0级代表完全备份,能指定最高7级的增量.
例如,2级可能代表周增量,1级代表日增量.
用这种规划,增量仅备份自上次同级或更低级备份以来的增量.
例如,2级备份仅备份自上次2级、1级或0级备份以来的改变.
多级增量增强了恢复,因为从任何给定的级仅需要恢复最多一个增量.
标识符是能够被指定到备份集或镜像文件的字符串(最多30个字符).
标识符是被存储子系统用来帮助用户记忆一些存储单元(例如磁带卷或磁盘分区)的符号名.
它的用途与RMAN没有区别.
标识符能够跨越备份集或镜像文件.
标识符不必对每个备份集或镜像文件唯一,这能有助于分组某些备份集,在感觉上组成一个整体确定的备份集,例如一个表空间.
备份和恢复的并行化操作由RMAN在内部处理,它建立多个并行用户会话,每个设备一个会话.
RMAN在用户会话内多路复用独立命令的发生,因此尽管在RMAN内语句执行是串行化的(如SQL*Plus),但通过虚拟的多用户会话可以实现并行化.
尽管一个用户能够指定分组,但当多路复用它们到备份集时,数据文件被RMAN分组.
除SYSTEM表空间外,RMAN支持任何表空间的PTR.
为了实现后者,Oracle要求数据库仅用技术支持助手复制和操作.
备份本质上要求数据库被打开(以获得回滚信息),可是恢复仅要求实例被启动.
备份和恢复都检查记录和报告块的毁坏.
它们也为破碎块探测进行校验和.
破碎的块是当它被修改时,正好赶上被备份操作读取,因此它必须被重读来得到一致性版本.
在Oracle8.
x中,控制文件随日志转换和归档拷贝增长.
可是这个增长能够通过设置init.
ora文件中的参数control_life_record_keep_time进行控制,这个参数被表示保持最旧的可重用条目或记录的天数,而Oracle7.
x没有可重用条目.
如果设置这个参数为0,无论何时需要,条目都可再用,它们无时间限制.
所有保存RMAN备份和恢复信息的数据字典视图都以V$BACKUP_*作为前缀,如下所示:V$BACKUP_CORRUPTIONV$BACKUP_DATAFILEV$BACKUP_REDOLOGV$BACKUP_SETV$BACKUP_PIECEV$BACKUP_MEMBERV$BACKUP_RESTORE_STATV$BACKUP_PARMS查看这些视图和V$BACKUP_LOG以及V$DATAFILE可监控的活动.
188Oracle8i数据库开发与专业应用4.
7.
4高级队列概念在分布式环境中有两种主要类型的执行:立即(同步)或延时(异步).
在大多数情况下,立即执行是在许多分布式系统总被采用的.
但是在其他一些情况下,例如基于复制的分布式系统,延时执行是适当的.
队列是延时执行机制.
队列是先进先出(FIFO)或先来先服务(FCFS)数据结构,首次到来的事情是首先得到服务并退出.
可是,存在纯队列的变体,它们全都或多或少地基于优先级这一概念.
在队列中的一个任务单元称之为一个工作.
一个工作在队列中等待被服务或被处理.
即使系统失败,持续队列也能保证在队列中的所有工作将在系统成功重启动后被处理.
工作控制和任务流管理是两个很适合队列化的领域.
事物处理(TP)监控器和面向消息的中间软件(MOM)依靠或者模仿消息队列功能.
Oracle8.
x提供高级队列(AQ)能力而无需第三方软件.
消息是能被处理的最小工作.
和网络包一样,它包括用户数据和控制信息.
单个事务能创建(产生)或处理(消耗)多个消息.
ENQUEUE创建消息,DEQUEUE使消息被处理.
消息队列是消息的队列或消息的集合.
由于不同的原因,多消息队列能够被创建,例如从功能上分开一些消息任务、分开独立的消息活动和可能增加进程的吞吐量.
消息表是用来存放多消息队列的Oracle表.
Oracle8.
x高级队列的一些比较重要的特性包括如下:(1)对象排列和优先级;(2)对象作为用户数据;(3)响应和异常队列;(4)事务性和非事务性消息;(5)一个消息的多个接收者;(6)消息分组.
Oracle高级队列的许多用户功能、管理功能是通过系统包dbmsaq和dbmsaqadm提供的.
dbmsaq包含基本过程enqueue和dequeue.
用户必须被授予aq_user_role.
消息的payload是它的用户数据.
看一看enqueue和dequeue声明.
enqueue(queue_nameINvarchar2,enqueue_optionsINenqueue_option_t,message-propertiesINmessage_properties_t,payloadIN,msgidOUTraw)dequeue(queue_nameINvarchar2,dequeue_optionsINdequeue_option_t,message_propertiesOUTmessage_properties_t,payloadOUT'john.
jq1',payload=>employee_typemsgid=>msgh);dbms_aq.
dequeue(queue_name=>'john.
jq1',payload=>employee_typemsgid=>msgh);用这个enqueue调用,一个消息有msgid、msgh和指定为employee_type对象的pageload,这个消息被放进john拥有的队列jqi中.
后续的dequeue调用处理同一个消息.
所有enqueue_options、dequeue_options和message_properties缺省值被采用.
同时,注意赋值操作符=>的使用.
当任何消息有基于时间相关的属性(例如延时、截止或保持间隔)时,要求有一个AQ计时器进程或时间管理器(tm).
设置init.
ora参数AQ_TM_PROCESSES为1,这将启动一个时间管理器进程.
当前,它仅能被设置为1,但是在未来的版本中,它可能能启动多个时间管理器.
DBMS_AQADM包含用于管理创建和控制队列和队列表以及管理订阅者和启动/停止时间管理器的子程序,必须有AQ_ADMINISTRATOR_ROLE以执行以下这些过程:CREATE_|DROP_QUEUE_TABLECREATE_|DROP_|ALTER_|START_|STOP_QUEUESTART_|STOP_TIME_MANAGERADD_|REMOVE_|QUEUE_SUBSCRIBER(S)采用缺省值时,这些语句可以十分简单.
但是和创建队列、处理队列操作一样,在DBA_AQADM过程的执行中可以指定许多选项,特别是处理产生的过程.
作为一个例子,一个最后关键概念涉及订阅者.
一个队列可以允许每个消息有多个接收者(这是队列表创建时的一个选项),可以处理来自这种队列消息的用户称为订阅者(subscriber).
Oracle在它的数据库引擎中集成了很强壮、也很复杂的队列机制.
DBA_QUEUE和USER_QUEUE表包含表队列信息,DBA_QUEUE和USER_QUEUE包含队列信息.
AQ$视图对于每个队列列表可用.
4.
7.
5约束、国家语言支持和SYS安全性在Oracle8.
x中约束检查能够被拖延直到事务结束前,也就是服务器只在提交时检查约束是否被满足.
如果约束在事务期间被违反,这是没有问题的.
如果在提交时违反,整个事务被回滚.
与之相对的是立即约束检查,即服务器在每个语句结尾检查约束.
如果语句违反约束,这条语句被回滚,不是整个事务.
190Oracle8i数据库开发与专业应用还有,替代使约束无效或有效,它们能够被强迫.
一个强迫约束强加于所有新修改语句,但是忽略当前已存在的数据(它实际上可能违反约束).
尽管可能不是一个好注意,Oracle8.
x现在可以使用非唯一索引使唯一性约束和主键约束可以被处理.
用于国家语言支持(NLS)的NCHAR列是新的.
它是一个定长字符、多字符数据类型,能容纳最多2000个字符.
NVARCHAR2与varchar2的关系就与NCHAR同char的关系是一样的.
但是NVARCHAR2能容纳最多4000个字符.
最后,为了存储和提取NCHAR和NVARCHAR2数据类型,实际值用字符N作为前缀,不用引号.
在Oracle8.
x中,除非是属于OSDBA组或拥有SYS口令/内部口令,否则如果没有SYSDBA身份,将不能链接到SYS图表中.
这些有使用ANY限定(例如SELECTANYTABLE)的系统权限的用户,在Oracle8.
x中将不能像在Oracle7.
x中那样有权访问SYS图表.
在Oracle8.
x中必须有SELECT_CATALOG_ROLE或EXECUTE_CATALOG_ROLE才能选择或执行SYS对象.
4.
8小结1.
问:如何评价Oracle8是数据库管理系统的一个重大升级产品答:主要有以下几点:(1)Oracle8经过了大规模的beta测试;(2)这是Oracle数据库管理系统产品中,把WindowsNT作为第一级开发平台的第一个重要版本;(3)新产品的学习和培训对Oracle的商业伙伴和客户都很重要,但对开发商和最终用户并不太重要,因为他们依赖于外部咨询专家;(4)在Oracle产品中,把Web和网络计算机环境作为系统的重要内容来强调Oracle8是第一个版本;(5)Oracle公司做出了大量的努力以支持开发人员在Internet环境下建造应用.
2.
问:相对于版本7,Oracle8有哪些主要的改进答:在Oracle8中对现有技术的增强主要包括以下部分:(1)并行的更新、插入和删除(parallelupdate,insert和delete);(2)增量备份(Incrementalbackuo);(3)DBLink集中(DBLinkconcentration);(4)连接池(connectionpooling);(5)改进的并行服务器;(6)改进的复制功能;(7)对非结构化数据的支持;(8)优化器的增强.
3.
问:SYS和SYSTEM的模式在Oracle8中的作用是什么答:SYS和SYSTEM是每个Oracle数据库都缺省安装的两个账户.
SYS上模式是所有内部数据库表、结构、供给包和过程等的拥有者,它还拥有所有的V$和数据字典视图,并创建所有封装的数据库角色(DBA,CONNECT,RESOURCE等).
SYS是一个Oracle数据库第4Oracle8数据库介绍191的根用户或系统管理员.
由于它具有全能的性质,应尽量避免作为SYS注册到系统中工作.
当以SYS账户注册到系统中工作,哪怕一个简单的打字错误,就有可能造成毁灭性的灾难.
SYS账户是唯一能够访问特定内部数据字典表的用户,因为它拥有所有的数据字典结构,为了将数据字典对象明确地授权给其他模式,SYS也是必须登录的账户.
当使用数据字典视图和表编写存储过程或触发器时,也必须使用SYS账户.
当数据库首次安装时,SYS账户的缺省口令是CHANGE_ON_INSTALL,并且每个称职的系统管理员都会立即更改这个口令.
SYSTEM模式也是在数据库创建时安装的,是用于DBA任务的缺省账户.
SYSTEM也对所有的数据库对象拥有完全的权限,而且许多第三方工具软件依赖于SYSTEM模式的存在及特权.
SYSTEM账户的缺省口令是MANAGER,并且像SYS口令一样,在数据库创建后应该立即更改.
许多数据库系统管理员使用SYSTEM模式执行数据库管理任务,但它更适合创建一个特殊的用户来完成数据库管理员的任务,这就确保了一个特殊的账户与一个特定的人相连,而那个特定的用户则对全部数据库的修改负有责任.
4.
问:Oracle8数据库有哪些对象答:可以把数据库对象划分为两种不同的类型:一类是由RDBMS内部使用的对象,被称为系统数据库对象(systemdatabaseobject),另一类是可以通过任何程序访问的对象,被称为用户数据库对象(userdatabaseobject).
(1)系统数据库对象:初始化参数文件;控制文件;联机重做日志文件;追踪文件;行内部地址;Oracle块.
(2)用户数据库对象:数据文件;区间;表空间.
(3)其他数据库对象:视图;序列;触发器;同义词;数据库链;包、过程和函数.
5.
问:Oracle进程有哪几类答:Oracle进程可以分为四类:对用户的请求提供服务;向数据文件中写数据;在日志文件中记录事务;监控数据库的功能运行.
6.
问:应用程序怎样与OracleDBMS连接答:Oracle的DBMS软件能够为应用程序处理所有的数据存储和数据检索的细节问题.
这与过去的平面文件不同,在过去的文件中,应用程序要对存储和检索过程实施完全控制.
现在需要学习Oracle的界面来控制与数据存储应用的交互.
可以在两个级别上考虑这种交互.
第一级涉及应用程序与数据库管理系统之间相联系的通信机制.
第二级是在与数据库通信之后,如何规范信息请求,以及以什么格式把输出返回到应用程序中.
7.
问:什么是分区答:分区(partitioning)可能是Oracle8RDBMS中最重要的一个新特性.
尽管它的有些形式已经存在于Oracle7中,但是它在Oracle8中得到增强,并更完全地并入RDBMS引擎.
在Oracle7中首次出现了用分区视图进行分区的能力.
分区视图帮助按照用户定义的业务规则、条件和规范,物理地分开磁盘上的数据存储.
从本质上讲,表和索引是能够按8.
问:分区有哪些种类答:有四种主要类型的分区或非分区表,它们是:(1)非分区(常规的)索引;192Oracle8i数据库开发与专业应用(2)全局前缀索引;(3)本地前缀索引;(4)本地非前缀索引.
9.
问:什么是集合、变量数组和嵌套表答:集合是排序的或未排序的一组事物,变量数组是排序的,而嵌套表是未排序的.
嵌套表是在最新的ANSI标准中,但变量数组是非标准的.
任何主从(一对多)关系能帮助对比这两种类型的集合.
用某种顺序列出的主表项目能够使用变量数组(VARRY),对每一个主表行的每行项目细节可以在变量数组中使用嵌套表.
10.
问:Oracle8i中的Java能力有何作用答:在数据库中有Java使开发和部署internet/intranet应用变得更容易、更快、代价更少和更高效.
Java程序语言使开发者能利用容易获得的大量开发工具,与C或C++这样的语言相比,Java代码在数据库服务器中执行是安全的,因为它不能操作指向内存位置的指针.
Oracle8iJava虚拟机的内存管理器自动分配和释放内存,因此它使在数据库中内存越界所引起的数据损坏问题减至最小.
11.
问:如何装入Java源代码、二进制或资源文件答:可以用两种方法装入Java源代码、二进制或资源文件.
一种方法是在SQL*Plus中新的DDL命令:"CREATEJAVA{SOURCE|CLASS|RESOURCE}"使用这个语句能从一个二进制文件或通过使用在数据库中的LOB列导入Java代码.
第二种方法是借助Oracle8i提供的LOADJAVA工具.
这个工具自动装入Java到数据库中.
它把Java文件装入到数据库中名叫create$java$lob$stable表中,然后运行SQL"CREATEJAVA.
.
.
"命令.
还有用于从数据单元中删除Java程序的DROPJAVA工具.
12.
问:Oracle8的口令管理的增强包括哪些内容答:在Oracle8中提供的口令管理的增强包括账户锁定、时效和到期、历史机制和复杂的验证(激活检查).
用账户锁定,在指定数量的登录失败后,企图再次登录时,Oracle8自动锁定账户.
使用口令时效和到期,能指定一个截止周期或活动时间,它对应于口令保持多长时间的有效性.
使用口令历史机制,一个用户不能再用过去的时间间隔中使用过的任何口令,这个时间间隔被指定在该用户的环境资源文件中.
激活口令检查是通过一个缺省的SYSPL/SQL函数提供的.
13.
问:恢复管理器概念的作用是什么答:恢复管理器(RMAN)是对Oracle8备份、恢复和重建进行管理的一段软件.
RMAN可以是独立的或分布的.
RMAN对Oracle8服务器使用PL/SQL接口,它调用三个主要函数:BACKUP、RECOVER和RESTORE.
RMAN使用一个称为恢复目录的知识库.
在Oracle8.
0.
4版本中,第三方存储子系统如EMC/Epoth、Legato、IBM等等能够被集成到RMAN解决方案中.
例如,磁带驱动器以自动方式使用,能够以并行方式使用诸如那些来自Exabyte的磁带单元.
第4Oracle8数据库介绍19314.
问:Oracle8.
x高级队列的一些比较重要的特性有哪些答:主要有以下几条:(1)对象排列和优先级;(2)对象作为用户数据;(3)响应和异常队列;(4)事务性和非事务性消息;(5)一个消息的多个接收者;(6)消息分组.
第5章Oracle8数据库编程5.
1用PL/SQL对Oracle数据库编程前面我们所使用的SQL语言不具备过程能力,但Oracle通过PL/SQL语言对SQL进行了过程语言的扩展.
PL/SQL是下列应用逻辑元素的基础.
(1)SQL*Plus程序(SQL*PlusScript):SQL*Plus程序可以组成PL/SQL子程序.
(2)存储过程或存储函数:存储过程或存储函数是可由客户机应用系统、数据触发器或Oracle工具应用触发器调用的PL/SQL子程序.
(3)数据库触发器:数据库触发器是一个PL/SQL子程序,该子程序是基于对数据库表执行一条DML语句(如INSERT、UPDATE或DELETE)的某些操作.
(4)包(Package):将一组PL/SQL过程、函数游标和其他PL/SQL变量组织在一起形成一个包.
(5)应用触发器:OracleForms和OracleReports这些Oracle应用开发设备有PL/SQL引擎,因此开发者可以使用PL/SQL建立应用触发器.
本节主要介绍PL/SQL的一些基本要素,在试图设计存储过程之前,应该掌握PL/SQL的语法和使用方法,本节所介绍的内容均包括在2.
0以上的版本中.
不要使用PL/SQL逐行键入PL/SQL程序.
如果这样做,直到SQL*Plus读到PL/SQL块结束符"/"之前,它将不提供任何反馈(因为只有当块是完整的时候,SQL*Plus才将整个块传递给PL/SQL引擎,PL/SQL引擎是OracleRDBMS的组成部分).
应该使用文本编辑器(如Notepad)编辑PL/SQL程序.
可以将PL/SQL程序直接粘贴到SQL*Plus中,或使用START或@命令运行该程序.
此外还有ProcedureBuilder(过程编写器),它是比SQL*Plus更高级的PL/SQL程序开发工具.
还有其他第三方产品可提供类似的功能,例如,Platinum的SQLStationCoder或DBCorp基于PL/SQL浏览器开发工具的WEB*PL.
5.
1.
1程序块结构语言PL/SQLPL/SQL是一种块结构语言,它的语法与C程序很类似.
除了支持嵌入SQL语句外,PL/SQL还提供了标准的程序结构,如过程和函数的说明、IF-THEN-ELSE和LOOP这样的控制语句以及变量说明.
一个PL/SQL程序由过程、函数或匿名块组成.
匿名块(anonymousblock)是一个没有参数也没有返回值的没有起名的PL/SQL块.
在SQL*Plus会话中,匿名块是运行程序(script)中的共同部分.
图5-1显示了从最高层观察的PL/SQL块的结构,其中包括可选的说明部分、执行部分和可选的控制PL/SQL和SQL例外及错误部分.
第5章Oracle8数据库编程195图5-1PL/SQL块的最高层结构让我们看一个简单的可产生一些检测数据的PL/SQL匿名块.
表5-1包括一个匿名块,可以从SQL*Plus程序中运行该匿名块,它在TEST_TABLE中插入100个行.
表5-1在SQL*Plus中运行一个PL/SQL匿名块SQL>@c:\tyo\day10_1SQL>droptabletest_table;Tabledropped.
SQL>SQL>createtabletest_table(2record_numberint,3current_datedate);Tablecreated.
SQL>SQL>DECLARE22max_recordsCONSTANTint:=100;3iint:=1;4BEGIN55FORiIn1.
.
max_recordsLOOP66INSERTINTOtest_table7(record_number,current_date)8VALUES9(i,SYSDATE);1010ENDLOOP;1111COMMIT;12END;/PL/SQLproceduresuccessfullycompleted.
PL/SQL说明部分执行部分例外处理部分196Oracle8i数据库开发与专业应用仔细研究上面的PL/SQL程序的一些要素.
因为它没有名字,所以这个程序是一个匿名的PL/SQL块(它不能作为一个过程、函数或包来进行说明).
程序中所有行都包含在一个单一的SQL*Plus程序中.
前两条SQL命令是删除TEST_TABLE表,然后再建立它.
该PL/SQL实际是从DECLARE语句开始的.
说明部分说明了一个常量max_records(第2行)和一个变量i(第3行),它作为一个计数器.
块的执行部分开始于BEGIN(第4行),块包含一个单层的FORLOOP语句(第5行),该语句使当i小于或等于max_records时,在表TEST_TABLE中插入一行.
当FORLOOP做完后,该事项被提交(commit)(第11行).
程序的最后一行是一个/,它使SQL*Plus将PL/SQL块交给PL/SQL引擎.
除非发生PL/SQL编译错误,一般只有一条反馈信息:PL/SQLproceduresuccessfullycompleted.
后面,我们将会介绍如何使PL/SQL产生诊断信息,它可使你看到PL/SQL子程序执行的步骤.
1.
说明部分一个PL/SQL块的说明部分是任选项,但是必须对所有PL/SQL语句中引用的变量和常量进行说明.
为了在一个PL/SQL块内包括一个说明部分,在PL/SQL块的开始使用字DECLARE.
每一个变量或常量的说明是由它的名字、类型和一个可选的默认值组成的.
像所有的PL/SQL语句一样,每个变量或常量的说明均以分号结束.
表5-2包括了一些常量和变量说明的例子.
表5-2说明变量和常量的例子Fax_NumberVARCHAR2(10);Current_Used_ValueNUMBER(6,2):=100.
00Max_Current_Used_ValueREAL:=9999.
99StateVARCHAR2(2):='CA';2.
执行部分一个PL/SQL块的执行部分是从关键字BEGIN后面开始的,每条PL/SQL语句均以分号结束.
这些语句可归纳为以下几类:(1)赋值语句(Assignmentstatement);(2)流程控制语句(Flow-of-controlstatement);(3)SQL语句;(4)游标语句(Cursorstatement).
3.
例外处理部分例外是在PL/SQL程序的执行中出现的一个错误,它可能是预定义的(例如,一个INSERT语句试图在一个表中增加一个重复行,结果出现了DUP-VAL-ON-INDEX例外).
可以说明自己的、针对特定应用系统的例外.
在例外部分可定义例外处理程序,例外处理程序可由预定义例外和用户例外调用.
每一个例外处理程序是由一条或多条PL/SQL语句组成的.
5.
1.
2用PL/SQL说明变量PL/SQL提供了SQL没有的附加数据类型.
除一般的OracleSQL数据类型外,PL/SQL还可以使用这些数据类型对变量进行说明:(1)BOOLEAN(布尔型):可用预定义的常量TRUE、FALSE或NULL对一个布尔变第5章Oracle8数据库编程197量赋值.
(2)BINARY-INTEGER(二进制整数):该类型使用于在-2,147,483,647到2,147,483,647范围内的带符号整数.
(3)NATURAL(自然数):是BINARY-INTEGER的一个子集,这种数据类型是整数集的一部分,从0到2,147,483,647.
(4)POSITIVE(正整数):是BINARY-INTEGER的另一个子集,这种数据类型是整数集的一部分,从1到2,147,483,647.
(5)%TYPE:这种设计可说明一个变量的数据类型与某一指定列的数据类型相同,其结果产生更易于维护的PL/SQL代码.
(6)%ROWTYPE:用这种数据类型可以说明一个复合变量,与某一特定表中的一行相同,这种复合变量是由引用表中的列名和数据类型组成的.
除此之外,PL/SQL还提供两种复合数据类型:TABLE型和RECORD型.
后面将介绍有关内容.
1.
用%TYPE说明一个变量用%TYPE说明变量的语法是:variable-nametable-name.
column-name%TYPE;各变量说明如下:variable-name:是要说明的变量;table-name:是包含将变量说明为其类型的列的表;column-name:是table-name表中所说明的列.
例如,为了说明一个用来存储修理仓库技师名字的变量,可使用这种方法:Tech-NameDepot-Estimate.
Technician%TYPE;在变量说明中使用%TYPE的好处是:PL/SQL代码可依赖于Depot-Estimate表中的Technician的定义.
2.
用%ROWTYPE说明一个变量用%ROWTYPE说明一个变量的语法是:variable-nametable-name%ROWTYPE;各变量说明如下:variable-name:是要说明的变量组合;table-name:是一个表,它的结构将用于对复合变量的说明.
例如,用一个复合变量存储Depot-Estimate表的一行,它的说明方式是:Depot-Est-RowDepot-Estimate%ROWTYPE;Depot-Est-Row的一个元素可以通过下面方式得到:Depot-Est-Row.
Technician:='RICHARDSON';5.
1.
3一些常见的控制结构几种控制一个PL/SQL子程序执行流程的PL/SQL命令如下:(1)IF-THEN-ELSE(2)LOOP(3)EXIT198Oracle8i数据库开发与专业应用(4)WHILE_LOOP(5)FOR_LOOP(6)GOTO(7)NULL在能够建立存储过程和触发器之前,应该熟悉PL/SQL编程的基本知识,后面将介绍这些语句的使用.
1.
IF语句PL/SQL的IF-THEN-ELSE语句与C语言中的同类语句有些不同.
它的语法如下:IFconditionTHENstatement;.
.
.
statement;[ELSIFconditongTHENstatement;.
.
.
statement;.
.
.
[ELSIFconditionTHENstatement;.
.
.
statement;[ELSEstatement;.
.
.
statement;]ENDIF;其中各变量定义如下:condition是一个有效的PL/SQL条件;statement是一个有效的PL/SQL语句.
对于IF-THEN-ELSE语句,应掌握如下事实:(1)ELSIF和ELSE子句是可选的.
(2)一个IF子句可以有多个ELSIF语句,但只能有一个ELSE子句.
表5-3给出了一个IF-THEN-ELSE语句的简单例子.
表5-3IF-THEN-ELSE语句的使用ifMOD(i,5)=0thenrec_number:=5;elsifMOD(i,7)=0thenrec_number:=7;elserec_number:=I;endif;2.
简单的LOOP语句LOOP的最基本的类是不带任何附加条件的LOOP语句,它的语法为:LOOPstatement;.
.
.
statement;ENDLOOP;各变量定义如下:第5章Oracle8数据库编程199statement是任何有效的PL/SQL语句,包括另一个LOOP.
显然,这个循环是一个无限的循环.
为了跳出循环,可在当一个条件被满足时执行EXIT语句.
3.
EXIT语句EXIT语句有两种形式:(1)EXIT不带任何其他子句(无条件退出);(2)EXIT[label-name]WHENcondition.
第一种形式的EXIT是用于跳出所在的循环,第二种形式的EXIT是用于当满足给定条件时,跳出所在的循环,见表5-4.
表5-4EXIT语句的使用SQL>declare22ipositive:=1;3max_loopsconstantpositive:=100;44begin55loop66i:=i+1;7exitwheni>max_loops;88endloop;99end;10/PL/SQLproceduresuccessfullycompleted.
4.
WHILE-LOOP语句WHILE-LOOP语句是给循环加了一个条件:WHILEconditionLOOPstatement;.
.
.
statement;ENDLOOP;各变量定义如下:condition是一个有效的PL/SQL条件;statement是一个有效的PL/SQL语句.
表5-5给出了WHILE-LOOP语句的使用范例.
表5-5WHILE-LOOP语句的使用WHILEI>表5-7给出了一个如何使用一条GOTO语句和一个标号用来代替EXIT语句的例子.
表5-7GOTO语句的使用SQ>declare22ipositive:=1;3max_loopsconstantpositive:=100;44begin55i:=1;66loop7i:=i+1;8ifi>max_loopsthen9gotomore_processing;10endif;1111endloop;12>13i:=1;1414end;15/PL/SQLproceduresuccessfullycompleted.
第5章Oracle8数据库编程2017.
NULL语句在某种情况下,需要指明PL/SQL将不执行任何操作.
例如,在一个例外处理程序中,当一个指定的例外发生时,也许并不想做任何处理.
为清楚起见,在一条IF-THEN-ELSE中使用NULL语句,可以使在一条特定的ELSIF子句内不执行任何操作.
Oracle将该命令命名为null,但它与null值没有任何关系.
表5-8给出一个如何使用NULL语句的范例.
表5-8NULL语句的使用if(mod(i,10)=0)theni:=i+1;elseNULL;endif;8.
赋值语句正像所看到的,PL/SQL使用":="给一个PL/SQL变量赋值.
可以在说明部分定义一个常量或一个变量的默认值.
这里有一点值得注意的是:当用%TYPE符号说明一个变量时,如果引用的列被定义为NOTNULL时,不能给该变量赋一个NULL值.
9.
在PL/SQL子程序中加入注释PL/SQL给出两种方式用于编辑代码.
第一种方式,可以在任意行添加以"--"开头注释,例如:Depot-Est-Row.
Technician:=Last-Tech-Name;--Assignthenameofthelasttechnicianinvolved第二种方式,可以添加C语言风格的注释,用/*和*/将注释括起来.
当注释是很多行时,适合于采用这种方式,如表5-9所示.
表5-9PL/SQL代码的注释j:=j+1;/*ThenextsectioninsertsarowintotheUtility_AudittabletorecordthenameofthecurrentOracleuserandthecurrentdateandtime(SYSDATE).
*/insertintoUtility_Audit.
.
.
5.
1.
4在PL/SQL程序中使用SQL语句就像在SQL*Plus中使用一样,可以在匿名块、过程或函数中使用SQL语句,但有一些不同.
像其他PL/SQL语句一样,每条SQL语句都必须以分号结束.
不过,PL/SQL可以在一条SQL语句中引用说明过的变量.
表5-10给出了一个范例,显示了如何说明在SQL语句中引用的变量.
202Oracle8i数据库开发与专业应用表5-10在SQL语句中使用变量DECLAREmax_recordsCONSTANTint:=100;iint:=1;BEGINFORiIN1.
.
max_recordsLOOPif(mod(i,10)=0)thenINSERTINTOtest_table(record_number,current_date)VALUES(i,SYSDATE);elseNULL;endif;ENDLOOP;COMMIT;END;/例子中的INSERT语句使用了数据型变量i和一个伪列SYSDATE,将其值放在Rcord-Number和Current-Date两个列中.
在一个PL/SQL子程序中,SELECT语句用另一个子句(INTO)来指明PL/SQL可以得到列值的变量,INTO子句放在select列表名和FROM子句之间.
表5-11给出一个包含一条SELECT语句的匿名PL/SQL块示例.
表5-11在一个PL/SQL块中使用SELECT语句SQL>setserveroutputonSQL>SQL>declare22Average_Body_TempPatient.
Body_Temp_Deg_F%type;33begin44dbms_output.
enable;55selectavg(Body_Temp_Deg_F)6intoAverage_Body_Temp7fromPatient;88dbms_output.
out_line('AveragebodytempinDeg.
F:'||8to_char(Average_Body_Temp,'999.
99'));99end;10/AveragebodytempinDeg.
F:99.
80PL/SQLproceduresuccessfullycompleted.
第5章Oracle8数据库编程2035.
1.
5PL/SQL子块的应用PL/SQL允许在一个块中包含子块,例如,程序表5-12列出一个匿名的块,它包含另一个子块,该子块有自己的说明部分.
表5-12子块的示例SQL>declare22max_iconstantint:=100;3iint:=1;4rec_numberint;55bigin66foriin1.
.
max_iloop77ifmod(i,5)=0then8rec_number:=5;9elsifmod(i,7)=0then10rec_number:=7;11else12rec_number:=i;13endif;1414insertintotest_table15(record_number,current_date)16values17(record_number,sysdate);1818--Hereisasub-block;1919declare20max_jconstantint:=10;21jint:=1;2222begin2323forjin1.
.
max_jloop2424rec_number:=rec_number*j;2525insertintotest_table26(record_number,current_date)27values28(record_number,sysdate);2929endloop;30204Oracle8i数据库开发与专业应用(续)30end;3131commit;32endloop;3333end;34/PL/SQLproceduresuccessfullycompleted.
SQL>selectcount(*)fromtest_table;COUNT(*)表5-12第1行是该匿名块的说明部分,第5行是主块执行部分的开始,子块的说明部分是从第19行开始,第22行是子块可执行部分的开始.
虽然PL/SQL可以在一个块中嵌套子块,但事实上它并不是理想的方法,主要有两个原因:首先,降低了程序可读性,进而降低了可维护性;其次,嵌套块不能被其他PL/SQL子程序调用.
为了提高程序的重用性和可维护性,应该尽可能多地设计过程和函数.
PL/SQL支持子程序的使用(即过程和函数的使用).
一个PL/SQL过程可执行一些功能并可采用任选的参数.
一个PL/SQL函数可以返回某类指定的数据类型的一个数值,并也可以采用任选结构.
5.
1.
6过程的说明除了匿名块之外,还可以说明PL/SQL过程和函数.
一个过程的语法是:PROCEDUREprocedure-name[(argument1,.
.
.
,argumentN)]IS[local-variable-declarations]BEGINexecutable-section[exception-section]END[procedure-name];其中变量说明如下:procedure-name:是一个过程名,并且按照Oracle数据库对象命名的规定命名;argument1到argumetN:是任选的参数说明部分,其组成是:argument-name[IN|OUT]datatype[{:=|DEFAULT}Value];local-variable-delcarations:是可选的在procedure-name局部的变量、常量和其他过程和函数的说明内;executable-section:是组成过程的PL/SQL语句;exception-section:是可选的过程的例外处理程序部分.
区分存储过程(storedprocedure)和说明过程及在匿名块中使用的不同是非常重要的.
说明过程在匿名块中的过程是非永久性的,当一个匿名块运行完成后,对Oracle而言,这些过程也就不再存在了.
而一个存储过程是用CREATEPROCEDURE语句创建的,或者是包含在一个包内,由于它可被SQL*Plus程序、PL/SQL子程序或数据库触发器调用,因此,它是永久性的.
第5章Oracle8数据库编程205为了对这种语法进一步说明,表5-13给出了一个匿名块的例子,它说明了一个名为Record_Patient_Temp_Deg_C的过程,这个过程有两个参数:病人号(PatientID)和病人体温摄氏温度(见第4行).
在第3行,变量High_Fever的初始值为42,在第17行,该过程用两个参数调用:New_Patient_ID(它是GG9999)和High_Fever,在匿名块后面的SELECT语句验证过程确实是将摄氏42度变成华氏107.
6度.
表5-13一个过程的范例SQL>declare22New_Patient_IDPatient.
Patient_ID%type;3High_Feverconstantreal:=42.
0;44procedureRecord_Patient_Temp_Deg_C(Patient_IDvarchar2,5Body_Temp_Deg_Creal)is66Temp_Deg_Freal;77begin88Temp_Deg_F:=(9.
0/5.
0)*Body_Temp_C+32.
0;99insertintoPatient10(Patient_ID,Body_Temp_Deg_F)11values12(Patient_ID,Temp_Deg_F);1313commit;14end1515begin1616New_Patient_ID:='GG9999';1717Record_Patient_Temp_Deg_C(New_Patient_ID,High_Fever);1818end;19/PL/SQLproceduresuccessfullycompleted.
SQL>selectPatient_ID,Body_Temp_Deg_F2fromPatient3where4Patient_ID='GG9999';PATIENTBODY_TEMP_DEG_FGG9999107.
6206Oracle8i数据库开发与专业应用表5-14证明在一个过程内说明的变量不可以在过程外使用.
表5-14说明在PL/SQL中变量使用范围的例子SQL>declare22procedureDelete_Patientsis33Temp_Deg_Freal;44begin55deletefromPatient6where7Patient_ID='GG3333';8commit;99end;1010begin11Temp_Deg_F:=100.
0;1212end;13/Temp_Deg_F:=100.
0;*ERRORatline11:ORA-06550:line11,column1:PLS-00201:identifier'TEMP-DEG-'mustbedeclaredORA-06550:line11,colume1:PL/SQL:Statementignored表5-14是一个以说明部分为开始的匿名块.
在第2行说明了一个过程Delete_Patients.
在该过程的内部,说明了一个REAL型变量Temp_Deg_F.
但在第11行,匿名块引用了Temp_Deg_F,从而导致PL/SQL出现一条错误信息PLS-00201.
这说明了在一个过程或函数中一个局部变量的使用范围:它不能被其他过程或函数调用.
5.
1.
7函数的说明一个PL/SQL函数说明与过程说明很相似,只是函数返回一个预定义的数据类型的值.
说明一个函数的语法是:FUNCTIONfunction-name[(argument1,…,argumentN)]RETURNfunction-datatypeIS[local-variable-declarations]BEGINexecutable-section[exception-section]第5章Oracle8数据库编程207END[function-name];各变量定义如下:function-name:是一个函数名,其命名方法遵循Oracle数据库对象命名规则;argument1到argumentN:是可选的参数说明,其组成是:argument-name[IN|OUT]datetype[{:=|DEFAULT}value];function-datetype:是对function-name的局部变量、常量和其他局部过程和函数的说明,是可选项.
executable-section:是组成该函数的PL/SQL语句;exception-section:是可选项,它是函数的例外处理程序的部分.
表5-15给出了一个说明和调用函数的例子.
函数Max_Additional_Fees只有一个参数Dept_ID(第3行),该函数返回Course_ID,是在指定系中所有课程的最高附加费(SELECT语句是从第9行开始的).
匿名块用ECON对应Dept_ID调用函数(第24行),且函数返回Course_ID值为189.
查询在程序表5-15结束位置上显示的189确实是最高附加费.
表5-15一个函数的例子SQL>declare22Course_IDCourse.
Course_ID%type;33functionMax_Additional_Fees(Dept_IDINvarchar2)4returnvarchar2is55Additional_FeesCourse.
Additional_Fees%type6UnitsCourse.
Additional_Fees%type;7Course_IDCourse.
Course_ID%type;88begin99selectCourse_ID10intoCourse_ID11fromCourse12where13Department_ID=Dept_IDand14Additional_Fees=15(selectmax(Additional_Fees)16fromCourse17where18Department_ID=Dept_ID);1919returnCourse_ID;2020end;2121--Beginningofexecutablesectionofanonymousblock.
.
2222begin208Oracle8i数据库开发与专业应用(续)2323dbms_output.
enable;2424Course_ID:=Max_Additional_Fees('ECON');2525dbms_output.
put_line('Course_ID:'||Course_ID);2626end;27/Course_ID:189PL/SQLproceduresuccessfullycompleted.
SQL>selectCourse_ID,Additional_Fees2fromCourse3where4Department_ID='ECON'5orderbyCourse_ID;COURSEADDITIONAL_FEES101251897501990每个过程和函数的参数可任选地被说明为以下的一种形式:(1)IN:参数的值传递给过程或函数,但是没有值返回给调用它的PL/SQL子程序.
在一个过程或函数内部,不能给说明为IN的参数赋值,只能引用这种类型参数的值.
(2)OUT:过程和函数不能使用参数传递的值,但给调用它的PL/SQL子程序一个返回值.
在一个过程或函数内部,不能引用说明为OUT的参数值,只能给这种类型参数赋值.
(3)INOUT:参数的值传递给过程或函数,并且给调用它的PL/SQL子程序一个返回值.
如果说明一个参数为INOUT类型,则在过程或函数内部,既可以引用这种类型也可以给它赋值.
表5-16说明如何使用这三种类型的参数.
表5-16不同参数类型IN、OUT和INOUT的使用SQL>declare22This_Arg1number;3This_Arg2number;4This_Arg3number;55procedureDifferent_Arguments6(arg1INnumber,7arg2OUTnumber,8arg3INOUTnumber)is9第5章Oracle8数据库编程209(续)9begin1010arg2:=arg1;11arg3:=arg3+1;1212end;1313--Beginningofexecutablesectionofanonymousblock.
1414begin1515This_Arg1:=3.
14159;1616Different_Arguments(This_Arg1,This_Arg2,This_Arg3);1717end;18/PL/SQLproceduresuccessfullycompleted.
5.
2用PL/SQL进行程序开发前面我们学习了PL/SQL的程序结构,本节将介绍如何建立PL/SQL模块(即存储在Oracle数据库中的过程、函数和包),还将介绍能在PL/SQL中使用而不能在SQL中使用的数据类型.
存储过程或函数是存储在Oracle数据库中的PL/SQL程序,可由用户直接或间接调用.
使用存储过程和函数的主要优越性有以下几点:(1)提高了效率:在客户/服务器体系结构中,客户机应用向数据库服务器提出对SQL的需求.
随着用户数量的增加,SQL请求也就不断地增加,使网络很快就成为运行的瓶颈.
使用存储过程可使运行性能得到显著的改进,因为对存储过程的一个调用,即调用了在服务器中执行的多个SQL语句,从而减少了网络的拥挤.
(2)可重用性:一个PL/SQL程序只需编写一次,即可用于各种地方——SQL脚本、数据库触发器和客户机应用程序.
(3)可移植性:可在任何Oracle数据库中使用存储过程,而不用考虑平台问题,所以不需要处理像操作系统或编译版本中出现的兼容性问题.
只要平台支持Oracle,不需做任何改变就可调用存储过程.
当然如果存储过程包含对文件和路名的引用,就需要另做一些改变.
(4)可维护性:一个存储过程用于完成一个特定的任务,如数据库触发器、SQL*Plus脚本、应用程序或其他存储过程可能需要调用该过程.
从所有这些地方均可调用同一个存储过程,这样可降低软件维护的成本.
可以使用不同的工具建立和维护存储过程、函数和包.
在本节将学习使用SQL*Plus或SQLWorksheet建立和维护它们.
这里有几种先进的工具,如OracleProcedureBuilder(Oracel过程编写器),它是Developer/2000的一个组成部分.
首先,Procedure210Oracle8i数据库开发与专业应用Builder(过程编写器)带有一个PL/SQL存储过程的编辑器,使用它可以非常简单地修改PL/SQL代码;第二,在编辑器中可以简单地单击一个按钮即可编译存储过程;第三,任何编译错误均显示在一个独立的窗口内,使用户感到很方便.
5.
2.
1建立存储过程或函数1.
存储过程和函数的建立使用诸如NotePad或WordPad这样的文本编辑器建立存储过程是一种好方法,更好的方法是使用Oracle提供的过程编写器(ProcedureBuilder),它是Developer/2000的一个组成部分.
将NotePad或WordPad打开,把一个存储过程复制并剪贴到SQL*Plus或SQLWorksheet中,以便于开发和测试.
建立存储过程的语法如下:CREATE[ORREPLACE]PROCEDUREprocedure_name[(argument1,…,argumentN)]IS[local-variable-declarations]BEGINexecutable-section[exception-section]END[procedure-name];各变量定义如下:procedure_name:是过程名,其命名方法遵循Oracle数据库对象命名规则;argument1到aregumentN:是任选参数,它的说明形式是:argument_name[IN|OUT]datatype[{:=|DEFAULT}value];local-variable-declarations:是对变量、常量和在procedure_name中的其他过程或函数的说明;executable-section:是组成过程的PL/SQL语句;exception-section:是可选的过程的例外处理部分.
表5-17给出一个存储过程,它只有一个参数用于DELETE语句,用以确定从Course表中删除那些班.
表5-17建立只有一个参数的存储过程SQL>createorreplaceprocedureDelete_Specified_Course2(Desctiption_Phrasevarchar2)is33begin44deletefromCourse5where6upper(Description)likeDescription-Phrase;77end;8/Procedurecreated.
第5章Oracle8数据库编程211建立存储函数的语法与建立存储过程的语法是非常相似的,当然,存储函数必须有返回数值.
CREATE[ORREPLACE]FUNCTIONfunction-name[(argument1,.
.
.
,argumentN)]RETURNfunction-datetypeIS[local-variable-decarations]BEGINexecutable-section[exception-section]RETURNfunction-valueEND[function-name];各变量定义如下:function-name:是一个函数名,其命名方法遵循Oracle数据库对象命名规则;argument1到argumentN:是可选参数,其说明的组成是:Argument-name[IN|OUT]datatype[{:=|DEFAULT}value];function-datatype:是函数返回值的数据类型;local-variable-declarations:是可选的变量、常量及在function-name中引用的其他过程或函数的说明;executable-section:是组成函数的PL/SQL语句;exception-section:是可选的函数的例外处理部分;function-value:是函数返回给调用程序的数值.
存储过程和存储函数之间的区别在于:存储过程没有返回值,而存储函数则有返回值.
因此,在SQL语句中可以调用存储函数,其方法与调用内部函数相同,但对存储过程无法做到这一点.
不过,如果将参数说明为OUT或INOUT,则存储过程和函数均可以返回修改过的参数值.
表5-18给出了如何建立存储函数来获得一个学生的平均成绩.
表5-18建立只有一个参数的存储函数SQL>createorreplacefunctionstudent_GPA(arg_student_IDINvarchar2)2returnnumberis33GPAnumber;44begin55selectavg(decode(grade,'A+',4.
25,'A',4,'A-',3.
75,6'B+',3.
25,'B',3,'B-',2.
75,7'C+',2.
25,'C',2,'C-',1.
75,8'D+',1.
25,'D',1,'D',0.
75,9'F',0))10intoGPA11fromstudent_schedule12where13student_id=arg_student_id;1414returnGPA;1515end;16/212Oracle8i数据库开发与专业应用本节中的许多例子都调用了一个名字为dbms_output的包.
这个包提供了一组过程和函数,用于显示一个PL/SQL块的值.
为了在SQL*Plus下使用这个包,在任何过程或函数调用dbms_output之前,先要输入下列命令:setserveroutputon2.
在建立存储过程时获取错误信息在建立存储的PL/SQL程序时,如果Oracle发现到错误,它提供的一条非描述性的信息仅指示出现了错误,却没有提供任何其他详细情况.
表5-19说明了试图用一个错误的语法建立存储过程时,将会发生的情况.
为了能看到由编译PL/SQL代码而产生的错误,可以使用SQL*Plus的命令showerrors显示特定的PL/SQL编译错误.
表5-19在存储过程的编译中Oracle返回一条错误信息SQL>createorreplaceprocedureshow_insertsIS22max_recordsconstantint:=100;3iint:=1;44begin55dbms_output.
enable;66foriin1.
.
max_recordsloop77if(mod(i,10)=0)then8insertsintotest_table9(records_number,current_date)10values11(i,SYSDATE)12dbms_output.
put_line('Thevalueofiis'||to_char(i));1313else14null;1515endif;1616endloop;1717end;18/Warning:Procedurecreatedwithcomplicationerrors.
SQL>showerrorsErrorsforPROCEDURESHOW_INSERTS:LINE/COLERROR12/5PLS-00103:Encounteredthesymbol"DBMS_OUTPUT"whenexpectingoneofthefollowing:;;wasinsertedbefore"DBMS_OUTPUT"tocontinue.
第5章Oracle8数据库编程213在试图建立或替换过程show_inserts时,在18行后面Oracle返回了一条警告,指出有编辑错误.
要查看这个错误,可以使用命令showerrors.
在第11行可以看到INSERTS语句没有用分号结束.
5.
2.
2检索存储过程建立存储过程后,也许想看一看PL/SQL程序的代码,不过,用于建立存储过程的SQL脚本是不可见的,尽管如此,还是可以使用查询Oracle数据字典视图的方法检索存储过程的源代码.
Oracle数据字典是一组表,它包含有关Oracle数据库本身的信息.
由于这些数据字典表的结构不易弄清楚,因此Oracle定义了一组视图,它们提供了有关数据库字典的一致的查看方法.
其中一个视图名为USER_SOURCE,它提供以下四个列:NAME:包括过程、函数、包或包体的名字;TYPE:指出源代码是否属于过程、函数、包还是包体;TEXT:包含源代码的一行;LINE:包含在TEXT中源代码所包含的行数.
假设建立了名为DROP_CLASS的存储过程,如果想看DROP_CLASS的源代码,查询USE_SOURCE数据字典视图,那么可按表5-20所列的程序进行.
表5-20检索存储过程的源代码SQL>selectline,text2fromuser_source3where4name='DROP_CLASS'5orderbyline;LINETEXT1proceduredrop_class(arg_student_IDINvarchar2,2arg_class_IDINvarchar2,3statusOUTnumber)is45counternumber;67begin89status:=0;1011--Verifythatthisclassreallyispartofthestudent'sschedule.
1213selectcount(*)intocounter14fromstudent_schedule15where16student_id=arg_student_idand214Oracle8i数据库开发与专业应用(续)17class_id=arg_class_id;1819ifcounter=1then20deletefromstudent_schedule21where22student_id=arg_student_idand23class_id=arg_class_id;24status:=-1;25endif;2627end;27rowsselected.
可以查询USER_OBJECTS获得属于当前所连接的Oracle账户的存储过程、函数、包或包体的目录列表.
如果想查看不管属于谁的所有对象,应查询DBA_OBJECTS,而不是查询USER_OBJECTS.
在DBA_OBJECTS中的OBJECT_TYPE列指出了对象的类型:表、视图、过程等.
要得到属于用户的数据库对象的类型的列表,应使用表5-21所示的查询.
表5-21确定属于当前用户对象的类型SQL>selectdistinctobject_type2fromuser_objects;OBJECT_TYPEFUNCTIONINDEXPACKAGEPACKAGEBODYPROCEDURETABLEVIEW7rowsselected.
5.
2.
3过程和函数的提前说明PL/SQL要求在PL/SQL子程序中任何地方所使用的标识符都要进行说明(包括常量、变量、游标、过程和函数).
当两个子程序相互调用时,这项要求就会出现问题,见程序表5-22.
第5章Oracle8数据库编程215表5-22在说明前引用函数SQL>setserveroutputonSQL>SQL>declare22functionMedicare_Patient(Patient_IDINvarchar2)3returnnumberis44statusnumber;5Pat_IDvarchar2(6);66begin77ifInsurable_Patient(Pat_ID)=2then8status:=1;9endif;1010returnstatus;1111endMedicare_Patient;121212functionInsurable_Patient(Patient_IDINvarchar2)13returnnumberis1414statusnumber;15Pat_IDvarchar2(6);1616begin1717ifMedicare_Patient(Pat_ID)=2then18status:=1;19endif;2020returnstatus;2121endInsurable_Patient;2222--Executableprotionofanonymousblock.
2323begin2424dbms_output.
enable;2525end;26/declare*ERRORatline1:ORA-06550:line7,column4:PLS-00313:'INSURABLE_PATIENT'notdeclaredinthisscopeORA-06550:line7,column1:PL/SQL:Statementignored216Oracle8i数据库开发与专业应用在表5-22中可以看到:PL/SQL不识别在函数Medicare_Patient中对Insurable_Patient的调用(第7行),因为对Insurable_Patient的说明在Medicare_Patient说明(第2行)的后面.
为了避免这种现象,应在说明部分包括对子程序的提前说明.
提前说明(forworddeclaration)是对子程序及它的参数和返回值类型的说明.
表5-23给出了如何对Insurable_Patient(第2行)进行提前说明的例子.
表5-23对函数进行提前说明SQL>setserveroutputonSQL>SQL>declare22functionInsurable_Patient(Patient_IDINvarchar2)returnnumber;33functionMedicarePatient(Patient_IDINvarchar2)4returnnumberis55statusnumber;6Pat_IDvarchar2(6);77begin88ifInsurable_Patient(Pat_ID)=2then9status:=1;10endif;1111returnstatus;1212endMedicare_Patient;131313functionInsurable_Patient(Patient_IDINvarchar2)14returnnumberis1515statusnumber;16Pat_IDvarchar2(6);1717begin1818ifMedicare_Patient(Pat_ID)=2then19status:=1;20endif;2121returnstatus;2222endInsurable_Patient;2323--Executableprotionofanonymousblock.
2424begin2525dbms_output.
enable;2626end;27/PL/SQLproceduresuccessfullycompleted.
第5章Oracle8数据库编程2175.
2.
4在SQL语句中使用存储函数使用OracleRDBMS7.
1版本可以在SQL语句中使用存储过程.
这一特性功能强大,因为它扩展了单条SQL语句的功能,使一条语句就包含了一个存储函数包括的逻辑内容.
下面是一个关于该功能是如何实现的简单例子.
因为Oracle没有将温度从华氏转换的内部函数,所以需要建立一个存储函数用于完成这一转换过程.
完成对存储函数的建立后,就可以在一条SELECT语句中调用该函数,见表5-24.
表5-24在SELECT语句中使用存储函数SQL>createorreplacefunctionDegF_to_DegC(Deg_FINnumber)2returnnumberis33Deg_Cnumber;44begin55Deg_C:=(5.
0/9.
0)*(Deg_F-32);66returnDeg_C;77endDegF_to_DegC;8/Functioncreated.
SQL>selectbody_temp,degf_to_degc(body_temp)2frompatient;BODY-TEMPDEGF_TO_DEGC(BODY_TEMP)99.
237.
333333100.
237.
888889103.
838.
888889一旦建立了存储函数,就可以永远使用它.
5.
2.
5将结果存储到表中以及调用存储过程或函数1.
将结果存储到表中虽然PL/SQL没有任何一个内部函数支持与用户的通信,但还是可以使用PL/SQL按以下方法给用户或另一个程序提供结果:(1)将信息写入用户或程序可查询的一个中间表中;(2)使用Oracle提供的DBMS_OUTPUT包中的过程或函数.
前面例子已经介绍了PL/SQL如何向中间表写东西.
当编译PL/SQL存储过程或函数时,PL/SQL可自动将错误信息写到开发人员可以查询的数据字典中.
如果要使用SQL*Plus进行输出,最好是使用DBMS_OUTPUT.
如果需要给用户或程序传送很多数据,采用将结果写入一个表中的方法会更好些.
2.
调用存储过程或函数调用存储过程或函数的方法如下:218Oracle8i数据库开发与专业应用在SQL*Plus中,可按下列方式使用execute命令(该语法适用于不带任何参数的存储过程).
executeshow_inserts;而在PL/SQL子程序中,可以简单地带着所需参数引用存储过程或函数.
5.
2.
6包包是一组相关的PL/SQL过程和函数.
像Ada程序语言一样,PL/SQL包是由包的说明部分和包体组成的.
可以建立特定应用的包(例如名为patient_data的包),它应包括操作和查询医院病人信息的相关过程和函数,同时也包括提供通用功能的过程和函数,诸如将局部信息从一个系统转换到另一个等同的系统.
1.
包的说明建立包的一般语法如下:CREATE[ORREPLACE]PACKAGEpackage-nameISdeclaration-sectionENDpackage-name变量定义如下:package-name:是所建立的包的名字,命名方法遵循Oracle数据库对象命名规则;declaration-section:由类型、变量、游标、过程和函数的说明组成.
表5-25是一个假定的Flugle学院信息系统的包的说明.
表5-25一个包的说明(specification)createorreplacepackageFlugleisfunctionregister_for_class(arg_student_IDINvarchar2,arg_class_IDINvarchar2)returnnumber;functionschedule_conflict(arg_student_IDINvarchar2,arg_class_IDINvarchar2)returnnumber;proceduredrop_class(arg_student_IDINvarchar2,arg_class_IDINvarchar2,statusOUTnumber);procedureassign_instructor(arg_class_IDINvarchar2,arg_instructorINvarchar2,statusOUTnumber);procedureassign_grade(arg_student_IDINvarchar2,arg_class_IDINvarchar2,arg_gradeINvarchar2,statusOUTnumber);functionstudent_GPA(arg_student_IDINvarchar2)returnnumber;END;第5章Oracle8数据库编程219这个Flugle包有六个项:三个过程(过程drop_class、过程assign_instructor和过程assign_grade)和三个函数(函数register_for_class、函数schedule_conflict和函数student_GPA).
当在脚本中建立包的说明或包体时,可使用OR_REPLACE子句.
Oracle还提供了DROPPACKAGE和DROPPACKAGEBODY语句,但OR_REPLACE子句可以不必记住在建立该包之前,是否已经取消了该包.
2.
包体的说明包体含有包的公用和专用元素,它隐藏了游标、过程和函数在实际中是如何实现的细节,这些细节对于开发者是隐藏的.
说明包体的语法如下:CREATEPACKAGEpackage-nameISdeclaration-sectionprocedure-bodies;function-bodies;initialization-sectionENDpackage-name;包的变量定义如下:package-name:是所建立的包的名字,命名方法遵循Oracle数据库对象命名规则;declaration-section:是由类型、变量和游标说明组成的;procedure-bodies:是由包说明中所说明的每一个过程的可执行部分组成;function-bodies:是由包说明中所说明的每一个函数的可执行部分组成;initialization-section:一个可选部分,当某个包是第一次引用时,就要执行它.
表5-26列出了Flugle包体的内容,它包含了作为包的组成部分的每个过程和函数的细节.
(续)createorreplacepackageFlugleis--Declaresomeexceptions.
schedule_conflict_existsexception;already_registeredexception;not_registeredexception;--Declarationvaluesforstatus.
conflicting_classesnumber:=-2;unsuccessfulnumber:=-1;normalnumber:=0;--Functionregister_for_class--functionregister_for_class(arg_student_IDINvarchar2,arg_class_IDINvarchar2)returnnumberisstatusnumber;表5-26说明一个包体220Oracle8i数据库开发与专业应用(续)counternumber;begin--Determineifthestudentisn'talreadyregisteredforthisclass.
selectcount(*)intocounterwherestudent_id=arg_student_idandclass_id=arg_class_id;ifcounter>0then----Thestudentisalreadyregisteredforthisclass.
--raisealready_registered;else----Thestudentisn'tregisteredforthisclass.
--ifschedule_conflic(arg_student_id,arg_class_id)=0theninsertintostudent_schedule(student_id,class_id)values(arg_student_id,arg_class_id);elseraiseschedule_conflict_exists;endif;endif;status:=normal;returnstatus;exceptionwhenschedule_conflict_existsthenraise_application_error(-20001,'Scheduleconflictexists');whenalready_registeredthenraise_application_error(-20002,'Studentisalreadyregisteredforclass');whenothersthennull;end;--Functionschedule_conflict--functionschedule_conflict(arg_student_IDINvarchar2,arg_class_IDINvarchar2)returnnumberis--Declareacursortolookforotherclasseswiththesameschedule--asthisone.
第5章Oracle8数据库编程221(续)cursorget_other_classesisselectSS.
Class_IDfromStudent_ScheduleSS,ClassCwhereSS.
Class_ID=C.
Class_IDand(C.
Semester,C.
School_Year,C.
Schedule_ID)=(selectSemester,School_Year,Schedule_IDfromClasswhereClass_ID=arg_class_ID);Conflict_Class_IDClass.
Class_ID%type;statusnumber;begin--Needtolookattheotherclassesinthestudent'sschedule--forthesamesemesterandschoolyear.
forget_other_classes_Recinget_other_classesloopfetchget_other_classesintoConflicting_Class_ID;exitwhenget_other_classes%notfound;endloop;closeget_other_classes;ifget_other_classes%rowcount>0thenstatus:=conflicting_classes;elsestatus:=normal;endif;returnstatus;end;--Proceduredrop_class--proceduredrop_class(arg_student_IDINvarchar2,arg_class_IDINvarchar2,statusOUTnumber)iscounternumber;begin--Verifythatthisclassreallyispartofthestudent'sschedule.
selectcount(*)intocounterfromstudent_schedulewhere222Oracle8i数据库开发与专业应用(续)student_id=arg_student_idandclass_id=arg_class_id;ifcounter=1thendeletefromstudent_schedulewherestudent_id=arg_student_idandclass_id=arg_class_id;endif;end;--Procedureassign_instructor--procedureassign_instructor(arg_class_IDINvarchar2,arg_instructor_IDINvarcahar2,statusOUTnumber)iscounternumber;begin--Determineifthisinstructorisassociatedwiththedepartment--thatoffersthisclass.
selectcount(*)intocounterfromInstructorI,ClassCwhereC.
Class_ID=arg_class_IDandI.
Instructor_ID=arg_instructor_IDandC.
Department_ID=I.
Department_ID;ifcounter=0thenstatus:=unsuccessful;else----Assignthisinstructortothisclass.
--updateclasssetInstructor_ID=arg_instructor_IDwhereClass_ID=arg_class_ID;status:=normal;endif;end;第5章Oracle8数据库编程223(续)--Procedureassign_grade--procedureassign_grade(arg_student_IDINvarchar2,arg_class_IDINvarchar2,arg_gtadeINvarchar2,statusOUTnumber)iscounternumber;begin--Deterifthestudentisregisteredforthisclass.
selectcount(*)intocounterfromstudent_schedulewherestudent_id=arg_student_idandclass_id=arg_student_id;ifcounter=0then----Thestudentisnottakingthisclass.
--raisenot_registered;else----Assignthegradeforthisclass.
--updatestudent_schedulesetgrade=arg_schedulewherestudent_id=arg_student_idandclass_id=arg_class_id;endif;exceptionwhennot_registeredthenraise_application_error(-21003,'Studentontregisteredforclass');whenothersthennull;end;--FunctionstudentGPA--functionstudent_GPA(arg_student_IDINvarchar2)returnnumberisGPAnumber;224Oracle8i数据库开发与专业应用(续)begin----Calculatetheaveragegradepointforthisstudentbasedonall--classesforwhichagradehasbeenassigned.
selectavg(decode(grade,'A+',4.
25,'A',4,'A-',3.
75,'B+',3.
25,'B',3,'B-',2.
75,'C+',2.
25,'C',2,'C-',1.
75,'D+',1.
25,'D'1,'D-',0.
75,'F',0))intoGPAfromstudent_schedulewherestudent_id=arg_student_id;returnGPA;end;end;一旦建立了Flugle包体,就可以调用包内的任何一个函数.
程序表5-27使用UPDATE语句给Class104200的教师设置为null.
后面的SELECT语句证明了该班没有安排教师.
在它的后面使用了一个匿名块,用于调用Assign_Instructor给班级104200安排一个教师E491.
当状态为0时,说明该过程执行是成功的.
最后的SELECT语句证明了该教师确实已经安排到这个班级.
表5-27从PL/SQL匿名块中引用包中的过程SQL>setserveroutputonSQL>SQL>updateclass2set3Instructor_ID=null4where5class_ID='104200';1rowupdated.
SQL>selectInstructor_ID2from3where4Class_ID='104200';INSTRUCTOR_IDSQL>declare22statusnumber;33begin第5章Oracle8数据库编程225(续)44dbms_output.
enable;555Flugle.
Assign_Instructor('104200','E491',status);66dbms_output.
put_line('Status:'||to_char(status));77end;8/Status:0PL/SQLproceduresuccessfullycompleted.
SQL>selectInstructor_ID2fromClass3where4Class_ID='104200';INSTRUCTOR_IDE4913.
设计一个用于数据库触发器的包可以从SQL*Plus脚本、PL/SQL子程序、客户机应用脚本(如OracleForm或PowerBuilder)以及数据库触发器中引用包中的过程或函数,但数据库触发器不能调用任何含有COMMIT、ROLLBACK或SAVEPOINT语句的存储过程、函数或包内子程序.
如果要从一个数据库触发器随意调用包的子程序,应该首先确保包中的过程或函数不进行确认或返回事项的操作.
关于数据库触发器的详细内容将在下一节介绍.
5.
2.
7附加PL/SQL数据类型在前面的介绍中,给出了一些PL/SQL编程的基本要素.
已经看到:PL/SQL支持所有在SQL中使用的数据类型.
PL/SQL还提供了以下几种附加数据类型,但这些数据类型在SQL语句中不能使用,它们是:(1)BOOLEAN;(2)BINARY_INTEGER,NATURAL和POSITIVE;(3)%TYPE;(4)%ROWTYPE;(5)PL/SQL表;(6)用户定义记录.
1.
BOOLEAN(布尔)数据类型PL/SQL所支持的附加数据类型中的一种是BOOLEAN,表5-28说明如何定义BOOLEAN变量,也可以用TRUE或FALSE对BOOLEAN变量进行初始化.
226Oracle8i数据库开发与专业应用表5-28说明一个BOOLEAN变量及对其进行初始化SQL>setserveroutputonSQL>SQL>declare2Payment_Is_Lateboolean:=TRUE;3begin44dbms_output.
enable;55ifPayment_Is_Latethen6dbms_output.
put_line('Thepaymentislate!
');7endif;88end;9/Thepaymentislate!
PL/SQLproceduresuccessfullycompleted.
在第2行,BOOLEAN变量Payment_Is_Late被初始化为TRUE.
在第5行计算Payment_Is_Late的值,因为在第5行等于TRUE,因此执行第6行.
在给BOOLEAN变量赋值之前,该变量的值是null(空).
在表5-29中用BOOLEAN表达式Day_Of_Month>3的值给BOOLEAN给BOOLEAN变量Payment_Is_Late赋值.
表5-29用BOOLEAN表达式给BOOLEAN变量赋值SQL>setserveroutputonSQL>SQL>declare2Payment_Is_Lateboolean;3Day_Of_Monthinteger;44begin55dbms_output.
enable;66selectto_number(to_char(sysdate,'DD')7intoDay_Of_Month8fromdual;99Payment_Is_Late:=Day_Of_Month>3;1010ifPayment_Is_Latethen11dbms_output.
put_line(/Thepaymentislate!
');12endif;1313end;14/ThePaymentislate!
PL/SQLproceduresuccessfullycompleted.
第5章Oracle8数据库编程2272.
BINARY_INTEGER(二进制整数)数据类型BINARY_INGEGER(二进制整数)数据类型是存储有符号整数,范围是从-2,147,483,647到2,147,483,647.
PL/SQL可提供另外两种BINARY_INTEGER的子类的数据类型,它们是:(1)NATURAL(自然数):可存储范围在0到2,147,483,647的整数;(2)POSITIVE(正整数):可存储范围在1到2,147,483,647的整数.
可以用NATURAL或INTEGER数据类型说明一个不带小数的变量,如循环次数计数器.
当给已说明为BINARY_INTEGER、NATURAL或POSITIVE的变量用实数赋值时,这个数字将被截除,表5-30给出了这样的一个例子.
表5-30用实数给PL/SQL整型变量赋值SQL>declare2Counternatural;33begin44dbms_output.
enable;55Counter:=103.
2;66dbms_output.
put_line('Counter:'||to_char(Counter,'999.
999'));77end;8/Counter:103.
0003.
%TYPE类型的使用PL/SQL对于引用Oracle表和列数据类型提供了两种符号,它们是:(1)用%TYPE说明一个变量,它与指定列(或前面所定义的变量)具有相同的数据类型;(2)用%ROWTYPE说明一个复合变量,其结构是指定表或游标的镜像.
以上两种数据类型有助于使PL/SQL代码与存在于Oracle数据字典中的表和列定义相结合.
为了定义与某列具有相同的数据类型的变量,根据下列语法定义%TYPE数据类型:variable-nametable-name.
column-name%TYPE;变量定义如下:variable-name:是要定义的PL/SQL变量;table-name.
column-name:是指定的列,它的数据类型将用于变量variable-name.
使用%TYPE的最大好处就是它可以维护PL/SQL代码所需的工作量,例如可以增加或减少列的宽度而不需要改变对依赖于该列的变量做任何说明.
4.
%ROWTYPE类型的使用可以用%ROWTYPE定义一个变量(实际上是一个记录),它的结构定义为某个被指定的表的结构.
用下列语法使用%ROWTYPE:228Oracle8i数据库开发与专业应用variable-nametable-name%ROWTYPE;变量定义如下:variable-name:是将要定义的PL/SQL变量;table-name:是指定的表,它与variable-name相对应.
例如,一个名为Instructor_Rec的记录被说明为Instructor%ROWTYPE,结果Instructor_Rec的字段分别具有与Instructor表中的各列相同的名字和数据类型,见表5-31.
表5-31在一条SELECT语句中使用%ROWTYPESQLWKS>declare2>3>Instructor_RecInstructor%ROWTYPE;4>5>begin6>7>dbms_output.
enable;8>9>select*10>intoInstructor_Rec11>fromInstructor12>where13>Instructor_ID='P331';14>15>dbms_output.
put_line('InstructorID:'||Instructor_Rec.
Instructor_ID);16>dbms_output.
put_line('LastName:'||Instructor_Rec.
Last_Name);17>dbms_output.
put_line('FirstName:'||Instructor_Rec.
First_Name);18>19>end;20>/Statementprocessed.
InstructorID:P331LastName:POULSONFirstName:RANIER可以看到从15到17行variable-name.
field-name引用了一个%ROWTYPE类型记录的字段.
variable-name是所说明的%ROWTYPE型变量的名字,field-name是在variable-name的说明中所指定的表中的一个列的名字.
尽管可以在一条SELECT语句中引用由%ROWTYPE数据类型说明的一条记录,但不能使用INSERT语句引用整个记录.
例如,PL/SQL拒绝执行下列INSERT语句:SQL>declare2Patient_RecPatient%ROWTYPE;33begin44Patient_Rec.
Patient_ID:='HHH111';5Patient_Rec.
Body_Temp_Deg_F:=102.
7;第5章Oracle8数据库编程22966insertintoPatient7(Patient_ID,Body_Temp_Deg_F)8values9Patient_Rec;1010end;11/Patient_Rec;*ERRORatline9:ORA-06550:line9,column1:PLS-00103:Encounteredthesymbol"PATIENT_REC"WhenexpectingoneofthefollowanaggregateResumingparseatline9,column12.
必须指定与在INSERT语句中所指定数据列相对应的Patient_Rec记录的每一个组成部分.
如果在同一表中用%ROWTYPE数据说明了两个变量,那么可以将一个变量值赋给另一个变量.
表5-32将New_Patient变量赋值到ER_Patient变量,从而说明了这个概念.
表5-32给%ROWTYPE型PL/SQL变量赋值SQL>declare22New_PatientPatient%ROWTYPE;3ER_PatientPatient%ROWTYPE;44begin55dbms_output.
enable;66select*7intoNew_Patient8fromPatient9where10Patient_ID='ZZ0123';1111ER_Patient:=New_Patient;1212dbms_output.
put_line('ER_Patient.
Body_Temp_Deg_F:'||13to_char(ER_Patient.
Body_Temp_Deg_F));1414end;15/ER_Patient.
Body_Temp_Deg_F:98.
6230Oracle8i数据库开发与专业应用但是,如果两个%ROWTYPE变量指向的不是同一个数据表,即使这两个表是统一的,也不能将一个%ROWTYPE变量赋给另一个%ROWTYPE变量.
表5-33基于不同的%ROWTYPE变量不能互相赋值SQL>createtableIdentical_Patientas2select*fromPatient;Tablecreated.
SQL>setserveroutputonSQL>SQL>declare22New_PatientPatient%ROWTYPE;3ER_PatientIdentical_Patient%ROWTYPE;44begin55dbms_output.
enabled;66select*7intoNew_Patient8fromPatient9where10Patient_ID:='ZZ0123';11ER_Patient:=New_Patient;1212dbms_output.
put_line('ER_Patient.
Body_Temp_Deg_F:'||13to_char(ER_Patient.
Body_Temp_Deg_F));1414end;15/declare*ERRORatline1:ORA-06550:line11,column15:PLS-00382:expressionisofwrongtypeORA-06550:line11,column1:PL/SQL:Statementignored5.
更复杂的数据类型:Table(表)和Records(记录)PL/SQL支持两种更复杂的数据类型:table和records.
table和records这样的对象首先要说明一个数据类型,然后基于该数据类型再说明实际的PL/SQL表或记录.
可以将PL/SQL表看作一个数组:它由单一字段组成,也可以不说明PL/SQL所含元素数的上限,它的范围是动态的.
PL/SQL表(PL/SQLtable)是由相同类型组成,用索引排序的元素的集合体.
Oracle将PL/SQL表这种结构称为表是不合理的,将其称为数组要更合适一些.
PL/SQL表与数据库不同,它是由单列组成的.
使用数组,可以通过索引方式得到PL/SQL表的值.
第5章Oracle8数据库编程231PL/SQL表和数据库具有各自的特性和应用范围,它们是两类不同的对象.
一个用户定义记录提供了比用%ROWTYPE进行说明更为灵活的方式.
当出现下列两种情况时,应考虑使用用户记录.
(1)只需要一个表中的列的子集;(2)也许要在一条记录中存储相关的或导出的记录.
如果说明某个与数据库表相关的用户定义记录类型,就可以在数据库表中使用%TYPE数据类型确定相应数据列的每个字段.
在出现不可避免的数据库改变时,可以减少对PL/SQL代码维护的工作量.
6.
PL/SQL表的说明用下列语法说明PL/SQL表的类型:TYPEtype-nameISTABLEOFtable-name.
column-name%TYPEINDEXBYBINARY-INTEGER;变量定义如下:type-name:是要说明的名字;table-name.
column-name:指定列使它的数据类型以type-name数据类型为基准.
说明PL/SQL的类型以后,就可在该类型基础上说明变量.
例如在表5-34中有一个PL/SQL匿名块,Class_ID_Tab被认为是在Class表中列Class_ID的表.
游标FORLOOP从Class表选择每项Class_ID,并将它赋值给Class_ID_Tab中的一个元素.
在表5-34中使用SQLWorksheet执行.
表5-34PL/SQL表的应用SQLWKS>setserveoutputonServerOutputONSQLWKS>declare2>3>typeClass_ID_TypeistableofClass.
Class_ID%TYPE4>indexbybinary_integer;5>6>Class_ID_TabClass_ID_Type;7>ibinary_integer:=0;8>final_countbinary_integer;9>10>begin11>12>dbms_output.
enable;13>14>forClass_ID_Recin(selectClass_IDfromClass)loop15>16>i:=i+1;17>Class_ID_Tab(i):=Class_ID_Rec.
Class_ID;18>19>endloop;20>final_count:=I;232Oracle8i数据库开发与专业应用(续)21>22>23>foriin1.
.
final_countloop24>25>dbms_output.
put_line('Class_ID_Tab('||[ccc]to_char(i)26>Class_ID_Tab(i));27>endloop;28>29>end;30>/Statementprocessed.
Class_ID_Tab(1)=104200Class_ID_Tab(2)=104500Class_ID_Tab(3)=109100Class_ID_Tab(4)=120200Class_ID_Tab(5)=110300Class_ID_Tab(6)=108300Class_ID_Tab(7)=108400Class_ID_Tab(8)=108600Class_ID_Tab(9)=103400Class_ID_Tab(10)=103600可将PL/SQL表作为一个参数传递给一个过程或函数.
使用PL/SQL表,也可传递一个BINARY_INTEGER变量,用于指定PL/SQL表中元素的个数.
表5-35给出一个例子,该例中的过程返回值包含所有课程附加费超过50美元的课程代码(Course_ID)的PL/SQL表.
表5-35返回一个PL/SQL表SQLWKS>declare2>3>typeCourse_ID_TypeistableofCourse.
Course_ID%TYPE4>indexbybinary_integer;5>Course_ID_TabCourse_ID_Type;6>7>ibinary_integer:=0;8>Total_Numberbinary_integer;9>10>procedureGet_Course_IDs(Num_Rowsbinary_integer,11>Course_ID_TableoutCourse_IDType)is12>13>ibinary_integer:=0;14>15>begin16>17>forCourse_ID_Recin(selectCourse_IDfromCourse18>whereAdditional_Fees>50)loop19>20>i=i+1;第5章Oracle8数据库编程233(续)21>Course_ID_Table(i):=Course_ID_Rec.
Course_ID;22>23>endloop;24>25>Num_Rows:=i;26>27>endGet_Course_IDs;28>29>--Mainblock.
30>31>begin32>33>dbms_output.
enable;34>35>Get_Course_IDs(Total_Number,Course_ID_Tab);36>37>foriin1.
.
Total_Numberloop38>exitwhenCourse_ID_Tab(i)=NULL;39>dbms_output.
out_line('Course_ID_Tab('||to_char(i)Course_ID_Tab(i));40>41>endloop;42>43>end;44>/Statementprocessed.
Course_ID_Tab(1)=101Course_ID_Tab(2)=189Course_ID_Tab(3)=101Course_ID_Tab(4)=178Course_ID_Tab(5)=177Course_ID_Tab(6)=174Course_ID_Tab(7)=181Course_ID_Tab(8)=501在表5-35中,第1行是对匿名块进行说明,第2行是说明Course_ID_Type的类型,第10行开始是说明过程Get_Course_IDs的类型,第13行对索引Course_ID_Type的PL/SQL表初始化为0,匿名块的执行部分是从第31行开始的,过程Get_Course_IDs是在第35行匿名块的执行部分中被执行的.
PL/SQL对PL/SQL表的索引范围没有限制,可以从-100,0,1或任何认为合适的其他数值开始.
7.
用户定义记录的说明用户定义记录的使用方法与PL/SQL表的使用方法非常相似:先定义记录的数据类型,然后在新数据类型基础上说明变量.
按以下方式说明记录类型:234Oracle8i数据库开发与专业应用TYPEtype-nameISrecord(field-namefield-datatype[NOTNULL][initial-value];.
.
.
field-namefield-datatype[NOTNULL][initial-value]);对说明类型所使用的变量定义如下:type-name:是被说明的记录类型名;field-name:是字段名,命名方法遵循Oracle数据库对象命名规则;field-datatype:是字段的数据类型,它可以看作是一个被指定的PL/SQL数据类型(如NUMBER或BOOLEAN类型),或可引用某列的数据类型(用%TYPE指定的类型);initial-value:是初始值,如果将field-name说明为NOTNULL,则必须给它赋初值.
使用用户定义记录的好处之一是:可以说明一个字段,用于存储相关数据库中没有储存的,从一个记录中导出数据.
表5-36是有关说明用户定义记录的范例.
该例中说明一个记录类型名为Patient_Rec_Type,它是由三个字段组成的:Patient_ID、Body_Temp和Bed_Number.
前两个变量存在于Patient表中,但在表中Body_Temp有一个不同的字Body_Temp_Deg_F,第三个字段Bed_Number在Patient表中不存在.
表5-36使用用户定义记录类型SQL>declare22typePatient_Rec_Typeisrecord3(Patient_IDPatient.
Patient_ID%TYPE,4Body_TempPatient.
Body_Temp_Deg_F%TYPE,5Bed_Numbervarchar2(4));66Patient_RecPatient_Rec_Type;77begin88dbms_output.
enable;99Patient_Rec.
Patient_ID='ZZ0123';10Patient_Rec.
Body_Temp:=98.
6;11Patient_Rec.
Bed_Number:='A123';1212dbms_output.
put_line('PatientID:'||Patient_Rec.
Patient_ID);13dbms_output.
put_line('Body_Temp:'||to_char(Patient_Rec.
Body_Temp));14dbms_output.
put_line('BedNumber:'||Patient_Rec.
Bed_Number);1515insertintoPatient16(Patient_ID,Body_Temp_Deg_F)17values18(Patient_Rec.
Patient_ID,Patient_Rec.
Body_Temp);1919end;20/PatientID:ZZ0123Body_Temp:98.
6BedNumber:A123第5章Oracle8数据库编程2355.
2.
8设定变量默认值在默认情况下,不管任何时候进入过程、函数或匿名块时,所有变量的初值均为NULL.
在PL/SQL说明部分可使用两种方法对变量初始化:variable-namedata-type:=initial-value;或variable-namedate-typeDEFAULTinitial-value;这里有一个匿名块,它使用两种方法对变量进行初始化:SQL>declare22inatural:=33;3my_stringvarchar2(30)default'JACKSON'44begin55dbms_output.
enable;66end;7/PL/SQLproceduresuccessfullycompleted.
变量设定默认值可以使代码更容易理解和维护.
通过设定默认值,可以减少程序如何运行的一些可能性.
5.
3PL/SQL编程的高级技术本节主要介绍的内容有:如何在一个PL/SQL子程序中处理错误,如何定义例外处理程序用以处理Oracle错误和用户定义例外,以及一些预先定义例外的例子;在PL/SQL子程序中说明和使用游标,用以从数据库中检索多个行;使用PL/SQL创建数据库触发器,介绍如何使用触发器对数据进行有效性检验、增强安全性或记录对一个表进行的修改.
5.
3.
1在PL/SQL中处理错误在《Oracle错误信息和代码手册》(OracleErrorMessageandCodesmanual)中,列出了除特定的操作错误之外的所有错误代码和信息,在某些地方,应用系统也许会遇到其中的某种错误.
在PL/SQL中,将Oracle错误称为例外(exception),其中一些例外有预定义名,可以在PL/SQL子程序中引用.
除了预定义Oracle例外之外,也可以在PL/SQL子程序中定义特别应用(application-specific)例外.
例外是预定义的或用户定义的、可由OracleRDBMS自动激发(raised)或由PL/SQL子程序特意激发的应用程序错误.
PL/SQL子程序处理错误的一种方法是:在每条SQL语句后面进行检查是否有任何Oracle代码错误,这种解决问题的方式会导致子程序将无法继续运行.
另一种方法是:使236Oracle8i数据库开发与专业应用用PL/SQL对特定例外指定应该要进行的处理.
PL/SQL子程序的这部分内容被称为PL/SQL子程序的例外部分(exceptionsection).
当PL/SQL子程序的执行过程中出现一个Oracle错误,就称为"激发(raised)"出了一个预定义例外,还可以在PL/SQL代码中的适当位置使用RAISE语句激发出一个用户定义例外.
例如,假设编写了一段PL/SQL子程序,用于将展开文件(flatfile)的数据装入数据库的表中.
如果展开文件中有无效数字(例如3.
14写成3.
1A),当PL/SQL子程序试图用无效数字插入一行时,就会激发预定义例外.
5.
3.
2例外部分例外部分是PL/SQL子程序的可选部分,它将告诉PL/SQL如何处理特定的例外.
例外部分语法如下:EXCEPTIONWHENexception-name1THENPL/SQL-statement;.
.
.
WHENexception-nameNTHENPL/SQL-statement;.
.
.
[WHENOTHERSTHENPL/SQL-statement;]END;变量定义如下:exception-name1到exception-nameN:是预定义和用户定义例外的名字;PL/SQL-statement:是激发例外时所执行的一条或多条PL/SQL语句.
为了进一步说明,表5-37是一个带有例外部分的PL/SQL块.
注意例外部分包含两个例外处理程序:一个是预定义例外(TOO_MANY_ROWS例外,第11行);另一个是对所有其他例外处理(用OTHERS表示,在第13行).
表5-37处理TOO-MANY-ROWS例外SQL>declare22Course_RecCourse%ROWTYPE;33begin44dbms_output.
enable;55select*6intoCourse_Rec7from8where9Department_ID='BIO';10第5章Oracle8数据库编程237(续)10exception11whenTOO_MANY_ROWSthen12dbms_output.
put_line('TOO-MANY-ROWSraised-useacursor');13whenOTHERSthen14NULL;15end;16/TOO_MANY_ROWSraised-useacursor如果删除例外处理OTHERS,就会因没有出现例外而激发例外,此时PL/SQL返回错误信息.
表5-38中一个变量最多存储5个字符,此例中将一个有18个字符的字符串赋值给该变量,因此产生Oracle错误.
表5-38例外部分不能处理OTHERS例外SQL>declare22xyzvarchar2(5);33begin44dbms_output.
enable;55xyz:='Thiswillnotfit!
';66exception77whenTOO_MANY_ROWSthen8dbms_output.
put_line('TOO_MANY_ROWSExceptionRaised');9dbms_output.
put_line('Occurredinanonymousblock');1010end;11/declare*ERRORatline1:ORA-06502:PL/SQL:numericorvalueerrorORA-06512:atlint55.
3.
3预定义例外不论是预定义还是用户定义的例外,所有例外均可进行分类.
预定义例外可以自动激发,例如,用SQL语句引用一个因不存在表而引出的Oracle错误.
在某种情况下,PL/SQL子程序中可能有一条SQL语句,该语句没有返回行,此时将会激发NO_DATA_FOUND例外.
预定义例外的名字都富有含义.
在开发Oracle应用时可能会遇到以下几种预定义例外:(1)DUP_VAL_ON_INDEX;(2)INVALID_NUMBER;(3)TOO_MANY_ROWS;238Oracle8i数据库开发与专业应用(4)VALUE_ERROR.
下面将说明每种预定义例外在什么情况下会被触发.
1.
DUP_VAL_ON_INDEX例外当SQL语句要在存在唯一索引的列中建立重复数值时,将会激发DUP_VAL_ON_INDEX例外.
为了进一步说明,在表5-39中有一个匿名PL/SQL块,该块要求对Course表进行更新,使Course_ID数据项有很多相同的行,因此激发了DUP_VAL_ON_INDEX例外.
表5-39处理DUP_VAL_ON_INDEX例外SQL>declare22begin33dbms_output.
enable;44updateCourse5set6Department_ID='BIO';7Course_ID='101';88exception9whenDUP_VAL_ON_INDEXthen10dbms_output.
put_line('DUP_VAL_ON_INDEXexceptionraised');11end;12/DUP_VAL_ON_INDEXexceptionraisedPL/SQLproceduresuccessfulluycompleted.
2.
INVALID_NUMBER例外当SQL语句指定无效数字时,将会激发INVALID_NUMBER例外.
表5-40给出了一个匿名PL/SQL块,它可对Course表中的AdditionalFee列进行更新,由于To_Number函数要将字符串型变量Bogus_Value变换为数值型,因此而激发例外.
表5-40处理INVALID_NUMBER例外SQL>declare22Bogus_Valuevarchar2(30):='NOTANUMBER';33begin44dbms_output.
enable;5updateCourse6set7Additional_Fees=to_number(Bogus_Value);88exception9whenINVALID_NUMBERthen10dbms_output.
put_line('INVALID_NUMBERexceptionraised');11end;12/INVALID_NUMBERexceptionraisedPL/SQLproceduresuccessfullycompleted.
第5章Oracle8数据库编程2393.
NO_DATA_FOUND例外当SELECT语句没有返回任何行时将会激发NO_DATA_FOUND例外,见表5-41.
表5-41在没有例外处理程序情况下出现NO_DATA_FOUND例外SQL>declare22Course_RecCourse%ROWTYPE;3begin44dbms_output.
enable;55select*6intoCourse_Rec7fromCourse8where9Course_ID='777';1010end;11/declare*ERRORatline1:ORA-01403:nodatafoundORA-06512:atline5当给NO_DATA_FOUND增加一个例外处理程序后(在11行中),在这种调用环境中,PL/SQL不再出现nodatefound错误,见表5-42.
表5-42处理NO_DATA_FOUND例外SQL>declare22Course_RecCourse%ROWTYPE;3begin44dbms_output.
enable;55select*6intoCourse_Rec7fromCourse8where9Course_ID='777';1010exception11whenNO_DATA_FOUNDthen12dbms_output.
put_line('Nodatareturned');13whenOTHERSthen14NULL;15end;16/NodatareturnedPL/SQLproceduresuccessfullycompleted.
240Oracle8i数据库开发与专业应用4.
TOO_MANY_ROWS例外在PL/SQL环境中,一条SELECT语句检索多行数据时就会激发TOO_MANY_ROWS例外.
为了从一个查询中检索任意数目的行,可使用游标,可将游标看成是查询返回结果的窗口.
表5-43给出对于TOO_MANY_ROWS例外如何使用例外处理程序的例子.
表5-43处理TOO_MANY_ROWS例外SQL>declare22Course_RecCourse%ROWTYPE;33begin44dbms_output.
enable;55select*6intoCourse_Rec7fromCourse8where9Department_ID='BIO';1010exception11whenTOO_MANY_ROWSthen12dbms_output.
put_line('TOO_MANY_ROWSraised-useacursor');13whenOTHERSthen14NULL;15end;16/TOO_MANY_ROWSraised-useacursorPL/SQLproceduresuccessfullycompleted.
5.
VALUE_ERROR例外激发VALUE_ERROR例外的多数情况与截断和转换误差有关.
例如表5-44给出一个PL/SQL块(始于第1行),它给定义为VARCHAR2(5)的变量用多于5个字符的字符串赋值.
表5-44处理VALUE_ERROR例外SQL>declare22xyzvarchar2(5);33begin44dbms_output.
enable;55xyz:='Morethan5characters';66exception7第5章Oracle8数据库编程241(续)7whenVALUE_ERRORthen8dbms_output.
put_line('VALUE_ERRORraised');99whenOTHERSthen10NULL;1111end;12/VALUE_ERRORraised5.
3.
4例外说明除预定义之外,还可定义应用指定的例外,可用下列形式对这种例外进行说明:exception-nameEXCEPTION;变量exception-name是一个被说明的例外,它的命名遵循PL/SQL对象命名规则.
表5.
45说明了一个名为Life_Threatening_Fever的例外,如果病人的体温超过华氏106度就激发该例外.
表5-45说明一个应用例外SQL>declare22Life_Threatening_Feverexception;3Patient_IDPatieng.
Patient_ID%TYPE;44begin55dbms_output.
enable;66forPatient_Recin7(selectPatient_ID,Body_Temp_Deg_FfromPatient)loop88ifPatient_Rec.
Body_Temp_Deg_F>106.
0then9Patient_ID:=Patient_Rec.
Patient_ID;10raiseLife_Threatening_Fever;1111endif;12endloop;1313exception1414whenLife_Threatening_Feverthen15dbms_output.
put_line(Patient_ID||'hasalife'||16'threateningfever!
');17end;18/GG9999hasalifethreateningfever!
242Oracle8i数据库开发与专业应用5.
3.
5成功或失败:查看SQLCODE和SQLERRMSQLCODE是一个预定义符号,它包含当前执行的PL/SQL语句的Oracle错误状态.
如果SQL语句执行中没有错误,则SQLCODE为0.
SQLERRM是PL/SQL符号,它包含与SQLCODE相关的错误信息.
如果SQL语句执行成功,则SQLCODE等于0,且SQLERRM包含一个字符串ORA-0000:normal,successfullycompletion,见表5-46.
表5-46引用SQLCODE和SQLERRMSQL>declare22begin33dbms_output.
enable;44dbms_output.
put_line('SQLCODE:'||to_char(SQLCODE));5dbms_output.
put_line('SQLERRM:'||to_char(SQLERRM));66end;7/SQLCODE:0SQLERRM:ORA-0000:normal,successfullycompletion如果确实出现一个错误,SQLCODE和SQLERRM就会分别产生代码和信息,见表5-47的输出部分.
表5-47在例外部分引用SQLCODE和SQLERRMSQL>declare2Class_RecClass%ROWTYPE;33begin44dbms_output.
enable;55select*6intoClass_Rec7fromClass;88exception9whenOTHERSthen10dbms_output.
put_line('SQLCODE:'||to_char(SQLCODE));11dbms_output.
put_line(SQLERRM);12end;13/SQLCODE:-1422ORA-01422:exactfetchreturnsmorethanrequestednumberofrowsPL/SQLproceduresuccessfullycompleted.
第5章Oracle8数据库编程2435.
3.
6用RAISE_APPLICATION_ERROR返回错误Oracle在DBMS-STANDARA包中提供一个名为RAISE-APPLICATION-ERROR的过程.
SQL*Plus、PL/SQL子程序或客户机应用程序调用该过程,该过程则返回应用特定(application-specific)错误信息.
Oracle的用户定义的错误代码使用范围是-20000到20999.
例如,表5-48给出的PL/SQL块,它说明一个例外,名为Fever_Out_of_Range.
游标FORLOOP(第6行)读取Patient表中的每一行,如果病人的体温超过华氏115度,就会激发Fever_Out_of_Range例外(第8行).
在例外部分,对Fever_Out_of_Range的例外处理程序调用了RAISE_APPLICATION_ERROR,并传递给它一个错误代码-20000和相关的错误信息(第14行).
表5-48激发一个应用特定例外SQL>declare22Fever_Out_of_Rangeexception;3Patient_IDPatient.
Patient_ID%TYPE;44begin55dbms_output.
enable;66forPatient_Recin7(selectPatient_ID,Body_Temp_Deg_FfromPatient)loop88ifPatient_Rec.
Body_Temp_Deg_F>115.
0then99raiseFever_Out_of_Range;10endif;11endloop;1212exception1313whenFever_Out_of_Rangethen14raise_application_error(-20000,15'Feverisoutoftherange65Deg.
Fto115Deg.
F');1616end;17/declare*ERRORatline1:ORA-20000:Feverisoutoftherange65Deg.
Fto115Deg.
FORA-06512:atline145.
3.
7使用游标检索数据游标(cursor)是在编程中,用一条SELECT语句能检索任意数量的行的一种结构.
在使用SQL*Plus或SQLWorksheet时,可能要执行一个不考虑返回行数目的查询,即244Oracle8i数据库开发与专业应用检索出零个、一个或一千个行都没关系.
但是,PL/SQL子程序中有一条SELECT语句(不管该子程序是匿名块、存储过程、还是触发器)检索到多个数据行时,则Oracle返回一条错误信息.
显然系统具有检索多行数据的功能是非常必要的,要达到这一功能就必须利用某些结构,因此Oracle提供了一种相应的资源,这就是游标.
像SQL*Plus这样的Oracle工具可自动建立和使用游标.
表5-49显示用一条SELECT语句检索多个行时,Oracle是如何返回错误信息的.
表5-49SELECT语句返回多个行时,Oracle产生错误的信息SQL>declare22Instructor_IDInstructor.
Instructor_ID%TYPE;3Last_NameInstructor.
Lase_Name%TYPE;4First_NameInstructor.
First_Name%TYPE;55begin66selectInstructor_ID,Last_Name,First_Name7intoInstructor_ID,Last_Name,First_Name8fromInstructor9orderbyInstructor_ID1010end;11/declare*ERRORatline1:ORA-01422:exactfetchreturnsmorethanrequestednumberofrowsORA-06512:atline6图5-2一个游标的实例——活动集InstructorIDLastNameFirstNameA612NILANDMARTINAB331BILLINGSBENJAMINB391BATESJOSEPHD201DANIELSLAURAD944RESTONRAPHAELE301EDWARDSSAMANTHAE405CHANGROGERE491RICHARDSONNANCYG331TORRESPETERJ505JASONJERROLD第5章Oracle8数据库编程245可以将游标看作是一组查询结果中的一个窗口(见图5-2).
可按以下四个步骤使用游标:(1)说明(declare)游标:给游标起名字,并且与SELECT语句在语法上相关联;(2)打开(open)游标:OracleRDBMS执行与游标相关的查询,并确定所限定的行(活动集);(3)用游标提取数据行:将每一行的值返回到PL/SQL子程序环境中,一次返回一行;(4)关闭(close)游标:释放所有Oracle占用的与游标相关的资源.
这是一个用于确定某一指定班与学生的活动安排是否有冲突的存储函数.
函数Schedule_Conflict有两个参数:Student_ID和Class_ID.
可以通过查看学生当前活动安排与所指定的班是否占据了相同的时间,用以确定是否存在冲突,完成这项查询可使用游标.
表5-50给出该函数的全部文本.
表5-50在存储函数中使用游标SQL>createorreplacefunctionschedule_conflict(arg_student_IDINvarchar2,2arg_class_IDINvarchar2)3returnnumberis44conflicting_classesnumber:=-1;5normalnumber:=0;66cursorget_other_classesis7selectSS.
Class_ID8fromStudent_ScheduleSS,ClassC9where10SS.
Class_ID=C.
Class_IDand11(C.
Semester,C.
School_Year,C.
Schedule_ID)=12(selectSemester,School_Year,C.
Schedule_ID13fromClass14where15Class_ID=arg_class_ID);1616Conflicting_Class_IDClass.
Class_ID%TYPE;17statusnumber;1818begin19--Needtolookattheotherclassesinthestudent'sschedule20--forthesamesemesterandschoolyear.
2121openget_other_classes;2222loop2323fetchget_other_classesintoConflicting_Class_ID;24exitwhenget_other_classes%notfound;2525endloop;2626ifget_other_classes%rowcount>0then246Oracle8i数据库开发与专业应用(续)27status:=conflicting_classes;28else29status:=naomal;30endif;3131closeget_other_classes;3232returnstatus;3333end;34/Functioncreated.
SQL>selectStudent_ID,Class_ID2fromStudent_Schedule3where4Student_ID='10231311';STUDENT_IDCLASS_ID1023131110420010231311104500SQL>selectschedule_conflict('102311','104200')fromdual;SCHEDULE_CONFLICT('10231311''104200')现在分析这个游标的每个细节.
首先从第6行开始,get_other_classes游标说明为两个表之间的连接:Student_Schedule表和Class表;第二,在存储函数的可执行部分打开游标(第21行);第三,循环语句从游标中提取行,直到没有行可被检索为止(第23行).
在表5-50的最后可以看到:Student_Schedule表的查询显示出Student_ID10231311注册了两个班104200和104500.
在最后的SELECT语句中调用了该函数,用以检查104200班对于学生10231311是否有冲突.
当然是有冲突的,因为该生已经参加了该班,因此,函数返回值为-1,它表示这样的状态:有冲突的班.
1.
说明游标在使用每个游标之前,必须对它进行说明.
说明游标意味着给它起个名字,并指定与游标相关的SELECT语句.
在PL/SQL中说明游标的语法如下:CURSORcursor-name[(parameter1parameter1-datatype[:=default1],.
.
.
parameterNparameterN-datatype[:=defaultN])]ISselect-stmt第5章Oracle8数据库编程247各变量定义如下:cursor-name:是游标的名字,并且它的命名方法遵循Oracle对象命名的限制;parameter1:是第一个参数名;parameter1-datatype:是parameter1的数据类型;default1:是parameter1的一个可选默认值;parameterN:是游标的第N个参数名;parameterN-datatype:是parameterN的数据类型;defaultN:是parameterN的一个可选默认值;select-stmt是一条有效的SELECT语句,它与所说明的游标相关联.
表5-51给出两个不同的游标,第一个游标有三个没有默认值的参数,第二个游标有三个确定默认值的参数.
表5-51参数带有默认值和不带默认值的游标cursorpatients_with_hypertension(patient_agenumber,normal_dyastolic,normal_systolic)isselectpatient_id,age,dyastolic,systolicfrompatientwheredyastolic>normal_dyastolic*(age+200)/200andsystolic>normal_systolic*(age+200)/200;cursorpatients_with_hypertension(patient_agenumberdefault55,normal_dyastolicnumberdefault70,normal_systoicnumberdefault130)isselectpatient_id,age,dyastolic,systolicfrompatientwheredyastolic>normal_dyastolic*(age+200)/200andsystolic>normal_systolic*(age+200)/200;如果使用Oracle预编译程序(如Pro*C),需要使用一个游标,通过SELECT语句检索多行数据.
2.
打开游标从一个游标中取出行之前,首先必须打开游标.
当游标被打开时,可执行SELECT语句,并构成了所限定行的一个列表,这些行被称为一个活动集(activeset).
如果打开一个不带任何参数的游标,语法非常简单:openmy-cursor如果说明的游标带有参数,当打开游标时必须给每个参数提供一个PL/SQL变量或直接值,见表5-52.
248Oracle8i数据库开发与专业应用表5-52说明并打开带有参数的游标SQL>declare22cursorpatients_with_hypertension3(patient_agenumber,4normal_dyastolicnumber)is5selectpatient_id6frompatient7where8dyastolic>normal_dyastolic*(age+200)/200and9systolic>180;1010Patient_IDPatient.
Patient_ID%type;1111begin1212openpatients_with_hypertension(45,80);1313end;14/PL/SQLproceduresuccessfullycompleted.
如果已经说明一个带有参数的游标,并确定了参数的默认值,就不需要再给每个参数定义PL/SQL变量或直接值,见表5-53.
表5-53游标参数的默认值SQL>declare22cursorpatients_with_hypertension3(patient_agenumberdefault55,4normal_dyastolicnumberdefault70,5normal_systoicnumberdefault130)is6selectpatient_id7frompatient8where9dyastolic>normal_dyastolic*(age+200)/200and10systolic>normal_systolic*(age+200)/200;1111Patient_IDPatient.
Patient_ID%type1212begin1313dbms_output.
enable;1414openpatients_with_hypertension;1515loop16第5章Oracle8数据库编程249(续)16fetchpatients_with_hypertension17intoPatient_ID;18exitwhenpatients_with_hypertension%notfound;1919dbms_output.
put_line(patient_record.
patient_id);2020endloop;2121end;22/N3393PL/SQLproceduresuccessfullycompleted.
如果说明了带有参数的游标,但没有确定参数默认值,此时就必须给每项参数提供PL/SQL变量或直接值.
表5-54给出一个实例,该例中没定义游标所需的参数,则Oracle拒绝执行游标语句.
表5-54当游标参数没有设定时Oracle返回一条错误SQL>declare22cursorpatients_with_hypertension3(patient_agenumber,4normal_dyastolicnumber5normal_systolicnumber)is6selectpatient_id7frompatient8where9dyastolic>normal_dyastolic*(age+200)/200and10systolic>180;1111Patient_IDPatient.
Patient_ID%type;1212begin1313openpatients_with_hypertension;1414end;15/declare*ERRORatline1:ORA-06550:line13,column1:PLS-00306:wrongnumberortypesofargumentsincallto'PATIENTS_WITH_HYPERTENSION'ORA-06550:line13,column1:PL/SQL:SQLStatementignored250Oracle8i数据库开发与专业应用3.
从游标取出行一旦打开游标,就可以进行查询,并指定了所限定的行.
要取出行必须执行FETCH语句,它可取出在游标的SELECT语句中所指定的每个列的值,并可将这些数值放入PL/SQL变量中.
一般可在一个循环中取行.
为了进一步说明,表5-55有一个匿名PL/SQL块,该PL/SQL块可从Instructor表中取出行.
表5-55从一个游标取出行SQL>declare22Instructor_IDInstructor.
Instructor_ID%type;3Last_NameInstructor.
Last_Name%type;4First_NameInstructor.
First_Name%type;55cursorger_instructorsis6selectInstructor_ID,Last_Name,First_Name7fromInstructor8orderbyInstructor_ID;99begin1010dbms_output.
enable;1111openget_instructors;1212loop1313fetchget_instructorsinto14Instructor_ID,Last_Name,First_Name;15exitwhenget_instructors%notfound;1616dbms_output.
put_line(Instructor_ID);1717endloop;1818end;19/A612B331B391D201D944E301E405E491G331J505L391M101P331R983S131T149W490Y561PL/SQLproceduresuccessfullycompleted.
第5章Oracle8数据库编程251当从游标取到结束行时,可使用EXIT跳出循环,它的语法是:EXIT[label][whencondition]变量定义:label:是任选的标号名,用来指定所要跳出的循环;condition:是一个返回Boolean值的PL/SQL条件.
与游标说明有关的四个特殊属性是:%ROWCOUNT、%FOUND、%NOTFOUND、%ISOPEN,这些属性是在游标名字的后面使用.
要用EXIT语句结束一个循环,可按下列方式引用游标的%NOTFOUND属性:exitwhenget-instructors%notfound;4.
关闭游标使用后必须关闭游标,主要是因为:为了应用一组不同的参数值重新打开游标;为了释放被游标占用的资源.
如果PL/SQL程序没有关闭游标,当子程序中断与数据库的连接时,Oracle可终止或使用DISCONNECT关闭游标.
关闭游标很简单,即:closeget-instructors;表5-56通过关闭游标的方法,用一组不同的参数值改变游标参数,并重新打开游标.
它使用patient_with_hypertension游标来说明这一过程.
首先将age设置为50、normal_dyastolic设置为80(第14行)以打开游标,然后从循环中提取行(第16行),并关闭游标,下一步是将age设置为40、normal_dyastolic设置为70,再次打开游标(第22行).
可在循环中用不同结果提取行.
表5-56通过关闭和再次打开游标的方式改变游标的参数SQL>decare22Patient_IDPatient.
Patient_ID%type3AgePatient.
Age%type4DyastolicPatient.
Dyastolic%type55cursorpatients_with_hypertension6(patient_agenumber,7normal_dyastolicnumber)is8selectpatient_id,age,dyastolic9frompatient10where11dyastolic>normal_dyastolic*(age+200)/200;1212begin1313dbms_output.
enable;1414openpatients_with_hypertension(50,80);252Oracle8i数据库开发与专业应用(续)1515loop1616fetchpatients_with_hypertension17intoPatient_ID,Age,Dyastolic;18exitwhenpatients_with_hypertension%notfound;1919dbms_output.
put_line('Withage=50,dyas=80:'||Patient_ID);2020endloop;2121closepatients_with_hypertension;2222openpatients_with_hypertension(40,70);2323loop2424fetchpatients_with_hypertension25intoPatient_ID,Age,Dyastolic;26exitwhenpatients_with_hypertension%notfound;2727dbms_output.
put_line('Withage=40,dyas=70:'||Patient_ID);2828endloop;2929closepatients_with_hypertension;3030end;31/Withage=50,dyas=80:N3393Withage=50,dyas=80:A2002Withage=40,dyas=70:N3393Withage=40,dyas=70:E3893PL/SQLproceduresuccessfullycompleted.
5.
3.
8使用游标进行FOR循环对于打开、取、关闭游标的这种交替工作方式,Oracle提供了另一种方式——游标循环.
使用游标FOR循环,Oracle要隐含地说明一个变量——循环索引——它与游标的记录有相同的记录类型,见程序表5-57.
第5章Oracle8数据库编程253表5-57使用游标FOR循环SQL>declare22Instructor_IDInstructor.
Instructor_ID%type;3Last_NameInstructor.
Last_Name%type;4First_NameInstructor.
First_Name%type;55cursorGet_Associate_Profsis6selectInstructor_ID,Last_Name,First_Name7fromInstructor8wherePosition='ASSOCIATIONPROFESSOR'9orderbyInstructor_ID;1010begin1111dbms_output.
enable;1212forGet_Associate_Profs_RecinGet_Associate_Profsloop1313dbms_output.
put_line('Lastname:'||Get_Associate_Profs_Rec.
Last_Name);1414endloop;1515end;16/Lastname:NILANDLastname:DANIELSLastname:RESTONLastname:JASONLastname:ANGELOLastname:CHERNOWLastname:YOUNGPL/SQLproceduresuccessfullycompleted.
FOR后面的名字是隐含说明的循环索引,但是表5-58证明了不能在循环体外引用循环索引Get_Associate_Profs_Rec.
表5-58在循环体外引用循环索引时Oracle返回错误信息SQL>declare22Instructor_IDInstructor.
Instructor_ID%type;3Last_NameInstructor.
Last_Name%type;4First_NameInstructor.
First_Name%type;55cursorGet_Associate_Profsis6selectInstructor_ID,Last_Name,First_Name254Oracle8i数据库开发与专业应用(续)7fromInstructor8wherePosition='ASSOCIATIONPROFESSOR'9orderbyInstructor_ID;1010begin1111dbms_output.
enable;1212forGet_Associate_Profs_RecinGet_Associate_Profsloop1313dbms_output.
put_line('Lastname:'||Get_Associate_Profs_Rec.
Last_Name);1414endloop;1515Last_Name:=Get_Associate_Profs_Rec.
Last_Name;1616end;17/declare*ERRORatline1:ORA-06550:line15,column14:PLS-00201:identifier'GET_ASSOCIATE_PROFS_REC.
LAST_NAME'mustbedeclaredORA-06550:line15,column1:PL/SQL:Statementignored5.
3.
9%FOUND、%NOTFOUND和%ROWCOUNT1.
%FOUND与%NOTFOUND前面的例子中用%NOTFOUND属性确定FETCH是否检索到行.
当在一个活动集中所有的行都已经被取到,且最后的FETCH语句没能检索到行时,%NOTFOUND的值是TRUE.
在执行FETCH语句前,%NOTFOUND返回一个NULL值.
如果PL/SQL程序中有一个循环,循环中的FETCH语句可能没被调用,此时应考虑对%NOTFOUND是否为NULL进行检测.
2.
用%ROWCOUNT获取行的行数不需要用计数器对游标所提取行的行数进行跟踪,可使用游标的%ROWCOUNT属性完成这一功能.
从表5-59的第13行可以看到:%ROWCOUNT返回提取行的行数.
第5章Oracle8数据库编程255表5-59用%ROWCOUNT确定游标提取行的行数SQL>declare22Instructor_IDInstructor.
Instructor_ID%type;3Last_NameInstructor.
Last_Name%type;4First_NameInstructor.
First_Name%type;55cursorGet_Associate_Profsis6selectGet_Associate_Profs_ID,Last_Name,First_Name7fromInstructor8wherePosition='ASSOCIATEPROFESSOR'9orderbyInstructor_ID1010begin1111dbms_output.
enable;1212forGet_Associate_Profs_RecinGet_Associate_Profsloop1313dbms_output.
put_line('Rowcount:'||Get_Associate_Profs%rowcount);1414endloop;1515end;16/Rowcount:1Rowcount:2Rowcount:3Rowcount:4Rowcount:5Rowcount:6Rowcount:7PL/SQLproceduresuccessfullycompleted.
当在游标中没有更多的行时,需跳出循环.
表5-60说明达到所指定的%ROWCOUNT值时,如何确定跳出循环的条件(见第13行).
256Oracle8i数据库开发与专业应用表5-60行取到指定数值时跳出游标循环SQL>declare22Instructor_IDInstructor.
Instructor_ID%type;3Last_NameInstructor.
Last_Name%type;4First_NameInstructor.
First_Name%type;55cursorGet_Associate_Profsis6selectGet_Associate_Profs_ID,Last_Name,First_Name7fromInstructor8wherePosition='ASSOCIATEPROFESSOR'9orderbyInstructor_ID1010begin1111dbms_output.
enable;1212forGet_Associate_Profs_RecinGet_Associate_Profsloop1314exitwhenGet_Associate_Profs%rowcount>=5;14dbms_output.
put_line('Rowcount:'||Get_Associate_Profs%rowcount);1515endloop;1616end;17/Rowcount:1Rowcount:2Rowcount:3Rowcount:4PL/SQLproceduresuccessfullycompleted.
正如在表5-59和表5-60中所看到的,能够使用%ROWCOUNT跟踪从游标取到的行数.
5.
3.
10用数据库触发器执行事物规则已经学习了SQL和PL/SQL各项功能的使用,现在可以探究数据库触发器的使用了.
在一个以非关系数据库为基础的信息系统中,其应用软件中体现了服务于系统的团体机制的事务规则.
例如,一条事务规则可能是:如果存货清单中某种部件的存货低于其存货的水平,就应该给系统定购所需数量的部件.
在COBOL或其他编程语言中,一般是写一段子程序,在应用系统的适当地方进行调用,以实现这条规则.
但是这种方法存在以下问题:(1)只有在应用程序或工具中调用该段子程序时,才能执行该条规则.
如果用其他工具修改数据库中的记录,规则就不能执行.
(2)找出实现事务规则的算法清单相当困难.
必须依靠凭证文卷(可能不完全准确)或阅读应用软件这种苦差事进行工作.
第5章Oracle8数据库编程257与其他现代的RDBMS一样,Oracle提供了一种结构数据库触发器,用它来实现团体机构的事务规则是很容易的.
数据库触发器(databasetrigger)就是一组PL/SQL语句,是当对一个表应用一条SQL语句(如SELECT、UPDATE或INSERT语句)时执行的一组PL/SQL语句.
可用数据库触发器完成以下任务:(1)实现一种复杂的安全政策;(2)在同一个表或不同的表中用某列的值改变另一列的值;(3)实现复杂的列值有效性检验.
例如,将一个列的值与另外一个表的合计列的值进行比较;(4)通过对另一个表写入修改值的方式将文卷改变成记录.
5.
3.
11建立触发器利用文本编辑器写触发器.
Oracle语句CREATETRIGGER建立(或替换)触发器,当对表指定事件发生时,即触发该触发器.
CREATETRIGGER的语法是:CREATE[ORREPLACE]TRIGGERtrigger-name{BEFORE|AFTER}Triggering-eventONtable-name[FOREACHROW][WHEN(condition)]PL/SQL-block变量定义如下:trigger-name:是建立的触发器的名字,且按照Oracle对象命名的限制条件命名;Triggering-event:是对应于DML的三条语句INSERT、UPDATE或DELETE;table-name:是与触发器相关的表的名字;FOREACHROW:是可选子句,当使用时,对每条相应行将引起触发器触发;condition:是可选的OracleBoolean条件,当条件为真时,触发器触发;PL/SQL-block:是触发器触发时执行的PL/SQL块,称为触发器体(triggerbody).
下面讨论CREATETRIGGER语句中各要素的使用.
1.
语句级和行级触发器数据库触发器有以下两种:(1)语句级(Statement-lever)触发器:在CREATTRIGGER语句中不包含FOREACHROW子句;(2)行级(Row-lever)触发器:在CREATTRIGGER语句中有子句FOREACHROW.
语句级触发器对于触发事件只能触发一次,而且不能访问受触发器影响的每一行的列值.
行级触发器可对受触发器影响的每一行触发,并且能够访问原列值和通过SQL语句处理的新列值.
一般语句级触发器处理有关引起触发器触发的SQL语句的信息(例如,由谁来执行和什么时间执行).
行级触发器的典型应用是当需要知道行的列值时,执行一条事务规则.
2.
在触发器体内引用列值在触发器体内,行级触发器可以引用触发时已经存在的行的列值,这些列值依赖于引起触发器触发的SQL语句.
258Oracle8i数据库开发与专业应用(1)对于INSERT语句,要被插入的数值包含在:new.
column-name,这里的column-name是表中的一列;(2)对于UPDATE语句,列的原值包含在:odd.
column-name中,数据列的新值在:new.
column-name中;(3)对于DELETE语句,将要删除的行的列值放在:odd.
column-name中.
3.
触发事件建立触发器时,需要指定什么事件发生时引起触发器触发.
这里有三种可能的事件:(1)用INSERT语句在表中插入新的行;(2)用UPDATE语句修改一组行(或没有行被修改);(3)用DELETE语句删除一组行(或没有行被删除).
此外,可将这些触发事件进行组合,因此根据这些触发事件,不管什么时候,当执行DELETE、INSERT和UPDATE语句中的一条时,触发器即被触发,见表5-61.
表5-61说明一个触发器事件均能引起触发的触发器SQL>createorreplacetriggerBlock-Trade_After_AllAfter2insertorupdateordeleteonTab13foreachrow44declare55begin66insertintoTab17(col11)8values9(11);1010end;11/Triggercreated.
4.
事前和事后行级触发器事前(BEFORE)行级触发器是在触发事件前触发,可使用事前行级触发器修改行的值,事后(AFTER)行级触发器是在触发事件发生后触发,使用事后(AFTER)行级触发器修改列的值.
5.
一个表可能的触发器可以在CREATTRIGGER语句中使用所有可能的排列,一个单表最多可以有12种触发器:(1)BEFOREDELETE、BEFOREINSERT、BEFOREUPDATE、AFTERDELETE、AFTERINSERT、AFTERUPDATE这样的六种行级触发器;(2)BEFOREDELETE、BEFOREINSERT、BEFOREUPDATE、AFTERDELETE、AFTERINSERT、AFTERUPDATE这样的六种语句级触发器.
如果正在考虑使用实体-联系模型工具进行数据库设计,你将会发现它们中大部分工第5章Oracle8数据库编程259具均可根据所定义的主关键字和外关键字的关系自动生成数据库触发器.
像ErwinfromLogicworks这样的工具,既可以用一个Oracle连接直接建立触发器,也可以在脚本文件中存储触发器.
如果选择后一种方法,可以给任何已经生成的触发器增加特定应用事务规则,以此修改创立触发器的脚本.
对于表,不是必须要建立12种触发器.
在建立触发器时,可根据实际需要进行正确的分析.
Oracle7.
1或更高版本支持在同一表中同一类型的多重触发器,但Oracle7.
0的快照(snapshot)功能,对主表不能建立AFTERROW触发器,因为在同一个表中快照标记已经使用了AFTERROW触发器.
不过,除非打算为了能用快照引用表而使用AFTERROW触发器外,应尽量避免对给定的表定义多个相同类型的触发器,以防止设计错误和混乱.
5.
3.
12用触发器对列值进行有效性检验作为某信用卡公司的DBA,可通过数据库触发器实现信用政策.
公司研究表明:如果一张信用卡在三天内累计计账超过1000美元,这种情况80%以上可能是信用卡诈骗.
执行部主任想在一个独立的表中根据上述标准记录每一笔账,并可在该表找到每笔账目的详细资料.
为了完成这项任务,可在Client_Charge_Log表中建立一个触发器,在插入数据行之前触发.
触发器可对指定的卡查看前三天的计账总额.
如果总额超过$1000,执行INSERT语句,并在Client_Charge_Log中插入数据行,信用代理可对表中的记录进行详细的分析.
表5-62给出如何建立触发器的过程.
表5-62建立一个事前插入触发器SQL>createorreplacetriggerClient_Charge_Log_Ins_Beforebefore2insertonClient_Charge_Log3foreachrow44declare55total_for_past_3_daysnumber;66begin77--Checkthecreditchargesforthepast3days.
8--Iftheytotalmorethan$10000.
00,logthisentry9--intheClient_Charge_Attempt_Logforfurtherhandling.
1010selectsum(amount)11intototal_for_past_3_days12fromClient_Charge_Log13where14Card_Number=:new.
Card_Numberand15Transaction_Date>=sysdate-3;1616iftotal_for_past_3_days>1000.
00then260Oracle8i数据库开发与专业应用(续)1717insertintoClient_Charge_Attempt_Log18(Card_Number,Amount,Vendor_ID,Transaction_Date)19values20(:new.
Card_Number,:new.
Amount,:new.
Vendor_ID,:new.
Transaction_Date);2121endif;2222end;23/Triggercreated.
建立触发器后,就可将它触发,用几行数据对表Credit_Charge_Log的内容进行初始化,见表5-63.
表5-63插入下一数据行前Credit_Charge_Log表的内容SQL>select*fromCredit_Charge_LogCARD_NUMBERAMOUNTVENDOR_ITRANSACTI8343124443239383128.
331234567819-JUN-95945312883423224383.
129876543218-JUN-954644732212887321431.
11818181819-JUN-950944583312453477211.
940909090918-JUN-950944583312453477413.
830808080818-JUN-950944583312453477455.
319191919119-JUN-9509445833124534772251234123420-JUN-950944583312453477512.
221234123420-JUN-958rowsselected.
在表中插入卡号为0944583312453477的数据行之前,触发器被触发.
它查询表中该卡号前三天内计账总数是否超过$1000,则在表Credit_Charge_Attempt_Log中插入该行.
在表5-64(第1行)可以看到,由于卡号为0944583312453477在前三天的计账总数已超过$1000,因此触发器在Credit_Charge_Attempt_Log中插入一数据行.
表5-64在表Credit_Charge_Log中插入行触发器触发SQL>insertintoCredit_Charge_Log2(Card_Number,Amount,Vendor_ID,Transaction_Date)3values4('0944583312453477',128.
28,'43214321','20-JUN-95');1rowcreated.
SQL>select*fromCredit_Charge_Attempt_Log;CARD_NUMBERAMOUNTVENDOR_ITRANSACTI0944583312453477128.
284321432120-JUN-95第5章Oracle8数据库编程2615.
3.
13使用触发器加强安全性这里有一个实例说明如何使用数据库实施安全政策.
Acme公司为了实施装船计划,建立一个数据库,因此必须在Shipment表中插入行.
Shipment表有个Manual_Check列,该列记录船运公司职员是否用电话准确核实了装运要求.
为了减少诈骗的可能性,公司政策是在正常工作时间下午5:00以后,每个职员应该核对所输入的装运要求.
作为一个DBA,应该负责执行这项政策.
如表5-65中所示,建立触发器Shipment_Ins_Before,它将在表Shipment执行INSERT语句前触发.
触发器体由单一PL/SQL语句组成,给Manual_Check列赋值为Y.
另外还决定使用WHEN子句,使触发器只能在下午5:00以后触发(或用24小时时间17:00).
表5-65建立触发前必须满足某个条件的触发器SQL>createorreplacetriggerShipment_Ins_Beforebefore2insertonShipment3foreachnow4when(to_number(to_char(sysdate,'HHH24'))>17)55declare66begin77:new.
Manual_Check:='Y'88end;9/Triggercreated.
建立触发器后,可以对它进行检测.
在表5-66中可以看到,当前时间比5:00p.
m.
晚,实际上是7:00p.
m.
.
在表Shipment中插入行时,Manual_Check列设置为Y.
表5-66触发器核对时间并触发SQL>selectto_char(sysdate,'HH24')fromdual;TO_CHAR(SYSDATE,'HH24')19SQL>insertintoShipment2(Shipment_ID,Product_Code,Quantity,Customer_ID)3values4('SHIP1001','PROD123',100,'CUST999');1rowcreated.
SQL>select*fromShipmentSHIPMENT_IDPRODUCT_CODEQUANTITYCUSTOMER_IDMANUAL_CHECKSHIP1001PROD123100CUST999Y262Oracle8i数据库开发与专业应用5.
3.
14使用触发器设置列的值触发器的另一种功能是:在SQL语句产生作用前,用一个特定的值给列赋值.
下面的方案给出这种过程,假设Block_Trade_Log用来在NASDAQ(全国证券交易协会自动报价系统)记录股票交易.
表主要包含以下几项内容:股票标志、交易价格、交易数量、交易时间、买进还是卖出和三天平均值.
当在表中插入数据行时,触发器用来给Running_Avg_3_Days设置数值.
表5-67给出建立触发器的过程.
表5-67使用触发器设置列值createorreplacetriggerBlock_Trade_Log_BIbeforeinsertonBlock_Trade_LogforeachrowdeclareRunning_Avgnumber;beginselectavg(price)intoRunning_AvgfromBlock_Trade_LogwhereStock_Symbol=:new.
Stock_SymbolandTimestamp>=SYSDATE-3;:new.
Running_Avg_3_Days:=Running_Avg;end;/注意:Running_Avg_3_Days的值是通过给:new.
Running_Avg_3_Days赋值的方式设置的.
如果触发事件是INSERT,列的值实际上是存储在带有:new引用的表中.
表5-68显示出表Block_Trade_Log的内容,注意股票标志是QQQQQ的两个数据行:一个是$102.
125;另一个是$103.
5.
当另一行标志QQQQQ插入表Block_Trade__Log时,触发器被触发,并计算该种股票三天的平均值($102.
8125),并将该数值赋给Running_Avg_3_Days列.
表5-68用INSERT语句激发触发器SQL>select*fromBlock_Trade_Log;STOCK_PRICEBLOCKS_TRADEDBRUNNING_AVG_3_DAYSTIMESTAMPQQQQQ102.
125100B19-JUN-95QQQQQ103.
5100S19-JUN-95VVVVV55.
753000S19-JUN-95VVVVV55.
51000B20-JUN-95SQL>insertintoBlock_Trade_Log2(Stock_Symbol,Price,Blocks_Traded,Bought_sold,Timestamp)3values第5章Oracle8数据库编程263(续)4('&stock',&price,&numblocks,'&BS','&date')5;Entervalueforstock:QQQQQEntervalueforprice:104.
25Entervaluefornumblocks:300Entervalueforbs:BEntervaluefordate:20-JUN-95old4:('&stock',&price,&numblocks,'&BS','&date')new4:('QQQQQ',104.
25,300,'B','20-JUN-95')1rowcreated.
SQL>select*fromBlock_Trade_Log;STOCK_PRICEBLOCKS_TRADEDBRUNNING_AVG_3_DAYSTIMESTAMPQQQQQ102.
125100B19-JUN-95QQQQQ103.
5100S19-JUN-95VVVVV55.
753000S19-JUN-95VVVVV55.
51000B20-JUN-95QQQQQ104.
25300B102.
812520-JUN-955.
3.
15级联触发器触发器的相互作用是相当复杂的.
例如,可以建立一个触发器,当它触发时,可以使另一个触发器触发.
触发器的这种工作方式叫作级联触发器(cascadingtrigger).
为了进一步解释级联触发器的概念,可研究表5-69中的三个简单的表(tab1、tab2和tab3).
开始每个表只有一行数据.
表5-69使用INSERT语句使触发器触发createtabletab1(col1number);createtabletab2(col2number);createtabletab3(col3number);SQL>select*fromtab1;COL17SQL>select*fromtab2;COL210SQL>select*fromtab3;COL313264Oracle8i数据库开发与专业应用表tab1建立了一个行级BEFOREUPDATE触发器,它可将tab1中的col1列的旧值插入到tab2中,见表5-70.
表tab2建立了行级的BEFOREUPDATE触发器,它可更新表tab3,并用col2的新值给col3赋值.
最后对于表tab3,建立语句级AFTERUPDATE触发器,它可在col3的值等于27时,在表tab3中插入行.
表5-70创建一个能够使另一个触发器触发的触发器SQL>createorreplacetriggertab1_Update_Beforebefore2updateontab13foreachrow44declare55begin66insertintotab27(col2)8values9(:old.
col1);1010end;11/Triggercreated.
SQL>createorreplacetriggertab2_Insert_Beforebefore2insertontab23foreachrow44declare55begin66updatetab37set8col3=:new.
col2;99end;10/Triggercreated.
SQL>createorreplacetriggertab3_Update_Afterafter2updateontab33declare44begin55insertintotab36(col3)7values8(27);99end;10/Triggercreated.
第5章Oracle8数据库编程265当使用还没有确认的INSERT、UPDATE或DELETE语句改变表的内容时,表也要变换.
行级触发器不能读或修改变换的表的内容,因为变换表处在不断变换的状态中.
对于这种规则唯一的例外是BEFOREINSERT行级触发器,仅使用外关键字修改表中有主关键字的某列.
现在看一看tab1中的数据行被更新时将会发生什么情况在表5-71中可以看到,它发生了以下变化:(1)tab1中,col1的值被更新为8;(2)tab2中,触发器Tab1_Update_Before用col1:7的旧值插入一行新数据;(3)tab3中,当在tab2中插入新行的时候,使触发器Tab2_Insert_Before触发,并设置col3的值,使其与在tab2插入的值7相同.
当tab3被更新后,触发器Tab3_Update_Before在tab3中用值27插入另一行.
表5-71级联触发器的检测SQL>updatetab12setcol1=8;1rowupdated.
SQL>select*fromtab1;COL18SQL>select*fromtab2;COL2107SQL>select*fromtab3;COL3727级联触发器能够被触发的级联数目默认数值被限制到32,但应记住:级联数越少,才越有能力理解INSERT、UPDATE或DELETE这些与级联触发器相关的SQL语句.
5.
3.
16在触发器中不能使用COMMIT和ROLLBACK数据库触发器不能使用COMMIT和ROLLBACK语句.
同时,触发器也不能调用那些含有COMMIT和ROLLBACK语句的存储过程、函数或包子程序.
Oracle保持这种限制的原因是:如果触发器遇到错误时,由触发器导致的所有数据库变换均能被返回(rollback)取消,但如果触发器确认(commit)了对数据库进行的部分变换,Oracle就不能完全返回整个事项.
5.
3.
17从触发器中调用存储过程可以从数据库触发器的PL/SQL体中调用存储过程或函数,而不管这些存储过程或函数是一个独立的包还是包的一部分.
例如,这里有对触发器Block_Trade_Log_BI的说明,266Oracle8i数据库开发与专业应用见前面的表5-67,它调用存储函数Get_3_Day_Running_Avg,该触发器以前面所讨论的Block_Trade_Log表为基础.
表5-72中含有触发器将要引用的存储函数.
表5-72创建一个由触发器调用的存储函数SQL>createorreplacefunctionGet_3_Day_Running_Avg2(Stock_Symbinvarchar2)3returnnumberis44Running_Avgnumber;55begin66selectavg(price)7intoRunning_Avg8fromBlock_Trade_Log9where10Stock_Symbol=Stock_Symband11Timestamp>=SYADATE-3;1212returnRunning_Avg;1313end;14/Functioncreated.
表5-73中调用存储函数Get_3_Day_Running_Avg的Block_Trade_Log_BI说明进行了修改.
表5-73修改一个由触发器调用存储过程SQL>createorreplacetriggerBlock_Trade_Log_BIbefore2insertonBlock_Trade_Log3foreachrow44declare55Running_Avgnumber;66begin77:new.
Running_Avg_3_Days=:Get_3_Day_Running_Avg(:new.
Stock.
Symbol);88end;9/Triggercreated.
第5章Oracle8数据库编程2675.
3.
18对触发器的删除、启用和废止如果已确定不需要某个指定的触发器,可用下面的语句删除它:DROPTRIGGERtrigger-name;变量trigger-name是将要被删除的触发器的名字.
例如,要在RepairHeader表中删除DELETEAFTER触发器,可通过SQL*Plus给出下列语句:SQL>droptriggerRepair_Header_Delete_After;Triggerdropped.
删除触发器应很慎重,也许只需临时废止触发器.
可以废止触发器直到再次启用它.
临时废止触发器可使用ALTERTRIGGER语句:ALTERTRIGGERtrigger-nameDISABLE;trigger-name是要废止的触发器的名字.
下例废止了触发器Repair_Header_Delete_After:SQL>altertriggerRepair_Header_Delete_Afterdisable;Triggeraltered.
启用一个废止的触发器,可用语句:ALTERTRIGGERtrigger-nameENABLE;trigger-name是要启用的触发器的名字.
例如可用下列命令启用Repair_Header_Delete_After:SQL>alterRepair_Header_Delete_Afterenable;Triggeraltered.
5.
4小结1.
问:PL/SQL是哪些应用逻辑元素的基础答:PL/SQL是下列应用逻辑元素的基础:(1)SQL*Plus程序(SQL*PlusScript):SQL*Plus程序可以组成PL/SQL子程序.
(2)存储过程或存储函数:存储过程或存储函数是可由客户机应用系统、数据触发器或Oracle工具应用触发器调用的PL/SQL子程序.
(3)数据库触发器:数据库触发器是一个PL/SQL子程序,该子程序是基于对数据库表执行一条DML语句(如INSERT、UPDATE或DELETE)的某些操作.
(4)包(Package):将一组PL/SQL过程、函数游标和其他PL/SQL变量组织在一起形成一个包.
(5)应用触发器:OracleForms和OracleReports这些Oracle应用开发设备有PL/SQL引擎,因此开发者可以使用PL/SQL建立应用触发器.
2.
问:程序块结构语言PL/SQL有哪几个部分答:(1)说明部分:一个PL/SQL块的说明部分是任选项,但是必须对所有PL/SQL语句中引用的变量和常量进行说明.
268Oracle8i数据库开发与专业应用(2)执行部分:一个PL/SQL块的执行部分是从关键字BEGIN后面开始的,每条PL/SQL语句均以分号结束.
(3)例外处理部分:例外是在PL/SQL程序的执行中出现的一个错误,它可能是预定义的(例如,一个INSERT语句试图在一个表中增加一个重复行,结果出现了DUP-VAL-ON-INDEX例外).
3.
问:PL/SQL提供了哪些SQL没有的附加数据类型答:(1)BOOLEAN(布尔型):可用预定义的常量TRUE、FALSE或NULL对一个布尔变量赋值.
(2)BINARY-INTEGER(二进制整数):该类型使用于在-2,147,483,647到2,147,483,647范围内的带符号整数.
(3)NATURAL(自然数):是BINARY-INTEGER的一个子集,这种数据类型是整数集的一部分,从0到2,147,483,647.
(4)POSITIVE(正整数):是BINARY-INTEGER的另一个子集,这种数据类型是整数集的一部分,从1到2,147,483,647.
(5)%TYPE:这种设计可说明一个变量的数据类型与某一指定列的数据类型相同,其结果产生更易于维护的PL/SQL代码.
(6)%ROWTYPE:用这种数据类型可以说明一个符合变量,与某一特定表中的一行相同,这种复合变量是由引用表中的列名和数据类型组成的.
4.
问:PL/SQL有哪些常见的控制结构答:几种控制一个PL/SQL子程序执行流程的PL/SQL命令如下:(1)IF-THEN-ELSE(2)LOOP(3)EXIT(4)WHILELOOP(5)FORLOOP(6)GOTO(7)NULL5.
问:如何在PL/SQL中程序中使用SQL语句答:就像在SQL*Plus中使用一样,可以在匿名块、过程或函数中使用SQL语句,但有一些不同.
像其他PL/SQL语句一样,每条SQL语句都必须以分号结束.
不过,PL/SQL可以在一条SQL语句中引用说明过的变量.
下例显示了如何在说明SQL语句中引用的变量.
DECLAREmax_recordsCONSTANTint:=100;iint:=1;BEGINFORiIN1.
.
max_recordsLOOPif(mod(i,10)=0)thenINSERTINTOtest_table(record_number,current_date)第5章Oracle8数据库编程269VALUES(i,SYSDATE);elseNULL;endif;ENDLOOP;COMMIT;END;/6.
问:怎样区分存储过程(storedprocedure)和说明过程答:区分存储过程(storedprocedure)和说明过程及在匿名块中使用的不同是非常重要的.
说明过程在匿名块中的过程是非永久性的,当一个匿名块运行完成后,对Oracle而言,这些过程也就不再存在了.
而一个存储过程是用CREATEPROCEDURE语句创建的,或者是包含在一个包内,由于它可被SQL*Plus程序、PL/SQL子程序或数据库触发器调用,因此,它是永久性的.
7.
问:PL/SQL函数与过程的说明有什么不同答:函数返回一个预定义的数据类型的值,而过程不需要.
8.
问:使用存储过程和函数主要有哪些优越性答:(1)提高了效率:在客户/服务器体系结构中,客户机应用向数据库服务器提出对SQL的需求.
随着用户数量的增加,SQL请求也就不断地增加,使网络很快就成为运行的瓶颈.
使用存储过程可使运行性能得到显著的改进,因为对存储过程的一个调用,即调用了在服务器中执行的多个SQL语句,从而减少了网络的拥挤.
(2)可重用性:一个PL/SQL程序只需编写一次,即可用于各种地方——SQL脚本、数据库触发器和客户机应用程序.
(3)可移植性:可在任何Oracle数据库中使用存储过程,而不用考虑平台问题,所以不需要处理像操作系统或编译版本中出现的兼容性问题.
只要平台支持Oracle,不需做任何改变就可调用存储过程.
当然如果存储过程包含对文件和路名的引用,就需要另做一些改变.
(4)可维护性:一个存储过程用于完成一个特定的任务,如数据库触发器、SQL*Plus脚本、应用程序或其他存储过程可能需要调用该过程.
从所有这些地方均可调用同一个存储过程,这样可降低软件维护的成本.
9.
问:怎样使用PL/SQL给用户或另一个程序提供结果答:可以按照以下方法:(1)将信息写入用户或程序可查询的一个中间表中;(2)使用Oracle提供的DBMS_OUTPUT包中的过程或函数.
10.
问:如何在PL/SQL中处理错误答:在《Oracle错误信息和代码手册》(OracleErrorMessageandCodesmanual)中,列出了除特定的操作错误之外的所有错误代码和信息,在某些地方,应用系统也许会遇到其中的某种错误.
在PL/SQL中,将Oracle错误称为例外(exception),其中一些例外有预定义名,可以在PL/SQL子程序中引用.
除了预定义Oracle例外之外,也可以在PL/SQL子程270Oracle8i数据库开发与专业应用序中定义特别应用(application-specific)例外.
例如,SQL>declare22Course_RecCourse%ROWTYPE;33begin44dbms_output.
enable;55select*6intoCourse_Rec7from8where9Department_ID='BIO';1010exception11whenTOO_MANY_ROWSthen12dbms_output.
put_line('TOO-MANY-ROWSraised-useacursor');13whenOTHERSthen14NULL;15end;16/11.
问:怎样用一条SELECT语句检索任意数量的行答:使用游标.
在使用SQL*Plus或SQLWorksheet时,可能要执行一个不考虑返回行数目的查询,即检索出零个、一个或一千个行都没关系.
但是,PL/SQL子程序中有一条SELECT语句(不管该子程序是匿名块、存储过程、还是触发器)检索到多个数据行时,则Oracle返回一条错误信息.
显然系统具有检索多行数据的功能是非常必要的,要达到这一功能就必须利用某些结构,因此Oracle提供了一种相应的资源,这就是游标(cursor).
像SQL*Plus这样的Oracle工具可自动建立和使用游标.
12.
问:"在触发器中不能使用COMMIT和ROLLBACK",这句话是否正确答:正确.
数据库触发器不能使用COMMIT和ROLLBACK语句.
同时,触发器也不能调用那些含有COMMIT和ROLLBACK语句的存储过程、函数或包子程序.
Oracle保持这种限制的原因是:如果触发器遇到错误时,由触发器导致的所有数据库变换均能被返回(rollback)取消,但如果触发器确认(commit)了对数据库进行的部分变换,Oracle就不能完全返回整个事项.
第6章Oracle与C语言接口——Pro*C6.
1Pro*C概述Oracle预编译器是一种编程工具,它可以把SQL语言嵌入高级语言中,充分利用高级语言灵活的控制结构和SQL语言对数据的操作能力.
Oracle支持六种高级语言的预编译:Ada、C、COBOL、FORTRAN、Pascal、pl/I.
通过预编译器,应用开发人员能开发出充分满足需求的应用程序,比如图形界面鼠标驱动等一般Oracle工具中无法实现的技术.
并且使用预编译器写出的应用程序,速度更快、性能优越.
6.
2Pro*C程序基本结构6.
2.
1一个简单的Pro*C程序例如:查询名为SMITH的雇员的雇员号和工资.
#includeEXECSQLBEGINDECLARESECTION;VARCHARusername[20];VARCHARpassword[20];floatsalary;intemp_number;EXECSQLENDDECLARESECTION;EXECSQLINCLUDESQLCA;main(){/*登录到Oracle*/strcpy(username.
arr,"SCOTT");username.
len=strlen(username.
arr);strcpy(password.
arr,"TIGER");password.
arr=strlen(password.
arr);EXECSQLWHENEVERSQLERRORSTOP;EXECSQLCONNECT:usernameINDENTIFIEDBY:password;printf("/nConnecttoOracleasuser:%s/n",username.
arr);272Oracle8i数据库开发与专业应用EXECSQLSELECTsal,empnoINTO:salary,:emp_number;FROMEMPWHEREename='SMITH';printf("/nSMITH'Semp_number=%dsalary=%6.
2f/n",emp_number,salary);EXECSQLCOMMITWORKRELEASE;}6.
2.
2Pro*C程序的基本结构我们根据上例来说明Pro*C的基本结构.
Pro*C程序由程序首部和程序体组成.
1.
程序首部程序首部包括三部分:变量定义、SQL通信区定义、与Oracle连接.
(1)变量定义Pro*C程序中所有在SQL语句中使用的变量,都必须在变量定义部分定义.
变量定义部分应放在两条语句之间:EXECSQLBEGINDECLARESECTION;变量定义部分.
EXECSQLENDDECLARESECTION;在变量定义部分可定义主变量和指示变量.
①主变量:是在程序体的嵌入SQL语句中使用的变量,可以是输出主变量(用于INTO子句)或输出主变量(用于WHERE子句).
②指示变量:是一个短整型变量,用于空值处理.
在后面将详细介绍.
在变量定义部分所定义的变量类型除标准C外,还可以使用一个Oracle提供的伪类型VARCHAR.
一个VARCHAR型变量,实际是C语言中的结构变量,它包括两个域:③变量名.
arr:是一个字符串变量.
④变量名.
len:表示该字符串的实际长度.
(2)SQL通信区(SQLCA)SQL通信区(SQLCA)是一个数据结构,它提供了对诊断检测和事务处理的方法.
当执行一条SQL语句时,Oracle会自动地设置其中所包含的各个域的值.
所以SQL通信区反映了最近一次执行SQL语句的情况.
声明SQL通信区语句:EXECSQLINCLUDESQLCA;(3)与Oracle连接任何Pro*C程序都与一般Oracle工具相同,如SQL*Plus、SQL*Forms等,必须先对Oracle核心进行连接.
对Oracle进行连接使用:EXECSQLCONNECT:用户主变量INDENTIFIEDBY:口令主变量2.
程序体程序体包括了应用程序的主体部分,由以下部分组成:数据处理、出错处理、事务处理.
(1)数据处理数据处理部分可以是由C语句和嵌入式SQL语句组成.
在写嵌入式SQL语句时,必须加上前缀:第6章Oracle与C语言接口——Pro*C273EXECSQL在使用SQL语句时,可以是查询语句、数据操纵语句.
如上例中的:EXECSQLSELECT.
.
.
(2)出错处理Oracle提供了对出错处理的语句:EXECSQLWHENEVER如上例中的:EXECSQLWHENEVERSQLERRORSTOP;(3)事务处理在Pro*C程序中,可以对事务进行提交或回滚.
EXECSQLCOMMITWORK[RELEASE]EXECSQLROLLBACKWORK[RELEASE]其中,RELEASE选项表示在完成提交或回滚操作后,释放所有事务占用的资源,如内存区域、锁资源等.
6.
3Pro*C中的SQL语言6.
3.
1简单查询语句简单查询语句是指只返回单条记录的查询语句,比如6.
2节中的例子.
这里需要注意以下三点.
(1)在嵌入的SQL语言中使用主变量时,必须加前缀":".
(2)在C语言中使用主变量时不用加":".
(3)SELECT语句必须有INTO子句.
INTO子句中的变量类型、个数、顺序应与SELECT子句中输出变量类型、个数、顺序相同.
6.
3.
2数据操纵语句数据操纵语句在Pro*C程序中可以对数据进行插入、删除、修改,其语句写法与其他工具中完全一样,只是前面多了个前缀"EXECSQL".
另外,要注意主变量的用法.
6.
3.
3使用游标的查询语句当一条查询语句返回多行数据时,应该明确定义一个游标(CURSOR),用于处理查询返回的数据和跟踪当前被处理的数据行.
游标在Pro*C中使用与在PL/SQL中的类似,都必须有以下四个步骤:(1)定义游标.
(2)打开游标.
(3)取数据.
(4)关闭游标.
下面我们举一个游标的例子:274Oracle8i数据库开发与专业应用查询EMP表中10号部门雇员的名字和工资.
#includeEXECSQLBEGINDECLARESECTIONVARCHARusername[20];VARCHARpassword[20];floatsalary;charname[15];EXECSQLENDDECLARESECTIONEXECSQLINCLUDESQLCA;main(){/*登录到Oracle数据库*/strcpy(username.
arr,"SCOTT");username.
len=strlen(username.
arr);strcpy(password.
arr,"TIGER");password.
arr=strlen(password.
arr);EXECSQLWHENEVERSQLERRORSTOP;EXECSQLCONNECT:usernameINDENTIFIEDBY:password;printf("/nConnecttoOracleasuser:%s/n",username.
arr);/*定义游标*/EXECSQLDECLAREemp_cursorCURSORFORSELECTENAME,SALFROMEMPWHEREDEPTNO=10;/*打开游标*/EXECSQLOPENemp_cursor;/*循环取数据*/for(;;){EXECSQLWHENEVERNOTFOUNDBREAK;EXECSQLFETCHemp_cursorINTO:name,:salary;printf("/n%s%6.
2f/n",name,salary);}/*关闭游标*/EXECSQLCLOSEemp_cursorEXECSQLCOMMITWORKRELEASE;}在本例中,定义游标时的SELECT语句不能带INTO子句,而在取数据时使用INTO:FETCHemp_cursorINTO:name,:salary;6.
3.
4使用指示变量在Pro*C中有一类特殊的变量叫指示变量,它主要用于处理空值.
指示变量不能独立第6章Oracle与C语言接口——Pro*C275存在,它必须对应于某个主变量,而且指示变量必须定义成短整型变量:shortisalary;在下例中,我们可以看出指示变量的用法:查询SMITH雇员的信息,并把姓名、奖金插入NEWEMP表中.
#includeEXECSQLBEGINDECLARESECTIONVARCHARusername[20];VARCHARpassword[20];floatcommition;shorticomm;EXECSQLENDDECLARESECTIONEXECSQLINCLUDESQLCA;main(){strcpy(username.
arr,"SCOTT");username.
len=strlen(username.
arr);strcpy(password.
arr,"TIGER");password.
arr=strlen(password.
arr);EXECSQLWHENEVERSQLERRORSTOP;EXECSQLCONNECT:usernameINDENTIFIEDBY:password;printf("/nConnecttoOracleasuser:%s/n",username.
arr);EXECSQLSELECTename,commINTO:name,:commition:icommFROMEMPWHEREename='SMITH';if(icomm==-1)printf("/ncommitionisNULL/n");EXECSQLINSERTINTONEWEMP(ename,comm);VALUES(:name,:commition:icomm);EXECSQLCOMMITWORKRELEASE;}在上例中我们可以看出,指示变量使用应注意以下四点.
(1)指示变量必须与主变量对应,不能独立存在.
(2)指示变量应定义为段整型:shorticomm;(3)在SQL语句中,指示变量应紧跟在主变量之后,并加上前缀":",比如:SELECTename,commINTO:name,:commition:icommFROMEMPWHEREename='SMITH'276Oracle8i数据库开发与专业应用(4)指示变量用来处理空值.
在上例的SELECT语句中,如果取comm值为NULL,那么指示变量icomm自动被赋予-1.
同样,在INSERT语句中要插入空值,也是使用指示变量,如果指示变量为-1,则插入NULL值.
6.
3.
5使用嵌入的PL/SQL块在Pro*C程序中,可以使用嵌入的PL/SQL块.
语法如下:EXECSQLEXECUTEDECLARE.
.
.
BEGIN.
.
.
END;END-EXEC;使用了EXECSQLEXECUTE和END-EXEC两个保留字把一个PL/SQL块括起来.
6.
3.
6Pro*C中的出错处理在Pro*C中可以使用WHENEVER语句进行出错处理.
语法如下:EXECSQLWHENEVER其中:是Oracle产生各种警告或错误的类型:SQLWARNING所有SQL语句的警告信息;SQLERRORSQL语句执行错误信息;NOTFOUND执行查询语句未找到符合条件记录.
是Oracle检测到以上条件时采取的操作:CONTINUE忽略发生的错误和警告,继续执行程序;DO子过程名执行一个子过程;GOTO语句标号跳到指定标号语句执行;STOP停止程序执行,退出程序.
因为WHENEVER语句是一条需要说明的SQL语句,所以它的作用范围取决于其物理位置,而不是逻辑位置.
WHENEVER语句对源程序中跟在它后面的所有可执行的SQL语句都进行检测,而不是对程序的逻辑流中的SQL语句进行检测.
所以,WHENEVER语句应该放在所要检测的第一条SQL语句之前.
只有当新的一条WHENEVER语句出现时,原来的WHENEVER语句才不起作用.
下面我们将举一个使用WHENEVER语句不当的例子.
在下面的例子中,由于未对DELETE语句重新定义WHENEVER语句,所以当DELETE语句没有找到满足条件的数据行时,造成程序死循环——反复执行DELETE语句.
.
.
.
main(){.
.
.
第6章Oracle与C语言接口——Pro*C277EXECSQLWHENEVERNOTFOUNDgotono_more;while(1){EXECSQLFETCHemp_cursorINTO:e_name,:salary;.
.
.
}.
.
.
no_more:EXECSQLDELETEFROMempWHEREempno=:emp_number;.
.
.
}下面是对上例的改进方法:.
.
.
main(){.
.
.
EXECSQLWHENEVERNOTFOUNDgotono_more;while(1){EXECSQLFETCHemp_cursorINTO:e_name,:salary;.
.
.
}.
.
.
no_more:EXECSQLWHENEVERNOTFOUNDgotono_match;EXECSQLDELETEFROMempWHEREempno=:emp_number;.
.
.
no_match:.
.
.
}6.
4编译运行Pro*C程序步骤编写运行一个Pro*C程序的步骤如下:(1)用文本编辑器书写一个.
PC程序;(2)使用Oracle预编译工具将.
PC文件转化成.
C文件;(3)编译、链接.
C文件,生成可执行代码;(4)运行可执行文件.
其中,第一步预编译Pro*C程序,是整个步骤的关键,我们将在下面着重介绍.
其余步骤根据操作系统不同会有不同的编译、链接形式.
278Oracle8i数据库开发与专业应用6.
4.
1预编译选项进行Pro*C的预编译,使用下面的命令:proINAME=文件名选项其中,"文件名"为需进行预编译的Pro*C文件名,后缀缺省为.
PC.
Pro*C的预编译选项很多,这些选项可以让用户控制如何使用Oracle资源;如何报告错误;如何定义输入和输出格式以及如何管理游标等等.
选项可以在命令行中指定,比如:proINAME=filenameERRORS=yesLTYPE=longMODE=ANSI14有些选项也可以在Pro*C源程序中指明,使用如下语法格式:EXECORACLEOPTION(选项名=值)比如:EXECORACLEOPTION(HOLD_COUSOR=yes)如果同一个选项既在程序中定义了又在命令行指明了,那么将以程序中的为准.
以下是各个选项的含义、取值和用法.
1.
AREASIZE该参数指定了由程序打开的游标的上下文空间的大小,AREASIZE指定的范围将覆盖在init.
ora文件中指定的游标区域.
如果该参数是在命令行中指定的,那么它将作为Pro*C程序中所有游标的缺省范围.
AREASIZE可以在Pro*C程序中多次指定,用于改变下一个或下一组游标的范围.
游标大小以KB为单位,缺省为16,游标区参数实际上只是给出一个最小值,当一个游标需要比该参数中说明的范围更大的空间时,Pro*C申请获得更多的空间.
2.
ASACC=指出列表文件是否遵守ASA回车控制约定,取"yes"或"no".
"yes"表示每行的第一列用作回车控制;"no"为缺省值.
3.
ERRORS=指出错误应该送到哪里,取"yes"或"no".
"yes"表示错误既要送到终端又要送到列表文件;"no"表示错误仅仅送到列表文件.
4.
HOLD_CURSOR=新的选项,使得程序员可以控制如何处理游标缓冲中一个给定的SQL语句,取值"yes"或"no".
"no"是缺省值,当一个不使用显式说明游标的SQL语句(如INSERT、UPDATE、DELETE)执行之后,该语句的游标缓冲项即可"重用",也即可以重新分派给其他的SQL语句使用;"yes"此时预编译器不会把该语句的游标缓冲项重新分派给其他的SQL语句,这对于有些需要反复使用的SQL语句是很有用的,因为它可以避免由于把SQL语句的缓冲项重新分派而必须进行的重新预编译.
5.
RELEASE_CURSOR=新的选项,同HOLD_CURSOR.
"no"是缺省值.
在一个不使用显式说明游标的SQL语句执行之后,该语句的游标缓冲项即可"重用",但此时并不释放;"yes"在SQL语句的每次执行之后,PCC总是释放它的游标缓冲项,这意味着SQL语句的每次执行都需要重新进行语法分析,对于那些不是第6章Oracle与C语言接口——Pro*C279经常执行的SQL语句,这是很有用的,从而可以释放数据库游标缓冲资源.
例如:EXECORACLEOPTION(RELEASE_CURSOR=yes);EXECSQLSELECTDNAMEINTO:NAMEFROMDEPTWHEREDEPTNO=:NR;EXECORACLEOPTION(RELEASE_CURSOR=NO);它将不会为例子中的SQL语句保留游标缓冲项,意味着每次执行该语句都会重新引起一次语法分析.
在该SQL语句之后,把RELEASE_CURSOR置回为缺省值"no".
一般来说,对于不是经常执行的SQL语句使用RELEASE_CURSOR=yes,而对于经常执行的SQL语句使用HOLD_CURSOR=yes.
合理结合使用HOLD_CURSOR、RELEASE_CURSOR、MAXOPENCURSORS,可以显著地影响程序的性能.
6.
HOST=指出输入程序使用的主语言,它们为C、COBOL、FORTRAN和PL/I.
7.
INCLUDE=指出EXECSQLINCLUDE包含文件的路径名,无缺省值.
8.
IRECLEN=指出输入文件的记录长度,缺省值是80,最大为132,IRECLEN应小于或等于ORECLEN.
9.
INAME=指出输出列表文件的名字,而不是使用缺省名INAME,该文件被写到当前目录或A盘.
10.
LRECLEN=指出列表文件的记录长度,缺省值为132.
11.
LTYPE=指出列表文件类型,取值为(long,short,none).
缺省值为"long",表示输入行出现在列表文件中;"short"表示输入行不出现在列表文件中;"none"表示不产生列表文件.
12.
MAXLITERAL=用于协调编译程序对最大字符串长度的限制.
缺省设置依赖于具体的语言(C语言是1000).
13.
MAXOPENCURSOR=该选项用来指定可以同时打开的Oracle游标数,或Pro*C试图保持其游标缓冲的SQL语句数.
通常,不是为每一个Pro*C游标都打开一个Oracle游标,Pro*C将在同一个Oracle游标数据区重新使用不同的Oracle游标.
MAXOPENCURSOR的缺省值是10.
该参数的最大值依赖于具体的操作系统(在init.
ora文件中给出了此上限值).
OracleRDBMS本身需要五个Oracle游标的开销.
通过使用MAXOPENCURSOR可以把该参数降到一个比较低的数目,但不能把它设置得超过上限值.
40~50的设置是比较平常的,但需注意每个游标都需要用户进程中额外的上下文空间.
14.
ONAME=指输出文件的名字,而不是使用缺省名INAME.
C,输出文件被写到当前目录或A盘.
280Oracle8i数据库开发与专业应用15.
ORACA=指出程序是否能够使用Oracle通信区,取值为"yes"或"no".
"no"为缺省值;当使用"yes"时,还必须在程序中包含ORACA:EXECSQLINCLUDEORACA.
16.
ORECLEN=指出输出文件的记录长度,缺省值是80,最大值为132.
17.
PAGELEN=指出每个物理页的行数,缺省值是66.
18.
REBIND=该选项控制了Pro*C处理BIND5和DEFINES的方式,取值为"yes"或"no".
yes指示预编译器产生代码,使得每次执行SQL语句都重新赋值所有的INTO和USING变量,yes为缺省值;no指示预编译器产生代码,使得每次语法分析只对INTO和USING变量进行一次赋值,这通常意味着每个程序只赋值一次.
缺省值是REBIND=yes,对所有情况有效.
然而重新赋值可能不是最佳选择,会影响性能和带来开销,所以对于那些不需要经常重新赋值的用户应选择REBIND=no.
19.
SELECT_ERROR=指示预编译程序当查询结果返回太多行时,是否产生错误,错误返回在SQLCODE中(OER2112).
取值为yes或no.
yes为缺省值.
20.
USERID=指定Oracle用户名和口令.
使用自动登录系统时,不能指定该参数.
21.
XREF=指出是否在列表中包含交叉引用节,取值为"yes"或"no".
yes为缺省值,包括对主变量、游标名、语句名的交叉引用.
6.
4.
2在各种操作系统下运行Pro*C程序步骤1.
在DOS环境下在DOS环境下,生成的Pro*C程序有两种可选模式:实模式和保护模式.
(1)实模式下程序构造第一步:预编译Pro*C源程序C>prociname=sample.
pcinclude=c:\oracle8\pro\csample.
pc是Pro*C源程序,c:\oracle8\pro\c是SQLCA.
H等文件所在目录.
第二步:编译DOS环境下的Pro*C程序应使用MicrosoftC的大存储模式(/AL).
C>cl/AL-Csample.
c第三步:链接C>linksample,,,sqlmsc/se:512/stack:10000sqlmsc.
LIB是Oracle与MicrosoftC语言的链接库.
第四步:运行C>sample(2)保护模式下的程序构造第6章Oracle与C语言接口——Pro*C281Oracle的Pro*C程序可以运行在DOS的保护模式下.
在保护模式下,Pro*C程序可以用到15MB的内存空间.
第一步:预编译Pro*C源程序C>procINAME=sample.
pcinclude=C:\oracle8\pro\c第二步:把源程序转变为OBJ文件C>cl-c-a/sample.
c第三步:与指定的运行时库链接C>link@samplep.
mln第四步:把已产生的实模式程序转化为保护模式程序C>exe2pxesample第五步:运行Pro*C程序C>ploadrsample2.
在UNIX环境下在UNIX环境下,系统提供一个缺省的用于生成Pro*C可执行程序的文件,使用如下命令:$make-fproc.
mk文件名其中,文件名是后缀为.
PC的Pro*C源文件.
proc.
mk是在/ORACLE_HOME/proc/demo下的文件,执行该命令时应把Proc.
mk文件拷贝到当前的工作目录.
6.
5小结1.
问:Oracle支持哪些高级语言的预编译答:Oracle支持六种高级语言的预编译:Ada、C、COBOL、FORTRAN、Pascal、pl/I.
通过预编译器,应用开发人员能开发出充分满足需求的应用程序,比如图形界面、鼠标驱动等一般Oracle工具中无法实现的技术.
并且使用预编译器写出的应用程序,速度更快、性能优越.
2.
问:Pro*C程序的基本结构是怎样的答:Pro*C程序由程序首部和程序体组成.
(1)程序首部:变量定义;SQL通信区定义;与Oracle连接.
(2)程序体:数据处理;出错处理;事务处理.
3.
问:在C语言中嵌入SQL语言应该注意哪几点答:(1)在嵌入的SQL语言中使用主变量时,必须加前缀":".
(2)在C语言中使用主变量时不用加":".
(3)SELECT语句必须有INTO子句.
INTO子句中的变量类型、个数、顺序应与SELECT子句中输出变量类型、个数、顺序相同.
4.
问:在Pro*C中怎样使用游标答:游标在Pro*C中使用与在PL/SQL中的类似,都必须有以下四个步骤:(1)定义游标.
(2)打开游标.
282Oracle8i数据库开发与专业应用(3)取数据.
(4)关闭游标.
5.
问:指示变量能否独立存在答:不能.
指示变量不能独立存在,它必须对应于某个主变量.
6.
问:使用指示变量应该注意哪几点答:指示变量使用应注意以下四点.
(1)指示变量必须与主变量对应,不能独立存在.
(2)指示变量应定义为段整型:shorticomm;(3)在SQL语句中,指示变量应紧跟在主变量之后,并加上前缀":",比如:SELECTename,commINTO:name,:commition:icommFROMEMPWHEREename='SMITH'(4)指示变量用来处理空值.
7.
问:编写运行一个Pro*C程序的步骤是怎样的答:编写运行一个Pro*C程序的步骤如下:(1)用文本编辑器书写一个.
PC程序;(2)使用Oracle预编译工具将.
PC文件转化成.
C文件;(3)编译、链接.
C文件,生成可执行代码;(4)运行可执行文件.
8.
问:在DOS环境下,生成的Pro*C程序有哪两种可选模式答:有实模式和保护模式.
第7章Oracle8组件和对象7.
1Oracle进程Oracle体系三个主要组件就是进程、内存区和文件,本节将详细地介绍进程.
7.
1.
1Oracle进程用术语"进程"来描述任一操作系统的程序(线程、作业等依赖于操作系统的术语),在Oracle数据库管理系统中,它执行完整的功能.
为方便讨论,将这些Oracle进程分成两类:主进程和选项进程.
主进程是那些与Oracle数据库的最小功能相关的进程.
选项进程是那些要改善性能,或者能从几个可选择进程中进行选择的那些进程(例如,专用服务器进程或多线程服务器进程).
这里的关键是,如果任何一个主进程没有在系统中运行(例如,在UNIX下发出ps命令时),数据库是不可操作的.
如果一个选项进程没有运行,它表示未选择启动该选项进程,或者不需要它当前运行.
就专用服务器而言,它仅在用户连接到一个数据库实例时才开始运行.
7.
1.
2Oracle主进程下面是与Oracle实例有关的一些主进程.
如果其中的任何一个进程停止运行,其他进程将检测到这一问题,并将自己关闭,数据库实例也被关闭.
四个主进程是:(1)系统监视进程(SMON);(2)进程监视进程(PMON);(3)数据库写入进程(DBWR);(4)日志写入进程(LGWR).
图7-1显示了这些进程在Oracle体系结构中的位置.
它们是服务于与Oracle数据库实例相关的数据文件和内存区的关键进程.
如果数据库未与外部世界的用户连接,仍能使用这些进程(运行在基本例程上的存储过程)在数据库中执行函数.
当然,这样的数据库对外部世界是无用的.
这四个主进程与其内存区一起被称为一个Oracle实例(OracleInstance).
如果需要,这四个主进程可与多个不同的数据库相连.
当这些进程启动时,它们从一个或多个初始化文件中派生参数.
可使用不同的初始化文件启动同一个数据库,这就允许为像海量数据加载这样的特殊功能来调整性能的特性.
为了跟踪不同进程的运行轨迹,Oracle使用系统标识符(SID).
SID是连接到给定实例的关键.
当Oracle进程启动后,它们就包含了SID,该SID作为进程名的一部分以便于识284Oracle8i数据库开发与专业应用别.
该参数也用于本地连接(SQL*Net和Net8),以便用户到合适的数据库实例之间执行给定的请求和事务.
图7-1Oracle主进程1.
系统监视进程系统监视进程SMON的任务是,在Oracle实例启动后做清除工作.
SMON是Oracle后台进程和数据文件的守护者.
系统监视进程在三种情况下(见图7-2)被激活.
图7-2Oracle系统监视进程(SMON)第一种情况,在启动时,它检查实例,看看是否需要恢复.
如果实例为关闭干净(正常关闭),则在进程中可能存在某些需要回滚的事务及临时段(此处存放Oracle中使用的不是永久性提交到数据文件中的数据),用于清理某些操作(如正在使用的排序等).
第二种情况,系统监视进程也被设计成周期性唤醒,以发现Oracle实例是否需要做一些清理.
SMON检查是否有临时段,这些临时段将不再使用,可以被清除.
对一个新的请求,确保临时空间最大值的有效性是非常重要的.
SMON还负责搜索数据文件中用来合并空闲区间(freeextent)的各种方法.
如果为某表请求1MB的区间,Oracle搜索一个1MB的连续区间(为提高存取速度,所有的块都是一块连一块).
常常可以发现这样一种情况,在数据文件中,有几兆的自由空间,但它们分散在若干个小碎块中.
SMON将试着移动所有这些小碎块,以便拥有更大的磁盘空闲块.
不过,这种能力是有限的.
因此,有时必须压缩表空间中的区间.
在并行服务器环境下,系统监视进程运行的一个特殊功能是,在CPU故障或实例失效时恢复实例.
如果要在运行的CPU或实例失败时尽可能多地恢复多项活动、作业等,这是第7章Oracle8组件和对象285一个相当复杂的操作,一些特性被内置在公共数据库文件中,用以跟踪所给定的并行服务器实例的活动,并允许进行恢复操作.
第三种情况,当SMON被其他进程调用时,系统监视进程被激活.
例如,如果数据库写入进程检测到需要使用临时段空间,它可激活系统监视进程来释放一些空间.
这对Oracle来说,是一个值得注意的重要特性.
2.
进程监视进程进程监视进程(PMON)专门用于在进程结束后进行清理工作.
它有规律地被唤醒(由操作系统决定),也可由其他进程调用(当其他进程需要此服务时).
例如,当一个用户进程死亡时,PMON必须运行.
(1)删除进程号.
该进程号是否可以再次被使用,与操作系统有关.
在UNIX中,ID是不可以重用的,在其他的操作系统中则可以重用.
进程号(ID)并不在Oracle内考虑,它是操作系统内核中控制进程功能的一个表.
(2)删除活动事务表中相应的行.
(3)释放进程已有的任何锁.
(4)删除进程在高速缓存中正在使用的项.
在Net8多线程服务器环境中,PMON负责重新启动任一分发器,或者已经死亡的服务器进程.
多线程服务器有可激活的进程最小数和最大数.
这里,只有当多线程服务器进程的数量小于该实例的最小级别时,PMON才介入.
当系统拥有大量的连接时,清理不需要的进程是系统中非常重要的功能.
在典型的UNIX系统中,每个连接都消耗几兆内存和一定量的处理器时间.
这对具有数百兆内存的大型多处理器系统而言,看起来并不重要.
但是,如果积累了成千上万的无用进程或无终止进程(例如,在需要花几个小时才能完成的表格查询期间,数据仓库用户关闭了自己的PC),如果PMON为检测其状态并杀死这些进程,就会很容易地消耗大量的处理器时间和数百兆RAM.
3.
数据库写入进程数据库写入进程(DBWR)负责把在高速缓冲内存区(buffercache)中已被修改的转移数据写入相应的磁盘数据文件中.
当用户进程想要把已修改的记录写入数据库高速缓存时,它确保内存中始终有空闲缓冲区在待用.
不论何时,用户向表中增加或者修改记录,修改的记录都被写入高速缓存中.
Oracle使用术语"弄脏(dirty)"来表示那些在内存的缓冲区中需要重写到磁盘上的记录.
在内存中,仅有固定大小的缓冲区(它由初始化文件中的数据库高速缓存的大小来决定),每次"弄脏"一个缓冲区,就会使空闲缓冲区的数量减少,空闲缓冲区在写操作时是可用的,如果空闲缓冲区的总数变得太小,用户进程就找不到有效的缓存存放查询所得的数据(要逐条读出每条记录,并把不立即需要的存放在高速缓存中).
这正是DBWR产生作用的地方.
数据库写入进程把记录写到数据库文件中并不使用最长的时间间隔,用户接口进程(专用的服务器进程)在它们写入最近未用的非脏(not-dirty)缓冲区时,也遵守该过程.
许多记录可以经常使用和修改,数据库写入进程要避免把不久可能又需要使用(比如由过去使用的频率来决定)的记录写到磁盘.
一个经典的相对静止的记录例子是在订单输入系统中的订单数据.
一般情况下,一个订单输入后,直到有人准备装运产品才会再次访问它,这些记录类型会很快从高速缓存中删除以便为其他订货腾出空间.
在高速缓存中,停留时间较长的一类记286Oracle8i数据库开发与专业应用录是经常使用其合法值的查找表.
举例来说,这些有订单输入到系统中的值,每次都可能被扫描,以证实它是正确的.
如果经常使用包含50个状态码表的查找表,它将是最后从Oracle缓冲区中被清除的对象之一.
Oracle如果需要空间,就将彻底清除它.
DBA有一个选项,可手工将一个表"钉"在内存中.
在此情况下,该表将停留在内存,安然无恙.
至此,已经讨论了数据库写入进程所做的工作,也看到了DBWR如何确定哪些记录从高速缓存写到磁盘中.
下一步将要确定什么时候数据库写入进程做写操作.
DBWR在确认下列四种情况之一时,执行写操作.
(1)用户进程把新的"脏"缓存(dirtybuffer)写入到数据库高速缓存(databasebuffercache).
用户进程在检测脏缓存的数量是否超过DBA设置的脏缓存的上限时是足够灵敏的(Oracle基于数据库缓存大小计算,它是DB_BLOCK_WRITE_BATCH的一半).
因为,作为Oracle后台进程世界的好成员,该用户进程礼貌地通知DBWR,是醒来写数据的时候了.
(2)用户进程寻找写数据使用的空闲缓存区,但没有找到.
由于这将花去太多的时间,用户进程并不在高速缓存中扫描每个可能的缓冲区.
其替代做法是,查找由DBA参数设置时规定的缓冲区数量(DB_BLOCK_MAX_SCAT_CNT,该参数由Oracle基于数据库缓冲区的大小来计算).
当用户进程查找了许多缓冲区而没有发现空闲的缓冲区时,就认为是做写入的时候了(这里有大量的缓冲区出现),其后,它通知DBWR开始写.
(3)数据库写入进程本身也例行唤醒,以看看是否有任何脏数据库缓冲区要做写入.
这一时间段设置为3秒.
(4)最后,日志写入进程或检查点进程需要有一些记录写到每个数据文件.
这些记录显示了在检查点产生时,数据库中所对应的最新改变.
因为这一功能对数据库恢复特别重要,这些进程获得了特别的注意.
当它们准备好后,就会通知数据库写入进程,把这些记录写到数据库中.
当数据库写入进程执行后,它传送了多少记录呢对检查点来说,当数据库写入进程被唤醒后,检查点记录直接及时写入,在其他情况下,写入的记录数依赖于DBWR的唤醒方式和Oracle配置参数的设定.
如果数据库写入进程是由用户唤醒的,此时,用户进程检测到脏缓冲区的数量太高或者不能发现空闲缓冲区,DBWR就会进入脏缓冲区,按批写入记录.
有时,Oracle维护脏缓冲区列表中没有足够的有效缓存(在脏缓冲区与正被修改的类表之间,有一个时间延迟).
如果DBWR在脏列表上不能找到足够的数据填充其传输定额(transferquota),它将从最少使用的末尾开始,扫描缓存区列表,以便找到脏缓冲区写到磁盘.
数据库写入进程是一个面向服务的进程.
如果DBWR由于用户进程等待非脏缓存而超时被唤醒,它会采用一种稍有不同的方法写数据缓冲区.
它从最近最少使用末尾开始遍历缓冲区列表,选择脏缓冲区写入磁盘.
DBWR每一次唤醒后,它会搜索DB_BLOCK_WRITE_BATCH指定的两倍大小的缓冲区(这些缓冲区许多并未弄脏,因此也不需要重写).
DBWR找到的任一弄脏的缓冲区都被写入到磁盘中.
每次DBWR唤醒后,它搜索一个新的缓冲区集,这些缓冲区按照最近最少使用算法,排成一个缓冲区列表(list).
最后,如果数据库有相当高的数据输入率,内存中整个脏缓冲区将写入磁盘.
某些操作系统(如UNIX)使我们能够激活多个数据库写入进程共享加载.
所使用的DBWR数量,由inti.
ora文件中的DB_WRITERS参数控制.
Oracle建议,在系统中,每个第7章Oracle8组件和对象287磁盘驱动器至少有一个数据库写入进程.
建议在所给定的时间,为写入到所要求的磁盘驱动器数,应有足够的DBWR进程.
首先要考虑一个合理的值,之后再加大它,看看其性能是否得到了改善.
为了改善其并行化处理的性能,Oracle需要改变它原来所使用的几个基本设计概念.
当要做的工作太多,以至于一个写入进程不能处理时,Oracle能分配多个数据库做写入进程工作.
在通过增加额外的进程改善性能之前,需要理解计算机的体系结构.
对有多个磁盘驱动器(并行数据库写入进程)和多个计算机处理器(如在并行查询选项中)的系统而言,并行化技术是有用的.
像大多数HP和IBM的UNIX服务器,其计算机是基于单处理器体系结构的,它们从多查询处理器中得到的好处远远小于像Sequent和Pyramid系统这样的大型处理器计算机.
同样,所有的Oracle数据存储在一个或两个磁盘驱动器上的计算机,也不能从大量的DBWR进程获得好处.
当添加并行进程时,一定要知道正在做什么,并确保它们将与计算机的体系一起工作.
4.
日志写入进程Oracle在两个地方写每个提交的事务,改进恢复的能力,以防文件完全毁坏.
第一个地方是前面提到的数据库写入进程.
现在讨论写事务的其他记录,把它们从重做日志缓冲区写入到重做日志文件.
这一功能由日志写入后台进程(LGWR)完成.
日志写入进程的一般概念是简单的.
数据库中的每个事务都被记录在日志缓冲区中.
此缓冲区按照先进先出的原则操作.
在系统中,有多个重做日志,日志写入进程以循环方式写入它们.
一个不太复杂的考虑是用户可在系统中输入事务,并一直等待到它们提交这些事务.
只有用户(或者是软件包)发出提交语句,这些记录才是正式的,在此之前这些语句能够被放弃,对其数据文件没有任何影响.
通常,提交经常发生,不会有大量的未提交事务挂起等待处理.
但有时,也会有许多未提交的事务.
LGWR就是设计用来处理这种情况的,并对那些正在处理的已接收的提交语句进行特殊处理.
因此,日志写入进程的处理规则如下:(1)LGWR在收到来自用户进程的提交语句时被唤醒,并执行写操作.
(2)LGWR每3秒被唤醒并写重做日志缓冲区.
在恢复时读日志的那些进程非常聪明,并不改变数据文件中的记录,直到对某一事务接收到了提交语句.
(3)当重做日志缓冲区三分之一被使用时,LGWR写重做日志缓冲区.
(4)最后,当数据库写入进程把数据库缓冲区中的记录写到磁盘时,LGWR确保相应的重做日志缓冲区也写入到重做日志中.
当然,该进程还有一些细节.
例如,如果在数据库中有大量的提交工作正在执行,Oracle可选择把提交的记录分组传送到日志文件,从而提高效率.
同样地,在一组重做日志文件中,实际上也能有数个相似的成员.
另一种情况,如果该组中的一个成员是不可用的(例如,由于其他输入/输出操作,磁盘正处于忙状态),此写入可产生于组中的一个有效成员.
最后,在正常情况下,即没有独立的检查点进程,日志写入进程负责把记录写到数据库缓存区中,它记录在所有数据文件中应用于数据库的最新的系统改变数(SCN),之后DBWR将这些记录从数据库缓冲区传送到磁盘文件.
7.
1.
3选项进程除了前面描述的主进程之外,Oracle8也提供几个进程选项,以完成所需要的功能.
这些选项进程被设计用于满足专门的需要,并不适用于所有数据库.
288Oracle8i数据库开发与专业应用1.
归档进程归档进程(ARCH)是一个概念化的简单进程.
当日志写入进程填写完其中一个在线重做日志文件后,它通知ARCH把它拷贝到序列中的下一个归档日志文件.
ARCH传送此在线重写日志文件的副本到指定的磁盘或磁带上另一个新文件中.
当然,只有当磁带上或文件系统中有有效空间写此归档日志文件时,它才能做这一工作.
归档进程仅在数据库的操作为ARCHIVELOG模式时,才由日志写入进程来启动.
ARCHIVELOG模式是指DBA发出一条ALTERSYSTEMARCHIVELOGSTART命令,或者使用初始化文件中的参数LOG_ARCHIVE_START=true来启动一个实例.
2.
恢复进程另一个进程仅在可选的数据库模式是恢复进程(RECO)时才会出现.
当选择实现分布式数据库时,该进程提供服务.
RECO的目的是要处理在分布式事务中产生的问题.
当试图处理复制数据表或远程表时,必须运用一些特殊的规则.
一旦使用广域网,可能产生许多问题.
如果写入本地磁盘有问题,基本事务写入进程立即作出反应,Oracle设计了RECO,对这类问题具有更多的容错能力,它等待直到与远程数据重新建立连接,之后检查那些不能确定是否记录到远程系统的事务.
它决定是否有来自其他远程系统形成的修改(能通过分布式选项链接许多不同的计算机上的不同的Oracle实例).
3.
加锁写入进程下一个专用进程是加锁写入进程(LockWriter,LCK).
该进程仅在并行服务器选项使用时才运行.
在这种情况下,不能使用由本实例的Oracle内存区提供的单个实例加锁机制.
可以使用的是这些专门的加锁写入进程(可以有10个)互相对话并确保共享数据库中记录被正确地加锁.
再者,单独分出此功能的逻辑是不会把实例间协商的负担加到现在的后台进程中的.
这是一个慢得多的进程,因为,通过单个实例快速共享内存区机制不产生消息.
4.
专用服务器进程这些进程作为传送请求到数据库的用户进程与Oracle实例的内存区和磁盘之间的接口进程.
它们提供诸如谁在对话、需要何种服务及在何处寻求何事等全部职能.
从提供这种连接性开始,它们就用于Oracle.
要记住的关键一点是,所有连接到Oracle实例的用户,都得到一个专用服务器(DedicatedServer)进程,并需要保留到该用户与某实例断开连接为止.
5.
Net8进程近年来,客户/服务器结构已成为相当流行的体系结构.
图7-3解释了这种体系结构的基本构成.
在客户工作站上运行的作业主要是负责显示功能和计算某些结果,服务器端还肩负一些处理工作,包括像数据库管理及一些计算等功能.
图7-3Net8连通性第7章Oracle8组件和对象289与客户/服务器体系结构相关的关键进程是监听器.
此进程监视确定的通信通道(像1512这样的特定的端口安装在TCP/IP下,专供SQL*Net和Net8使用),等待来自客户的请求,之后,它发送这一请求给适当的服务器用户进程进行处理.
当服务器用户进程完成请求所需的处理后,其结果通过监听器发送给适当的客户机.
6.
并行查询进程并行查询(Paralledquery)进程在Oracle8中是有效的.
当考察解决复杂的查询这类任务时,发现有许多必须执行的步骤,这些任务可由单个操作系统进程执行.
不过,因为大多数操作系统分配这些任务到单个CPU,单个CPU每秒钟所能执行的总步数是有限的,但这却有助于确定查询的响应时间.
如果能把这个大型查询分解成一系列任务(或者把大表分解成片段用于不同的进程,或者一方面在索引上查询,而另一方面查找主表中与索引查找相匹配的记录),就能分配多个CPU完成该工作,因此,完成这一作业就快得多.
这就是Oracle中并行查询的目的.
当在并行查询方式下操作数据库时,DBA产生大量并行查询进程.
它们等待直到用户进程发生查询前,此查询能得益于它们的服务.
当这种情况发生时,它们全力开始执行查询,这由用来分解这类工作的特定逻辑集决定.
7.
Web服务器进程Web服务器结构是概念上与前面的客户/服务器体系结构相像的体系结构.
这一技术被开发用于在因特网上传送图像和文本,其后它已扩展到包括多媒体内容,甚至用于分布式程序设计(例如Java小应用程序或ActiveX控件等)的其他形式.
从进程的观点来看,该体系结构是相当简单的,如图7-4所示.
图7-4Web服务器进程这里,Web监听器进程功能与SQL*Net监听器相似.
它连接用户工作站到合适的服务器进程,以实现进一步的处理.
当然,Web监听器也有其他的任务,像获取Web页面(HTML)和直接从磁盘文件中获取其他媒体内容,不过,此进程与执行大量计算的进程相反,其主要功能像一个信息路由器.
如果要在服务器上执行计算,它或者传送这些任务到另一个已存在的进程(它们与一个Oracle数据库相连),或者产生一个新的进程运行该项工作.
经过Web服务器进程连接到Oracle数据库有几个选项,可使用OracleWeb或者Web应用服务器,Web应用服务器高度实现了本地数据连接嵌入.
也可选择使用第三方Web服290Oracle8i数据库开发与专业应用务器,比如由Netscape或Microsoft所提供的.
在这种情况下,通常不得不写小应用程序,获取来自用户的原始请求,并把它们转换成能被数据库处理的格式.
这里采用ODBC或JDBC驱动程序的形式.
7.
2Oracle内存对Oracle及大多数其他多用户数据库管理系统而言,物理内存意味着速度.
存储在物理内存中的数据比那些即使是存储在最快的磁盘或光盘驱动器中的数据的存取速度要快得多.
本节提出的关于内存的讨论,集中在Oracle数据库所需的细节级.
尽管许多开发者并不需要这级细节,但当开发者试图超越它们的应用,改善其性能时,这些知识迟早是有用的.
本节主要讨论以下内容:(1)在不同的内存区,Oracle存储不同类型的信息;(2)对不同的内存区来说,其空间不足的影响是什么;(3)对不同的内存区来说,存储参数值是如何设置的.
7.
2.
1在Oracle8使用内存在研究每个内存区所包含的的细节之前,需要考虑的是把什么内容放到内存中,才能使数据库管理系统高效地工作是很有用的.
某种程度上,这依赖于DBMS设计者的爱好和风格,但是,一般来说,想要使用内存以提高速度的多用户DBMS,应把下列内容放入内存:(1)已经增加或改变的表中的各行.
它们首先被写入内存,所以用户进程不需要等待从磁盘上获取数据就能继续执行.
(2)那些与用户当前正在工作的行密切相关的行.
在大多数应用中,用户想要的下一行很可能与当前行相关联.
因为,大多数操作系统从磁盘驱动器中读出完整的块(512字节或者更多),如果在内存中存储了这些额外检索的行,那么很幸运,所需要的后续行正在高速内存中等待着.
(3)正在运行的应用程序所需的空间.
计算机执行存储在内存中的指令.
如果想要使一般的应用程序工作,则需要拥有一定的内存空间.
同样的概念适合于各种Oracle后台进程的存储代码.
(4)Oracle数据库进程与终端用户进程之间通信的信息.
该信息使许多操作系统进程能够与应用相关,这些应用使用Oracle数据库协调它们的行动.
1.
虚拟内存碰到要考虑的问题之一是,实际内存和虚拟内存的使用.
对那些不使用这一术语的人而言,实际内存由计算机随机的存取内存(RAM)芯片组成.
这种内存具有本节中所讨论的全部速度方面的优点.
大多数用户计算机系统,包括MicrosoftWindows和Macintosh操作系统,都提供被称为虚拟内存的机制.
虚拟内存是磁盘驱动器的一部分,用它来存储内存的溢出区,虚拟内存能够比实际内存运行更多的进程.
当有大量不经常运行的进程时,它工作得特别好.
因此,当它们需要从内存换出磁盘时,并没有更多的性能方面的影响,换出的进程,像它们驻留在内存一样,传送程序和数据到一个或多个磁盘驱动器上的特定区第7章Oracle8组件和对象291域,所以,空闲的实际内存可由其他进程使用.
不过,在Oracle中,实际上想要所有的Oracle内存区都存储在实际内存中,因为这种体系结构的目的就是要提高速度.
2.
系统全局区Oracle把它的内存区划分为几个部分.
系统全局区(SGA)拥有全部的公共数据存储区(如放在缓冲区中的事务、数据字典信息等).
程序全局区(PGA)存储在与各进程相关的数据.
用户空间与Oracle后台进程和用户进程正在运行的软件相关.
最后,排序区用于存放与用户查询相联系的排序数据.
3.
共享内存作为DBA,要理解的一个重要概念是控制内存区域如何设置成共享.
许多内存区(像UNIX中注册后所分配的shell,或者MicrosoftWindows所分配的内存区)并不是可共享的,只有DBA可以访问那些内存.
但共享内存是例外的,通常,使用共享内存区需要从系统管理员处得到特许,而具体的操作方法随操作系统的不同而不同.
只要正常安装由Oracle提供的RDBMS软件,那么在它创建新的数据库实例时,就会具有所需要的许可权(一般通过用户拥有的ID号)设置可共享的内存区,而不必采取任何明显的活动.
能够通过初始化文件的组合,以及Oracle在操作系统中安装其缺省产品的缺省参数,控制内存区.
从缺省设置开始,Oracle考虑到特定类型计算机的平均配置并附带了决定SGA、PGA及排序区大小这些参数的一组缺省值.
很明显,为Oracle的MicrosoftWindows版本的配置其设置要比大型的VAX计算机的配置小得多.
这些参数的设置能够被初始化文件中所键入的值取而代之.
7.
2.
2系统全局区(SGA)SGA(SystemGlobalArea)被认为是Oracle的心脏,如图7-5所示.
在进程准备把数据写入磁盘之前,它拥有对数据库所做的改变.
它存储的内容能帮助更快地存取数据.
没有SGA,就不能有Oracle数据库.
任何DBA关注的事情都是重要的.
图7-5系统全局区(SGA)SGA个部分的组成如下:(1)数据库(块)高速缓存区;(2)重做日志缓冲区;(3)共享池;292Oracle8i数据库开发与专业应用(4)进程间通信区;(5)多线程服务器队列(在使用时).
1.
数据库缓冲区高速缓存数据库缓冲区高速缓存存储Oracle数据库各表中的记录.
实际上,Oracle数据库读出和写入数据是按块方式,它存储包含正在使用的记录的整个数据块.
这些块包含已经从数据文件中读出的行,或者是那些需要写入到数据文件中的记录.
事实上,数据库缓冲区高速缓存是一个分站(Way-Station),位于用户和数据文件之间,正像大多数的旅馆一样,在招待这些客人时,有容量上的限制.
因此对DBA而言,理解Oracle如何确定单块停留多长时间是非常重要的.
确定一个记录需要在高速缓存停留多长时间的最简单的方法,涉及到等待写入到磁盘的新记录或已被修改的记录.
它们停留在数据库缓冲区高速缓存直到它们由数据库写入进程写入到磁盘.
如果感到太满时,Oracle开始释放数据块,数据库缓冲区高速缓存不再工作.
对剩余的缓冲区,它们已经从磁盘读入但还没有修改,Oracle必须决定,哪些要保留,哪些要清除.
许多系统使用先进先出方法,这看起来很公平,但对多数数据库来说这并不是一种高效的方法.
许多记录要经常存取,例如,公用查找表,所以,保留这些常用的在内存中,删除那些不使用的会更有意义.
实现这一概念的算法被称为最近最少使用法(leastrecentlyused,LRU).
当Oracle查询从数据库中读出一条记录时,包含该记录数据的块存储在数据库缓冲区高速缓存中,并按照最近最多使用放在记录列表的尾部.
每次使用数据缓存区高速缓存中的记录,它都是按最近最多使用被放入列表尾部.
当查询需要空间来存储从磁盘中读出的数据,而数据库缓冲区高速缓存中的所有缓冲区都满了的时候,它必须覆盖非脏的最近最少使用算法列表尾部,脏是指从磁盘中读入以后被修改过的顶部.
如果再次需要被覆盖的记录,则它们需要从磁盘中调入.
该进程通过在内存中存储数据,避免了从磁盘中缓慢地传送数据,从而节省了时间并工作得很好.
下面讲述一种更好的方法,除非有非常大的实际内存,否则必须把数据库缓冲区高速缓存限制在一个合理的范围内.
因此,LRU算法从一个短期(也许几分钟)视点查找数据.
无论如何,应该非常了解应用及用户,并理解这个"大画面",知道有几个经常使用的相对小的表(也许他们是用于查找调用大数据表的信息).
LRU算法可以在其中一个查询开始处,就把这些行调入数据库的高速缓存,但是,当从上述大的主表中一行接一行地移入数据时,它们最终会被淘汰,当下一个用户进行查询时,不得不重新启动此过程.
不过,Oracle7.
1及更高的版本提供了在内存中高速缓存一个表的选项.
这个选项具有将整个表装入内存的能力,并保持该表靠近最近最多使用的数据库缓冲区高速缓存的尾部.
必须谨慎使用这一方法,因为太多的缓存表会填满缓冲区高速缓存,这会使得读行数据时磁盘存取速度减慢,但对合适的数据库来说,这种方法对提高数据库的速度确实是一个有用的工具.
其使用方法如下:SELECT/*+CACHE(igreene.
lookups)*/parameterFROMigreene.
lookupd;下面讲述SGA区域中的重做日志缓冲区.
修改Oracle的数据文件记录在数据文件中,同时也单独写入重做日志文件中,这个事务记录使Oracle能在磁盘驱动器完全丢失事件时第7章Oracle8组件和对象293恢复数据.
重做日志事务存储在内存中以优化写性能,因为大多数操作系统写块都是以千字节为单位,整个数据块排队之后写入效率更高.
因为重做日志缓冲区是为与读出相对应的写入而设计的,它使用先进先出的方法存储.
重做日志项按其接收顺序加到缓冲区中.
Oracle的日志写入进程出现并获取这些记录的一个或多个块,把它们写入到联机重做日志文件.
对重做日志项而言,重做日志缓冲区则作为它的中转站,位于创建数据库修改事务的Oracle进程和磁盘重做日志文件之间.
2.
共享池SGA中五个区域的第三个是共享池.
已经看到了在内存中存储数据的优点,这些数据最近刚从磁盘读出或者需要写入到磁盘的数据文件及日志文件中.
Oracle开发人员查看数据库所提供的服务,并在内存区存储大量其他内容以改善总体性能.
共享池包含三个性能改进内存区,如图7-6所示.
(1)共享SQL区;(2)数据字典高速缓存;(3)游标.
图7-6共享池内存区共享池的第一部分是存储Oracle调用的共享SQL区.
结构化查询语言(SQL)是与数据库交互的标准方式,Oracle,IBM,Informix以及现在市场中占有率较高的多用户数据库都使用SQL.
SQL语句的例子为Select*frombig_payrall,该语句从虚构的表big_payrall中返回全部的行和列.
Oracle需要做一些工作来实现这一请求.
例如,Oracle需要指出在表big_payrall中都有哪些列,是否有索引可用于提高查询的速度,用户是否有存取这些数据的权限及是否可获得该数据的许多其他信息.
在许多数据库中,有一系列查询经常被使用(例如,预定输入系统经常要用到有效产品代码列表).
共享SQL区还存储已分析过(或语法分析)的查询,其他用户存取时就不再需要对该查询进行语法分析.
查询存储在共享SQL区中也被称为库缓存,使用LRU算法进行更新.
共享池的第二部分是数据字典高速缓存.
在数据库的所有查询和事务中,数据库管理系统需要决定数据放在哪里,它包括这样的细节:如对象(表)名是什么;它们位于什么表空间;它们的记录在数据文件中的什么位置;它们的列名叫什么.
此外,数据库安全性要求Oracle验证用户对数据库对象是否有适当的权限.
所有的这些字典数据信息存储在数据库的各个系统表中.
这些经常使用的信息放入高速缓存.
为此,数据字典高速缓存存储294Oracle8i数据库开发与专业应用上述系统表,以便RDBMS快速存取.
有时,数据字典高速缓存也被叫做行高速缓存.
行高速缓存指存储数据库(数据库缓冲区高速缓存)中的数据行的区域.
共享池的最后区域是游标.
游标实际上存储在共享SQL区,但是,由于它们在概念上不一样,所以分别讲述.
前面的SELECT语句所产生的查询结果要显示在屏幕上.
如果要在内存中存储查询的结果以便能以某种方式操纵数据,基本上来说,这是游标所做的工作.
它存储从数据库中检索出的数据用来进一步处理.
当Oracle执行像CREATTABLE这样的语句时,Oracle创建自己的内部游标(称为递归游标).
这样的语句产生对各个数据字典的大量修改操作,它们是一系列SQL语句,也可递归调用,由Oracle在后台处理.
这两种形式的游标占用共享SQL区的空间,当调整共享池大小时,应该充分考虑,同时还要注意,支持游标所要求的存储区域在PGA中.
讲述了共享池,现在该讲述SGA的第四个区了,这一内存区并没有一个富有魅力的名字.
它用于存储与Oracle数据库操作相联系的不同进程传送的信息,使用该内存区具有很多优点,如通过进程锁定应用对象.
一个好消息是对这些消息区还没有特殊的性能优化参数,也不需要DBA进行干涉.
一旦共享池中有足够的空间,就可设置.
SGA中可占用空间的最后部分是多线程服务器队列所要求的空间.
在讨论Oracle这种密集集成系统时,其难点之一是有时不得不在描述某一主题之前就引用其内容.
基本上,多线程服务器是Oracle的一种特性,它使用户能共享内存区和进程,这些共享内存区和进程用于把用户应用连接到Oracle数据库.
因为这些内存区存储在SGA中并影响它的大小,所以在使用多线程服务器选项时,要浪费数以百计的用户的内存复制这些相关的公共内存区.
DBA将是管理SGA的人,所以,第一项任务是监视SGA,在ServerManager中输入下面的命令:showsga该命令产生的结果,与下面例子中所显示的内容一样,该命令也同样用于大型平台:SQLDBA>showsgaTotalSystemGlobalArea4767460bytesFixedSize36432bytesVariableSize3846292bytesDatabaseBuffers819200bytesRedoBuffers65536bytes7.
2.
3程序全局区(PGA)系统全局区为全部用户需要共享的内容提供内存.
但也有很多用户需要保持自己特有的内容,这就要用到程序全局区(ProgramGlobalArea,PGA).
当用户连接到Oracle数据库时,所有的用户都分配了PGA.
该内存区的大小由操作系统确定,并且,只要用户与Oracle相连,就保持不变.
对PersonalOracle用户和那些仅有少量的用户的系统来说,这是一种可用的工作方法.
不过,许多大型事务处理系统,在给定时间可以有几十乃至上百的用户连接到数据库,在这样的大型数据库中,映射了SGA所需的大量内存,并且,此后也把每个用户进程和操作第7章Oracle8组件和对象295系统本身加入到内存中,大量的PGA将没有太多的空间可用.
这就是多线程服务器的作用.
在许多情况下,可以有大量的用户同时登录到数据库计算机上,但是,它们中只有较小的一部分真正要执行查询或修改.
大多数用户或者读系统的输入,以很慢的速度键入,或者正在想问题.
Oracle的多线程服务器被设计用来分配数量的空间,供存储特定事务的信息.
这些信息包括私有的SQL区及其他这类与特定问题相关的项目.
用户仍然保留空间以保持与其工作相关的变量和其他数据,例如像栈空间专用于它们独自的会话.
不管有或没有多线程服务器,存储在PGA中的数据如图7-7所示.
WithoutMultithreadedServerWithMultithreadedServer图7-7程序全局区的内容关于PGA的最后几点注意事项如下:(1)PGA属于单用户进程并仅由该用户能够读写它;(2)如果未使用多线程服务器,计算机中也没有足够使用的内存,就会从Oracle中接收到一个出错信息;(3)如果正运行在客户/服务器的配置方式下,用户的PGA将在作为数据库服务器的机器上分配;(4)一些资料提到PGA是进程全局区(ProcessGlobalArea)而不是程序全局区,其工作是一样的;(5)PGA的大小随着运行在不同操作系统上的Oracle版本而改变.
在给定实例中有3个参数会影响它们的大小,即打开数据库链接的数量,及有效角色和日志文件数.
对大多数DBA而言,理解PGA已经足够了.
一般DBA不必对PGA做更多的工作,除非他们运行的计算机系统中内存较少.
因为所涉及的参数由应用需求控制,DBA通常必须获得额外的内存,或者使用多线程服务器选项解决PGA内存限制问题.
7.
2.
4用户工作空间前面介绍了Oracle内部使用的内存区,其中运行用户的数据库服务.
但那些为执行进程任务所设计的实际应用,它们运行的时候都需要内存区——工作空间.
有许多重要数据存储在该区,如图7-8所示.
296Oracle8i数据库开发与专业应用图7-8用户工作区(1)Oracle进程的软件代码区;(2)用户进程的软件代码区;(3)排序区.
1.
Oracle应用软件内存此内存空间通常存储Oracle用户拥有的Oracle应用软件代码,并由操作系统保证其不被其他用户所修改.
这些内存区经常以共享方式来安装,以便用户在需要时能够访问软件的某一部分.
在同一台计算机上有一个Oracle软件的拷贝供每个Oracle实例使用,这是大家所希望的.
Oracle应用软件代码区的大小通常仅当软件升级时才改变.
2.
用户进程的软件代码区接下来要讨论的软件区还是由常规用户进程使用的内存空间.
大多数Oracle工具和DBA应用程序将工作在共享方式下,不过,许多应用程序要求每个用户有单独的工作区.
与SGA相比,这些用户区都相当小.
不过,当系统中有大量的用户时,DBA和系统管理员可能需要密切注视这些进程.
与SGA不同,如果不活动的用户进程换出到磁盘上,并不会产生特别的性能问题.
3.
排序区最后要讨论的用户内存区是排序区.
SQL查询中最常用的子句之一是Orderby子句.
没有人愿意按Oracle选中的记录次序返回长长的输出结果.
因此,大多数应用程序运行大量的排序.
当执行排序时,内存的速度是特别值得注意的.
如排序无法在内存中进行,此排序查询很容易花去5~10倍甚至更长的时间.
无论如何,尤其在大型数据仓库的Oracle实例中,也许不得不给数据排序,它们不适合放在系统的物理内存中,因此,不得不使用基于磁盘的排序.
排序区大小的改变依赖于应用的需要.
它的最大值由参数SORT_AREA_SIZE所控制,该参数既可以在初始化文件中设置,也可以使用操作系统的Oracle缺省值.
一旦排序完成,排序区的大小则减少到参数SORT_AREA_RETAINED_SIZE的指定值.
如果要排序的整个数据集在排序区放不下,数据则先按块(chunk)在内存中排序,之后,各块再合并在一起.
7.
3Oracle文件下面列出的Oracle组件是与数据密切相关的数据文件.
内存区仅在计算机操作时存储第7章Oracle8组件和对象297数据.
对永久性存储的信息而言,需要使用像磁盘这样的介质.
并且,当内存价格下降时,磁盘介质的成本仍比计算机内存的成本少很多.
因此,Oracle设计为在使用物理内存满足速度的要求与使用磁盘上的文件满足存储成本效能的要求之间取得平衡.
本节将讨论与Oracle数据库相关的不同文件和它们的内容,以及它们是如何使用的.
7.
3.
1Oracle文件和它们的用途就典型的PC软件产品安装而言,是把一些文件放入主目录下的一个目录或一系列子目录中,一般知道所需的一切在什么地方.
本节涉及的Oracle数据库的文件,数以百计,也许上千,它们分散在大量的目录中.
本节展示文件存储的总体情况,然后重点讨论DBA经常使用的文件.
有大量的文件并不在Oracle系统中.
但每个Oracle的附加软件包(OracleForms、SQL*Net、Net8等)添加了更多的文件.
不过,从DBA的角度来看,可将许多文件划分为下列类别.
1.
Oracle软件这是一些被购买并安装以使系统工作的文件.
这些文件在系统中形成大量的成千上百的Oracle文件.
一般来说仅需在安装的时候关心这些文件.
如果它们没有正确地加载和连接,仅有的办法是请求Oracle支持,让它们帮助恢复工作.
2.
数据文件当第一次创建一个实例时,仅有少量的数据文件.
事实上,在早期的Oracle版本(6或更早的版本)中,只有单个的数据文件.
而在Oracle8中,按缺省方式,至少有四个数据文件.
如果有跨越多个磁盘的超大型数据库,则可以有几十个数据文件.
这些是相对容易管理的资源,因为,数据库视图能够很快地定位这些文件.
与其他类型的Oracle文件相比,要更经常地对数据文件的大小进行维护.
3.
重做日志文件系统仅有少量(正常情况下约为4个)重做日志文件.
在数据库中有视图帮助定位这些文件.
只有在为增强性能改变重做日志文件的大小或移动它们时,这些文件才需要维护.
4.
归档日志文件当在归档日志方式下操作数据库时,这些文件将是最关心的.
如果这些文件写满了目标设置,它将停止对数据库的全部修改和插入操作,并且也会使实例崩溃.
它明确地知道归档日志在哪里,并监视它们的大小,例行地清除它们.
5.
控制文件如果运气好,在创建一个Oracle实例后,将永远不会被控制文件所困扰,这些文件通常提供配置信息和状态,帮助启动Oracle.
当修改数据库配置时,会改变它们的内容,但此后仍由Oracle管理它.
6.
初始化文件这些文件存储启动系统所需要的信息.
它们包括控制文件的位置和全部性能优化参数,设置这些参数可以调整实例的性能.
实际上,只有在对Oracle数据库进行优化时,才会关心这些文件.
7.
日志和跟踪文件主要的Oracle进程已设计为在它们产生问题或出现故障时保留系统中的最后消息.
当298Oracle8i数据库开发与专业应用它们检测到错误时,系统实际上有进程在监视其他进程的活动,并记录相应的信息.
8.
审计文件Oracle能够审计在数据库中产生的确定事件.
既可以在数据库中也可以在文件中存储活动的记录,这种选择在初始化文件中规定.
7.
3.
2数据文件数据文件也许是完成Oracle系统中最重要的功能——按可检索格式存储数据.
这些文件不能从操作系统的实用工具中直接读取,如UNIX的More或者微软的Windows下的Notepad,可以通过SQL查询它们的内容.
当使用SQL命令工作时,规范了表空间和表这样的逻辑结构.
物理结构是Oracle的事情.
之后,作为DBA,把这两个放在一起进行映射,如图7-9所示.
图7-9物理-逻辑数据结构要记住的是每个数据文件仅与一个表空间相连.
一个表空间有一个或多个数据文件.
当决定给定的表空间中数据文件的书目时,DBA必须做一个权衡.
所有的数据表(datatable)放在一个大的表空间里是容易管理的,不会出现有表超出一个表空间的空间之外,而在其他的表空间中有大量空间却不能使用的现象.
不过,由于不能控制表空间中数据文件里表或索引的位置,因此就不能在磁盘间拆分输入输出.
也有这样的情况,在占据系统的所有可用空间之前,宁愿用户由于填满表空间而停止工作.
这里有一个例子,如果为共享单个数据库的不同工程分配空间,需要记录大量的数据文件,这将花费系统资源,所以,经常要把拥有的文件数量降到一个合理值.
存储在每个Oracle数据文件里的是最新改变数值(Oracle的术语叫SCN)的记录.
这些数值应用于系统.
在这种方式下,当从磁带上恢复备份的数据文件时,Oracle能够确定哪些需要应用数据文件更新成新内容.
关于数据文件要记住的另一个特点是它们由操作系统预分配其全部大小,该大小在创建命令中定义.
如果为一个表空间分配了100MB的文件,那么该数据文件将占去100MB,即使它不包含任何表或数据.
这种预分配概念应用于数据库对象.
与表一样,也是在表空间和它们的数据文件中创建的.
如果用一个10MB的初始第7章Oracle8组件和对象299范围(initialextent)创建表,那么将有一个10MB的表空间扇区被保留,即使该表中不包含任何数据行.
下面简要地列出了应该知道的有关数据文件的其他内容:(1)有两个通用类型的数据文件——raw(生的)和cooked(熟的).
工作中使用的正常的操作系统文件可认为是"熟"的,因为它们使用操作系统提供的文件系统实用程序.
在一些早期的操作系统中,特别是老版本的UNIX实现中,其上层与操作系统文件管理实用程序相连,这将使Oracle减慢,所以,Oracle增强了其软件与磁盘驱动器直接通话的能力.
这些就涉及到"生的"磁盘.
随着大多数现代操作系统的实现,生熟磁盘驱动之间的速度差别已经变小,但有时在某些方面,熟磁盘驱动能够提供更好的性能.
(2)有多个表空间的主要好处之一,是在多个磁盘驱动器或磁盘控制器之间平衡输入/输出加载.
一般来说,要把表和它们的索引分散到各自的表空间,这些表空间位于分开的磁盘,这样可获得最大化性能.
也要把回滚段和临时段从表和索引数据文件中分离出来,以防止这些表空间的输入/输出相互之间产生竞争.
(3)因为每个到数据文件的写事务都有一个重做日志文件的事务镜像,通常要把数据文件与重做日志分开放在不同的磁盘驱动器上.
(4)最后,Oracle提供了一个令人感兴趣的特性——只读表空间.
指定把只读的表空间假定为最新的,无需检查它们的最新修改号(SCN).
这最终能把表空间定位在CD-ROM这样的设备上(不能写到记录中,修改SCN).
它也能为包含不再修改的参考数据的表空间节省时间.
如果这些数据文件中的一个丢失,可以从备份磁带上拷贝该数据文件并使它联机.
Oracle认为,不必试图应用重做和归档日志事务恢复最新的文件.
上述信息是理解Oracle数据文件的基础,后面讨论的对象是,在数据文件中的定位和表空间及数据文件的维护.
下面是一条SQL查询语句,它能确定数据文件的位置:SQL>select*fromsys.
dba_data_files;FILE_NAMEFILE_IDTABLESPACE_NAMEBYTESBLOCKSSTATUSC:\ORAWIN\DBS\wdbrbs.
ora3ROLLBACK_DATA31457281536AVAILABLEC:\ORAWIN\DBS\wdbtemp.
ora4TEMPORARY_DATA20971521024AVAILABLEC:\ORAWIN\DBS\wdbuser.
ora2USER_DATA31457281536AVAILABLEC:\ORAWIN\DBS\wdbsys.
ora1SYSTEM104857605120AVAILABLESQL>实际上,在创建了数据文件之后,对数据文件就没有什么要做的了.
这样可以把精力集中在维护与文件结构相对的数据库对象上,以及其他由OracleDBMS软件管理的技术细节上.
300Oracle8i数据库开发与专业应用7.
3.
3日志文件重做日志文件经常被作为联机重做日志文件(theonlineredologfile),以区别归档日志文件(theactivelogfile).
系统的日志文件的数量和大小是可以控制的.
基本上讲,当归档日志文件时,有少量的并且比较大的重做日志文件在做日志交换方面是有好处的.
当重做日志拷贝成归档日志时会扩大几倍.
这在对创建归档日志文件的磁盘的输入/输出传输率有限制时是重要的(在重写联机重做日志文件之前必须完成拷贝操作).
联机重做文件的数量固定,它们按循环方式使用,如图7-10所示.
当结束写入第一个文件时,进一步的事务被写到第二个文件.
这个进程连续不断,直到在序列中完成写入到最后一个文件,这时,将再一次开始写入第一个文件.
在归档日志方式下操作时必须小心,因为一个在线重做日志文件的内容不能被重写,直至这个重做日志文件完全拷贝到归档日志中.
举例来说,如果Oracle的归档日志文件的文件系统是满的或处于脱机状态,它不能将重做日志文件写到归档日志文件中,Oracle也不能接受事务.
系统发生阻塞,对那些试图执行修改、删除或插入操作的用户,将返回出错信息.
更糟糕的是,有时这种方式非常混乱,以至很难再次将系统恢复正常.
图7-10在线重做日志文件循环一个重做日志文件每次都记录每个事务的方法,可能产生输入/输出瓶颈.
可以选择创建重做日志文件组,如果组内成员之一所在的磁盘正处于忙状态上,事务被写到该组中可用的重做日志文件中,在稍后一段时间内,修改正在打开的日志文件,使之与重做日志文件一致.
有几组日志文件,每组日志文件就有几个成员.
下面是一个命令的例子,该命令用于决定实例中连接了什么重做日志文件:第7章Oracle8组件和对象301SQL>select*fromv$logfile;GROUP#STATUSMEMBER2C:\ORAWIN\DBS\wdblog2.
oraC:\ORAWIN\DBS\wdblog1.
oraSQL>这里是几个极少使用的在线重做日志方面的维护活动:(1)可以增加额外的重做日志文件.
如果使用与组方式相反的单个日志文件,该命令是:alterdatabaseaddlogfile'filename'size###k.
如果正使用日志文件组,该命令是:alterdatabaseaddlogfilegroup#('filename1','filename2'size###k.
(2)可以删除已存在的重做日志文件.
该命令是:alterdatabasedroplogfile'filename'或者是alterdatabasedroplogfilegroup#.
(3)可以以手工方式关闭当前正在写入的重做日志文件,以便能完成一些维护.
Oracle在日志文件或日志文件组正在使用时,不允许做任何维护.
因此,要关掉日志文件或日志文件组,可以使用命令:altersystemswitchlogfile.
从前面的介绍中可以知道归档日志文件几乎没有连续的在线重做日志文件拷贝.
它们的内容是一系列已经应用于数据库的事务.
关于归档日志文件还需要知道两个关键点:存储归档日志文件的可用的选项和如何安装数据库以使用归档日志文件.
归档日志文件有两个基本的存储选项.
第一个选项是在一个磁盘驱动器上使用空间.
另一个选项是直接把这些日志文件写到磁带上.
有正反两种:(1)归档日志写到磁带上,节省更多的昂贵的磁盘存储空间用于其他目的;(2)归档日志写到磁带上必须从更慢的带式介质上恢复,在此事件中,需要做覆盖;(3)归档日志写到磁带上要求专用磁带驱动器,这并不是在所有系统上都是可行的.
使Oracle开始写归档日志是更困难的问题.
如果在表空间中创建数据文件,在用户将数据放置到它的表空间时,Oracle自动地将它写到表空间.
在创建实例后,Oracle也自动地把它写到所创建的重做日志.
不管怎样DBA不得不通过有些繁琐并且极其敏感的进程使Oracle写归档日志:(1)进入初始化文件,设置LOG_ARCHIVE_START参数为True.
该参数并不像期望的那样真正开始做归档日志.
如果所有其他的参数都被设置,那么该参数将给Oracle一些权限以便开始归档日志,并仅在重新启动Oracle实例时才有效.
(2)告知归档日志文件名称的格式,确切的语法在《SQL语言参考手册》中,但是经常也可接受缺省格式.
(3)告知Oracle文件附在何处、如何命名将开始归档的文件.
这需要规定目录路径和归档日志文件的头几个字符.
比如有一系列归档日志文件,它由文本字符串alog开始,位于目录/disk57/Oracle/logs下.
设置LOG_ARCHIVE_DEST参数为:LOG_ARCHIVE_DEST=/disk57/Oracle/logs/alog.
归档文件名的第二部分是一个字符串变量,一般来说,它包括序列号.
它的格式由参数LOG_ARCHIVE_FORMAT规定.
这个参数有一些选项,但是其缺302Oracle8i数据库开发与专业应用省值就工作得很好,它的形式为:LOG_ARCHIVE_FORMAT='%s.
arc'.
(4)正常关闭Oracle实例,执行一个完全备份(处于安全的原因,请不要跳过此步),由于数据库未打开,使实例停止(这是SQL*DBA中的启动装配独占命令).
当数据库已经启动后,输入命令:alterdatabasearchivelog;(5)现在可以打开数据库了.
确信归档日志文件已被创建.
这是一个非常敏感的过程,语法上没有引起问题的错误.
通过使用下面的命令强制关闭重做日志文件来核查正在写入的日志文件:altersystemswitchlogfile;当Oracle由于一些小的语法错误拒绝LOG_ARCHIVE_DEST参数时,常常是一个令人生厌的过程.
一旦有了归档日志操作,经常需要关心归档日志文件的运行空间,并锁住Oracle把事务写入到数据库的能力.
无论如何,可以恢复所有的已经提交的数据,直到磁盘的失败点.
7.
3.
4控制文件在讨论完归档日志文件之后,下面讨论相对容易的控制文件.
如果运气好,只创建一个Oracle实例时才不得不考虑控制文件,这是因为,控制文件是Oracle内部使用的,不能手工编辑它们,也不能控制它们的大小,而只能移动它们.
只有丢失了什么文件的时候才会注意它们.
这时,Oracle将给出一个消息,指明哪个控制文件丢失了或者被损坏了.
当这种情况发生时,需要拷贝其他的控制文件(它们相互是相同的)到丢失的控制文件的位置上,然后重新启动系统.
控制文件是数据库在计算机系统中物理分配的线路图.
它们存储数据库的名称、数据文件和重做日志的名称,以及它们创建时的记录.
如果需要的话,可以增加控制文件或者删除已存在的控制文件.
在定位控制文件时,一个不能忘记的原则是:始终要保证至少一个控制文件是可用的,以便能够重建其他的控制文件.
可以用手工方式重建控制文件.
因此,要尽可能地把控制文件分散到几个磁盘上,以便总有一个控制文件用来启动实例.
7.
3.
5初始化和配置文件Oracle通过访问控制文件确定实例的物理配置.
不过,有大量的配置参数与性能优化相关,不需要在每次启动实例时手工再设置.
为了使这一切更容易,Oracle提供了一系列初始化文件,它们与DOS的autoexec.
bat和config.
sys相像.
在多用户的Oracle系统中,有两个主要的初始化文件:(1)init.
ora这是一个主要文件.
它的实际文件名包含Oracle实例的SID(系统ID).
因此,一个名为blue的实例将有一个名为initblue.
ora的初始化文件.
(2)config.
ora一般来说,config.
ora文件包括控制文件、归档文件及转储文件的位置.
它们还包含数据库名和数据库块大小的参数.
这些文件包含的参数值在实例之间是相同的,init.
ora包含的参数可在实例间进行优化和改变.
与init.
ora文件一样,config.
ora文件名中也包含SID(如configblue.
ora).
config.
ora文件由init.
ora文件中的一行命名,它指示使用第二个初始化文件(ifile=filename).
第7章Oracle8组件和对象303初始化文件是简单的文本文件,可以使用标准的操作系统编辑器编辑它,例如,UNIX中出色的vi编辑器.
其格式是简单的,即设置变量等于一个值.
关于这些文件的安装有两个不足之处:首先,必须在做某项工作时对两个文件进行编辑;其次,数据在文件中是如此分散,以至很难看到设置了什么项,并且也没有过去使用它们的历史记录.
因此,宁愿重做初始化文件,使其包含下面几个部分(一个UNIX系统的init.
ora示例文件包含在磁盘上):(1)文件头包含文件名、用途及全部参数变化的历史记录,以便参数改变后不能正常工作时,知道在哪儿设置它.
(2)把影响SGA大小的所有参数分成一组.
不包括被注释的参数,仅包括正在用的参数.
(3)把影响PGA大小的所有参数分成一组.
(4)把处理日志的所有参数分成一组.
(5)把有国家语言支持(NLS)相关的参数分成一组,NLS是Oracle的工具,它支持数据库在数据方面使用多种语言,就像日期格式一样.
(6)如果多线程服务器选项被使用的话,把与多线程服务器相关的参数分成一组.
(7)通用类别包含其他繁杂的参数,比如是否使用多数据库写入进程.
(8)最后,在某些情况下,Oracle建议把一些非文档参数增加到系统中,以使系统运行得更好.
当大型数据仓库一起工作时,这是常有的情况.
还需要注意一些更详细的信息.
在多用户Oracle系统中,可以在ORACLE_HOME目录下的dbs目录中发现init.
ora文件.
在ORACLE_HOME目录下,能够找到全部Oracle软件和管理文件.
如果这不包含实际的文件,它至少包含一个指向init.
ora文件的链接.
config.
ora文件放在ORACLE_BASE/admin/instance_name目录下的pfile子目录里.
在PersonalOracle中,仅有init.
ora文件,它位于/orawin/rdbms目录下.
在Oracle初始化文件里,这些足够开始工作了.
如果对Oracle实例的可用性做一个测试,在处理公司所依赖的日常操作的实例之前,试一试变更此实例的配置文件和优化参数.
如果要谨慎一点,那么可以用其他名字对原先的初始化文件做一个拷贝,然后每次试着调整一个参数,直到对该实例产生了自信.
这里是一个公共数据表,可以在Oracle数据库的初始化文件中找到它们.
其他的参数是在特定的情况下使用的.
但是,几乎每一个初始化文件中都能看到这些参数.
(1)db_name这是数据库的内部名.
该名字被编码保存到控制文件中,所以,一旦数据库创建,就不得不使用正确的名字.
(2)db_files列出数据库文件允许的最大值.
(3)control_files该参数列出外部的控制文件.
这些控制文件是相同的,所有控制文件在启动时必须是可用的.
如果一个控制文件由于磁盘驱动器的损坏丢失了,可以从这个控制文件表中清除它,用保留的控制文件启动数据库.
(4)compatible设置Oracle数据目录的内部配置,以服从OracleDBMS软件的某一版本.
举例来说,304Oracle8i数据库开发与专业应用当运行Oracle8软件时,可以设置与版本7.
2相兼容(如果已经安装了7.
2软件,这种兼容性并不保证功能完全一样,但也可能会完全一样).
这能够让软件旧版本上所写的数据库应用程序在新版本下运行,而无需做内部的修改.
(5)db_file_multiblock_read_count确定每次所写的数据块的数量.
(6)db_block_buffers确定在SGA中所分配的数据块缓冲区的块数.
(7)shared_pool_size确定分配给共享池的共享内存的总数.
(8)log_checkpoint_interval确定两个日志检查点之间以秒为单位的时间片段.
(9)processes确定与Oracle实例相关的进程最大数.
(10)log_buffer确定在SGA中分配给重做日志缓冲区的块数.
(11)audit_trail此参数为TRUE或者为FALSE,取决于是否能审计.
(12)max_dump_file_size在Oracle中检测到问题时,它限制转储文件的大小.
防止溢出为转储分配的磁盘空间.
(13)log_archive_start确定归档日志进程是否启动.
(14)background_dump_dest为与Oracle数据库进程密切相关的报警日志(alterlog)和转储文件规定文件位置.
(15)user_dump_dest确定了与终端用户进程相关联的停机文件的位置.
(16)db_block_size确定Oracle数据库磁盘上和内存中块的大小.
(17)rollback_segments规定在数据库启动时哪个回滚段联机.
7.
3.
6日志和跟踪文件当问题产生时,可以调用Oracle来帮助解决难题.
因此,Oracle的实用程序花了几个CPU周期写下了重要事件的记录,由此产生了一组日志文件.
在RDBMS中记录主要事件的日志文件是报警日志文件.
通常这个文件的确切名称和位置比alter_log复杂不了多少.
实际的文件名包含与该事件相连的实例名称.
例如对于实例blue而言,报警日志文件称为alert_blue.
log.
接下来的逻辑问题是报警日志中都有什么:(1)主要的DBA活动,像启动或停止实例或发布命令:创建、修改或删除数据库、表空间或回滚段.
(2)内部Oracle错误.
(3)与多线程服务器问题有关的消息.
第7章Oracle8组件和对象305(4)与快照自动刷新有关的错误.
跟踪文件是由Oracle的后台进程产生的.
当后台进程感到它们出现了主要问题或者这些进程之一检测到其他后台进程出错或丢失时,就产生跟踪文件.
消息的内容取决于进程写了多少消息能够感觉到的信息.
通常它包括问题的日期和时间、产生问题的后台进程、可用来与Oracle讨论问题的错误消息号码以及一些解释性文件.
如果Oracle出现了问题,那么要保存这些消息,直到明确了该问题的确切原因并解决了该问题.
一些Oracle版本在每次启动时都写跟踪文件,它这样并不是指出错误,而仅仅是记录一次成功的启动.
Oracle的一个公共特性是SQL*Net或Net8进程,它们在报警日志文件中不存储日志信息.
相反,会发现在供SQL*Net使用的目录下,日志文件与系统中正在使用的协议相关(例如TCP/IP).
报警日志与一个实例相关是有一些道理的,但是一个SQL*Net进程可以为多个实例服务.
上面讲述了日志和跟踪文件中的可用的丰富信息,下面讲一下在哪里找到它们.
这些日志文件所处的位置是由初始化文件中的参数规定的(确切地说,是在上述实例的config.
ora中的参数规定的).
这个参数被称为BACKGROUND_DUMP_DEST(它是Oracle后台进程转储文件的目标,其典型值为ORACLE_BASE/admin/instance_name/bdump).
最后讨论清除.
当更多的事件被记录时,日志文件不断地增长.
在处理它们之前,跟踪文件始终存在,吃掉越来越多的磁盘空间.
因此,执行一个内务处理过程,经常地清除日志、内核和跟踪文件是很必要的.
一个很好的做法是设置一个脚本,自动地拷贝报警和SQL*Net日志文件到文件名有日期的文件中(例如alert_blue.
log.
013095).
之后,在指定的目录下清除超过30天的所有跟踪文件和日志文件.
保持系统干净,并且当碰到问题时,永远不必查看整个1MB的日志文件以寻找数据.
7.
3.
7文件大小的自动调整Oracle8的一个特性已随Oracle7.
3一起采用,这就是数据文件自动调整大小选项.
过去的数据库管理者最大的问题之一是在表运行时超出了空间.
必须经常地保持警惕,以保证有足够的空间和足够大量的连续空间块适应表和索引的增长.
问题是特定表或索引什么时候将需要另一个范围不会提前发出警告.
在应用中,这是一个严重的问题.
当空间耗尽时,应用将崩溃,输入的数据也可能丢失.
解决这一问题的方法是在SQL语句上定义为给定的数据文件增加更多的空间,这个空间将由一个磁盘驱动器提供.
当然,仍要控制此调整大小,SQL语句也必须把它考虑进去.
下面是一个如何指定autoexend选项的例子(它不是缺省的).
alterdatabasedatafile'/u03/oradata/devel01.
ora'autoexendonnext50mmaxsize500M;7.
3.
8数据分布优化如果只考虑一个20MB的数据库,当做文件布局时,几乎可以不用考虑别的事情.
不过,如果要存储和读出上千兆字节的信息量,也许就要花一些时间考虑分散数据并用智能306Oracle8i数据库开发与专业应用化软件在磁盘之间改善性能.
7.
3.
9标准文件位置在详细讨论与Oracle系统相关的不同类型文件的细节之前,先提供一个这些文件系统在磁盘驱动器中排列的大概情况.
如果有Oracle6,那么准确地语言文件存储是很困难的.
大多数安装没有声音引导,采用的是DBA当时喜欢的方式.
从Oracle7开始,Oracle发布了一个指南,指导怎样布局可引用的文件,它称为最佳灵活体系结构(OptimalFlexibleArchitecture,OFA).
最佳灵活体系结构由Oracle的咨询人员设计,它为顾客完成安装工作.
Oracle非常喜欢它,并作为推荐产品在《安装与配置指南》中提供.
这个体系结构在大多数计算机系统中也是缺省的Oracle安装脚本.
图7-11说明了UNIX中的Oracle7配置.
该图也说明了OFA的一般概念.
目录的名字在其他操作系统中可以变更.
图7-11UNIX的最佳灵活体系系统(OFA)这个体系结构的开始点称为"OracleBase".
在OracleBase下有三个关键目录:admin存储日志文件和DBA的其他信息;data用于存储数据;product存储Oracle的应用软件和主实例的配置文件.
其他两个目录不经常使用:TAR用于固定磁带下载;local用于存储创建的项目和Oracle软件可能要存储的一些东西.
这个体系结构在典型的Oracle数据库中为每件事分配了一个位置.
正如大多数标准一样,一旦知道文件放在什么地方,就能在任何其他的Oracle数据库中发现这些同样的文件.
大量的目录可以使每个低级目录有一个明确的地点,并限制了该目录下全部排列的文件数.
有一个单独的目录包含有代表性的需要的全部可执行文件.
这使设置路径很容易,以至能访问Oracle应用.
最后,这种体系结构对协调系统中同时拥有的多个RDBMS软件版本也是容易的.
在改变实例时这特别有用.
当维护已存在产品的版本时,能够提出有测试数据库的RDBMS新版本,看看它工作得怎么样.
在几乎所有的基于PC的安装中,创建分跨在多个磁盘驱动器上的大量目录并不值得第7章Oracle8组件和对象307尝试.
许多PC都是单个磁盘,并且大多数DOS/Windows用户习惯于让软件产品安装在单独的目录层次上,其层次定位在根目录下.
在不同的平台之间进行数据交流时,对产品必须做的部分平衡作用是维护同样的命令结构和接口,以适用于主机环境下的客户.
Oracle实现的目录结构如图7-12所示.
图7-12MicrosoftWindows95下的PersonalOracle目录7.
4Oracle数据对象术语"对象"在Oracle数据库中用于描述存在于数据库文件里的那些实体,这些实体是用户交互使用的逻辑实体.
对开发者来说,理解这些数据库对象是指需要掌握Oracle数据库的一切.
数据库对象包括:表(Table)、索引(Index)、视图(View)、同义词(Synonym)、序列(Sequence)、分区(Paitition)、聚簇(Cluster)、存储过程和包(StoredProcedureandpackages)、用户自定义的数据类型(Oracle8新增加的)、表空间(Tablespace)、完整性约束(constraint).
7.
4.
1Oracle8数据库对象本小节讲述这些对象如何组合在一起形成数据库的.
基本的Oracle8数据库对象的用途如下.
(1)表表是Oracle数据库里数据存储的基本单位.
它们是进行数据库查询和修改数据的典型实体.
虽然可以设想没有任何用户数据表的数据库,但这样的数据库在很大程度上是不可能存在的.
(2)索引一些数据库表能够变得很大.
要得到某一行数据时,虽然每次扫描整个大表是可以的,但这不是一个非常有效的方法.
因此,如果有一个用于选择一行记录的公共选择要求(举例来说,在人员表中的雇员号ID),就可以建立一个索引以跟踪某些行,这些行在表中与这个选择标准的给定相联系.
这使Oracle能够在扫描较小的索引后从大表中检索单行数据,从而节省了处理时间.
(3)视图有时,可能想让某个用户仅存取表中的部分数据.
有时,又可能需要把几个表合在一起产生用户想要存取的数据,这些要求可使用视图来实现.
可以认为视图是选择表中部分数据的SQL选择语句或者是将多个表连接在一起的SQL选择语句,但是它可被存取,仿佛是个简单表.
(4)同义词308Oracle8i数据库开发与专业应用有些实例中,可能需要对数据库表或视图使用一个其他的名字.
或许为所命名的表使用非常正式的模式对开发者是讲得通的,但是,对终端用户来说却有一些麻烦.
或许有许多不同的表或视图的拥有者,并且不想让用户键入全限定表名(例如owner.
table_name).
在这种情况下,就可以使用同义词来给表或视图命名另一个名字,使键入SQL语句更容易一些.
(5)序列在数据库程序设计中,要能保证表中的行有一个唯一的属性值.
Oracle8支持序列(唯一的序列号),它在表中可使用,它经常用于产生主键.
(6)表空间当数据库变得更大时,从性能方面来说,成组的表和索引一起在不同的磁盘上分布数据是有好处的.
实现这一任务的机制是表空间.
表和索引在给定的表空间中创建.
表空间使数据文件(位于一个或多个磁盘上)相互联系,能够控制信息放在哪个磁盘上.
(7)分区Oracle8的一个新特性是分区.
假定这种情况,要在一个包含10年数据的表中扫描一月份的事务,那么将浪费大量时间扫描不符合要求的记录.
Oracle8能够把表里的数据分成组放入分区中,然后,分区放在显式磁盘上.
Oracle的查询引擎很灵活,足以忽略不符合选择要求的分区,从而节省了时间.
其可靠性特色是,如果由于磁盘故障所分配的分区不可使用,仍可以在与此相连的其他分区上存取数据.
(8)聚簇聚簇是Oracle中一个较老的组成部分,主要用在Oracle自己的数据字典上.
它可以把不同的对象中的数据分组存放在一起,从而提高了存取效率.
举例来说,如果有一个经常引导主数据表的对照表,那么就能把它们聚簇在一起快速存取.
不过,随着Oracle存储算法的改进,不得不使用聚簇的机会已经很少了.
(9)存储过程和包Oracle8数据库能在数据库中存储和执行软件.
这种软件处理机制可以自动地执行确定的算法(不论何时修改表),或者在需要的时候(用户或程序调用某个过程)执行.
(10)用户自定义的数据类型现实世界对象有多方面的信息能被应用.
举例来说,雇员有雇员编号(ID)、一串地址甚至一张照片等,Oracle8可以把这些不一样的或者重复的数据类型逻辑上合成一组,以便存取它们.
(11)完整性约束一个产品化的数据库主要关心的不是存储数据,也不是存储商品,而是有效数据.
当许多程序员在一个应用中一起工作,或者特定的用户存取数据库时,这是一个相当大的挑战.
Oracle提供了完整性约束,以帮助控制在给定的表中对给定的列能够进行什么操作,从而增强了信息的准确性.
7.
4.
2表Oracle数据库里信息存储的基本单位是表.
表由数据行组成,而数据表示给定实体的实例(例如雇员的地址).
表也有列,列表示与行相联系的属性(例如,给定地址中的城市和国家).
Oracle已经扩展了其列的能力,从简单的数值和字符数据存储发展到像视频、音第7章Oracle8组件和对象309频或图像数据之类更复杂的数据类型.
当向列表中插入一行时,Oracle已在为此表分配的区间里找到正确的位置,并以能够检索的方式存储数据.
Oracle记录位和字节的精确位置,可以使用的内部存储特性仅是行号.
这个唯一的号码规定了在给定的表中一个给定的行.
这样,如果表中有多个行,并有完全相同的值,要想去掉它们中的一个,可使用行号来完成.
下面的例子用来创建名为golf_scores的表:createtablegolf_scores(coursechar(20));data_playeddate;partnerchar(20);front_nicenumber(3);back_nicenumber(3);totalnumber(3);initrans1maxtrans100tablespaceuser_datastorage(inital10Knext10Kpctincrease0minextents1maxextents100);分析这个命令最直接的方法是把该命令分成几个部分:(1)Oracletablegolf_scores告诉Oracle要做的工作(创建表).
每个表需要一个名字,它是任何字符和下划线(不允许空格)的有效组合,总共为30个字符或者更少.
与旧式的主机代码和数字系统相比,现在的表名可以表示出表的含义.
Oracle有一些保留(像order),不能使用它们作为表名,但可以是较长名字的一部分.
(2)接下来的6行列出了该表的列名.
与每列连在一起的是数据类型和大小.
(3)intrans和mastrans与initial和next区间参数相似,除了它们给表中正在进行处理的记录事务分配空间之外.
这个空间分配在表头,每23个字节为一块.
当事务完成后,该空间不收回.
它们的最大值不超过255,在有些操作系统中可以更少.
如果用完了表的事务空间,那么新的事务不得不等待,直到存在的事务做完,事务空间被释放.
如果没有规定这些参数值,那么实例中就使用缺省值.
(4)tablespaceuser_data在本例中,这个命令告诉Oracle把表放在名为user_data的表空间中,如果没有定义此参数,用户ID将使用缺省表空间.
(5)storage()的括号里包括5个参数,它们是此表的存储函数.
如果没有定义任何值,它使用表空间中这些参数的缺省值.
310Oracle8i数据库开发与专业应用(6)initial和next是表空间里描述的初始区间和以后增加的区间参数.
(7)pctincrease是应用于每个后续区间大小的增加百分比,例如,初始区间大小是1KB,每2个区间是2KB,则pcincrease是50%.
第3个区间将是3KB(2KB的1.
5倍),第4个区间将是4.
5KB,依次类推.
(8)minextents和maxextents是该表中拥有的最小区间和最大区间数.
表中的每列都有列名、数据类型和大小参数.
列名的命名规则和表空间规则一样.
使用有意义的列名是很好的想法.
字符数据的大小定义字符串的最大长度.
数值类型有精度和刻度.
精度与数字的总位数有关,但当数值按指数方式表示时,总位数不包括指数.
刻度定义小数点右边数字的位数.
一个精度为5、刻度为2的数值,其取值范围在-999.
99~+999.
99之间,可认为其数据类型是number(5,2).
Oracle支持的数据类型见表7-1.
表7-1Oracle支持的数据类型数据类型意义固定/可变长度char(size)字符固定长度(加尾部空格)varchar2(size)字符变长(使用所需大小)number(prec,scale)数值变长(使用所需大小)date日期和时间每列7个字节long字符Oracle6中每行变长到64KB字节Oracle7中每行变长到2GB字节raw(size)自由形式每行变长到2000字节longraw自由形式Oracle6中每行可变长到64KB字节Oracle7中每行可变长到2GB字节rowid二进制每行6字节,可在查询中用数字表示在大多数情况下,使用结构化查询语言(SQL)存取表.
与平面文件系统或简单的数据管理工具不同,不必直接存取原始数据存储格式.
要让Oracle的表正确工作,需要学习SQL的许多学问.
当发出一条选择命令从表中检索一行数据时,实际上是从数据文件取回一个块或多个块,认识这一点很重要.
在许多情况下,可能需要一个表的多行数据,它们之间的位置相当近(因为它们在差不多的时间存储).
通过把一块数据检索到内存,Oracle避免了每行分别地存取磁盘.
Oracle使DBA能够通过授权机制控制谁能创建或修改这些对象.
现在要理解表的创建和修改的两个基本权限:CREATETABLE和ALTERTABLE.
7.
4.
3索引where子句是数据库程序设计中通用的构造.
很少有用户希望在每次查询中显示表中的所有数据.
相反,大多数查询设计用于返回与用户要求相匹配的一系列行,甚至是单条记录行.
如果没有索引,Oracle将不得不读出表中的所有行,之后过滤掉不符合要求的行.
然而,在有索引时,可以扫描较小的索引,看看哪些行满足要求,之后,仅从表中检索出这些行.
对一个较小的表来说,读出全部的记录行,逐个检查它们看看是否与用户输入的选择要求相匹配,这个工作量也不大.
但是,对大型表来说,这是非常慢的,并且要在系统中为每个查询做大量的加载工作.
为了帮助解决这种问题,就引进了索引.
索引是表中一个或多个列的数据排序表,是公共使用的选择要求.
这样,可以不必搜第7章Oracle8组件和对象311索整个大的、长长的人事记录来查找某个人的记录,而只需对只包含姓名的相对较短的索引排序,如图7-13所示.
当Oracle查找到与检索值相匹配的姓名时,就检索恰好包含所需要数据的记录块.
因为数据已经排序,Oracle不用读出索引中的每条记录.
相反,它使用更有效的检索例程(例如B树)以减少所需分析的索引记录数.
图7-13索引检索因为索引是表中数据的摘录列表,Oracle需要空间来存储它们.
因此,索引有与表相像的存储子句.
这里有一个命令例子,它在前面所说的表golf_scores的域data_played上创建索引:createindexgolf_scores_dataesongolf_scores(date_played)tablespaceuser_datastorage(initial2Knext2Kminextents1maxextents100pctincrease0);当查询能使用索引时,Oracle会自动地使用它(所谓能使用是指where子句中的值在索引的域中),这使开发者的工作变得容易了.
更大的好处是,Oracle能自动地维护索引.
当在有一个或多个索引的表中增加、删除、修改记录行时,索引根据这些变化自动地进行更新.
这就提出了一个重要的设计要求,更新索引要花去的Oracle的时间.
如果有一个表,它有大量的索引,那么在这个表中增加数据将花去更长的时间.
因此,较少的索引可以使向表中增加数据的能力得到提高(例如,系统中订购输入表一天中有大量的数据要加载).
与之相反,主要使用查询的系统(像决策支持系统)得益于基于用户查询的大量索引.
要说明表中什么索引是有用的往往是困难的.
很明显,为表中的每一列建索引也许并不好.
尽管索引检索比表扫描更有效率,但它也要花一些时间.
如果把检索表中所需行的时间与检索大型索引的时间加在一起,有可能比扫描表的时间还长.
建立和维护那些不经常使用查询的选择要求的索引也是不合理的.
在这种情况下,与这些不经常使用的查询所节省的时间相比,花费在更新上的时间更长.
312Oracle8i数据库开发与专业应用下面是一些关于索引需要进一步注意的事项.
(1)表不受索引的影响.
可以删除或重建索引,而不会影响表中的数据.
(2)在系统中执行大批量更新时,先删除索引,再执行修改,然后重建索引有时会更有好处.
(3)性能优化的规则之一是将某表的索引放到该表分布的不同磁盘上.
这样可以分散访问表和索引查询时所进行的输入/输出加载.
(4)创建唯一索引选项.
如果创建唯一索引选项,当试图插入一行到列表中,并索引列上的值与表中另一行的列值一致,就会给出一个错误.
这是强制表中的主键和以单步方式建立索引的好方法.
(5)如果具有创建或修改的权限,就拥有需要创建或修改与此表相连的索引的权限.
索引是改善查询性能的非常有用的工具.
然而像所有的工具一样,需要谨慎地考虑它们的设计,以确保能获得所希望的性能.
下面显示了与所给表名相关的索引中的列:SQL>selectindex_owner,index_name,column_name2fromdba_ind_columns3wheretable_name='WORLD_CITIES';INDEX_OWNERINDEX_NAMECOLUMN_NAMEJGREENESYS_C004352LOCATION_ID7.
4.
4视图前面章节的例子中已经看到了许多视图,这些例子是用来查询数据库中表、表空间和索引的列表.
实际的检索数据存储在一个或多个内部控制的Oracle表中,而且必须做一些搜索来找到它们.
如果有这些视图,只需要发出一条简单的查询就可获得想要的结果.
视图是从一个或多个表中选择的一行或多行.
数据并不要复制,视图仅仅是引用数据的一种结构,而数据实际上存储在表中,可以认为它是一个SQL查询(具有连接和筛选逻辑),能从中选择数据,仿佛它是一个表.
因此,它们不需要存储参数,也不驻留在表空间里,对设计者来说,视图可用于实现许多对象:(1)用户不想写把一个或多个表连接在一起的复杂的查询.
因此,建立一个逻辑,将这两个表连接成一个视图,让用户存取数据时仿佛是对表操作.
(2)也许有这样一些表,其中只允许某些用户存取表中某些列的数据.
对于这种情况可以创建包含允许用户访问列的视图,让用户访问该视图而不是基表.
(3)如果拥有表的列名对某些用户无意义,那么可以创建一个视图,重新命名这些列,使列名对用户有意义.
(4)可以处理比表更简单的结构.
举例来说,如果表上有上百列数据,那么可以创建一个更容易的视图,使用户只关心这个更容易的视图.
视图的最好特性之一是存取它们和存取表一样.
不必学习任何不同的语言,但不能在视图上创建索引.
为了创建索引,需要给Oracle用户ID分配CREATEVIEW权限.
不能改变视图,其替代方法是删除它们再重新创建.
通过使用CREATEVIEW命令的CREATEORREPLACEVIEW格式,可以仅用一条命令来做这项工作.
CREATEORREPLACEVIEW第7章Oracle8组件和对象313格式的优点是不会丢失已经授予该视图的各种权限.
这不是一个问题,因为删除或创建视图不影响与此视图相关的表中数据.
视图是方便的数据库对象,它自身并不存在任何数据.
视图引用的数据放置在实例的一个或多个表中.
它们有许多作用,包括使用户的查询方便,以及为数据库提供辅助的安全保密性.
7.
4.
5同义词同义词(synonyms)仅仅是一种分配用户能够引用的表或视图的别名的方法,这使得存取其他用户拥有的表更容易一些.
当拥有某表时,可以在SQL查询中使用它的名字.
但在想存取其他用户拥有的表时,就需要给出表的拥有者和表名(以owner,table_name格式).
当使用SQL*Net引用放置在不同的数据库中的表时,其格式可能是相当复杂的.
同义词简化了这种存取,因为能创建一个简单的同义词,使该同义词包含复杂引用串的细节,如图7-14所示.
图7-14同义词有两类同义词——专用的和公共的.
专用同义词(privatesynonyms)是为个人使用而创建的同义词.
公共同义词(publicsynonyms)是在数据库中任何用户都能使用的同义词.
很显然,从DBA的观点来说,常常要限制能够创建公共同义词的用户数.
但常常更要限制能删除公共同义词的用户数.
有3个主要的系统特权设置由DBA参与,并与同义词相关:CREATESYNONYM;CREATEPUBLICSYNONYM;DROPPUBLICSYNONYM.
最后,考虑一下当提交一个具有如下特征的对象名的查询时,会出现什么结果:有一个具有该名字的表;有一个此名的私有同义词;也有一个此名的公共同义词.
必须立即检查它以断定Oracle将做什么,获得此实验结果是很重要的.
下面是Oracle存取数据库中有相同名字的对象的顺序:(1)如果拥有某一特定名字的表,那么总是访问此表来查询对象名.
(2)如果未拥有此名字的表,但是有用此名命名的专用同义词,那么访问与该专用同义词相关的对象.
(3)最后,如果搜索的对象名中既没有表也没有专用同义词,那么存取由公共同义词规定的对象.
314Oracle8i数据库开发与专业应用7.
4.
6存储过程和包在Oracle数据库中存储过程是存储软件的一种方法.
基本上来说,用PL/SQL脚本开发的任何程序都能够作为Oracle存储过程来保存.
一批存储过程可以作为一个包存储在数据库中.
对Oracle开发者来说,存储过程展现了几个令人感兴趣的优点:(1)Oracle安全机制,像角色和授权,可用于保护数据和软件.
这也为安全管理提供了一种控制方法.
(2)当执行一个存储过程时,可以像它的创建者一样执行,而正常情况下没有此特权.
这适合于某些特定环境,它需要在软件中完成安全性特性,例如审计跟踪和专门的合法性检查.
DBA能够把写访问权限仅授予给创建存储过程的用户.
被授予写操作的用户在Oracle账户中未给出写权限,而是通过访问必须执行的存储过程来实现写操作.
此后,软件安全性强制执行写操作.
如果他们试图从SQL*Plus发布SQL命令来写这些表,那么将被拒绝.
(3)存储过程的一个好处是Oracle存储了软件的源代码和分析版本(parsedversion),这样就节省了每次Oracle对外部软件应用中接收的SQL查询进行语句分析的时间.
存储过程有两个问题.
第一,所有的存储过程都存储在系统表空间中,而通常认为这是仅由DBA使用的地方.
然而Oracle开发者不同意存放在系统表空间中,因此,不得不让非DBA软件存放在许多专用表空间里.
另一个问题是,软件必须用PL/SQL书写.
PL/SQL可以把工作做完,然而,它是难于调试的,也不支持正常输入/输出操作.
存储过程在创建时要求有特别的系统权限.
由于没有研究软件开发者关心的细节,需要授权CREATEPACKAGE,CREATEPROCEDURE,DROPPACKAGE以及DROPPROCEDURE权限给用户,他们将在系统中开发存储过程.
7.
4.
7聚簇聚簇是在一起存储的一组表,因为它们包含了许多公共列,并且在查询中经常连在一起.
它们在Oracle6中是常见的,但是Oracle8的基本数据存储算法比Oracle6要巧妙得多,它以一种有效的方式排列表而没有创建聚簇.
关于聚簇的一个神奇特性是,用户搞不清楚他们正在存取的表是否在聚簇中,只有开发者和DBA知道哪个表在聚簇中.
基本的Oracle参考手册提供了安装聚簇的详细描述.
它们也研究了使用聚簇时的更多细节.
如果在查询时,总有常用的列集合在一些表中,而性能方面又有问题,那么可以考虑用聚簇试验一下.
否则,也许永远不会注意聚簇,尽管Oracle的许多内部表被认为使用了聚簇,但是,也许永远不会直接处理这些表,因为,RDBMS软件已经做好了这一切.
7.
4.
8序列序列是一种工具,它用于在所使用的数据表中生成唯一的顺序号.
它是一种优秀的方法,用于在应用中生成确立唯一的号码来作为内部键连接两个表.
序列的最好特性之一是,当存取序列时,保证将得到唯一值,举例来说,如果创建一个拥有的序列表,并写一个读取下一个有效值的应用,让它按1增加,然后,用这个新值修改序列表,那么在修改语句发出之前,有时其他人可能会存取你所做的通用的记录(如果你用锁做过工作,就能避免这种情况,但是有了序列也可以避免这个烦恼).
如果这是表的主键,将有一个不可靠的主键.
最后要注意的一点是:不能回滚序列值的增加.
如果决定不将序列值插入到记录行列第7章Oracle8组件和对象315表中,就不用恢复序列值.
有三个参数与序列有关:初始值、最大值和增量(通常是1).
下面显示了用于创建序列的语句:SQL>createsequencelocation_id2incrementby13startwith14maxvalue9999999995Cycle;Sequencecreated.
序列是易于访问的.
举例来说,如果创建了一个名为staff_id的序列,来跟踪输入到人事数据库中每个雇员的唯一内部键,那么就能用下列简单的SQL语句,输入一个新记录数据,生成一个唯一键:insertintopersonnelvalues(staff_id.
nextval,'Jones','Sandra','123-4567');有关序列的维护问题与未达到其最大值的序列有关,或者与在某些数据加载到相关的数据表中未修改的序列有关.
在缺省情况下,索引是用循环选项创建的,这意味着,它们将是可再循环的.
如果序列所提供的列用作唯一限制或者索引,这可能引起问题.
因此,必须确保序列和列足够大,以容纳序列的大型唯一数值组.
有关序列的另一个常见问题是有人自己编写软件以实现自己的ID号,而不使用序列.
当用户试图使用序列时,将给出一个值,该值已经插入到相关的数据表中,因此,如果使用未用序列的程序,将不得不在程序运行后修改序列,以确保序列是最新的.
作为序列上要讨论的最后一点,创建或使用序列需要有一系列Oracle系统权限.
这些权限是CREATESEQUENCE和DROPSEQUENCE.
7.
4.
9表空间数据库里的基本存储单位是表空间.
表空间包含多种不同类型的对象用来存储用户数据.
它们也包含一系列Oracle用于存储与操作数据库有关信息的表、视图等.
表空间是存储的基本单位的第二个理由是:它连接到物理存储世界.
一个表空间与一个或多个数据文件相关,不能控制Oracle用哪一个数据文件存储正在增加的表中的行.
而且,也不能控制表空间,它最低限度地限制将访问的数据文件列表.
这种控制缺乏可能会带来很多不方便.
在两种情况下采用表空间是值得的.
第一种,管理数据库已经很繁忙了,所以不愿意去再控制物理存储.
第二种,通过创建仅有一个数据文件的表空间,就能控制哪个磁盘接收数据.
为了找到想要知道的表空间,通常发出一条结构化查询语言(SQL).
有人更愿意使用Oracle的SQL*Plus产品,有人则更愿意选择SQL*DBA或OracleServerManager.
另一种方法是访问为数据库管理员创建的视图,搜索内部的Oracle表以发现所需要的信息.
Oracle提供一个基于GUI的工具(EnterpriseManager)执行这些查询,然后以图表和数字方316Oracle8i数据库开发与专业应用式显示这个结果.
对那些没有访问EnterpriseManager的人员来说,总能够通过执行查询获得数据.
如果查询Oracle8里的all_tablespaces视图,要注意的第一件重要事情是涉及extents或者pct_increase的一串列,在数据库中占用空间的每个对象(例如表和索引)使用预分配的空间块,此空间块被称为区间(extents).
Oracle一直设计成让数据行按照它们的接受顺序写入到一个大的表空间中.
然而,由于系统很大,将不得不扫描大量的磁盘空间,以发现与特定表相关的全部行.
Oracle把表中的行分成组存储到称为区间的磁盘区中.
这是有好处的,因为Oracle把额外行一起读入到SGA缓冲区高速缓存中(它是有意义的,因为大多数操作系统一次从磁盘上读出整个块的数据).
开发者在工程开始时,必须精确地确定每个表的大小,并且也必须在创建表时预分配大量的空间,因为此表在今后会慢慢地增大.
Oracle采取的折中办法是使区间等于操作系统的块的大小的数倍,并且使每个表能够占用合理的范围数.
给定对象能够占用的区间最大值随操作系统的不同而改变,但是通常都超过100个区间.
现在,已经有了存储的概念,就更易于理解all_tablespaces中的缺省存储参数.
这些仅仅是缺省的,能够根据所创建的数据库对象改变它们.
在创建表空间时,如果没有定义缺省存储参数,系统将使用与数据库相关的缺省值.
如果没有为数据库定义缺省参数,就将继承由Oracle提供的更适合于操作系统的一套缺省参数.
下列是表空间中的基本存储参数:(1)initial_extent能定义第一区间的大小.
当创建一个数据库对象时,必须至少分配一个区间.
注意,不能创建一个比在单个数据文件中所能获得的最大连续区间更大的区间.
可能还有大量的空间可用,但是,如果它分散在不同的磁盘文件之间,并且,为其他区间所隔断,也只能为新对象分配较小的区间.
(2)next_extent定义分配的第二个区间大小.
所有其后的区间按照该值调整大小.
此区间随着后面要讨论的增量的百分比因子连续增大.
(3)min_extents是指定的区间最小值.
当创建一个对象时,不必创建一个恰好大小的区间.
有一种情况需要分配多于一个的区间,即有一个非常大的表,并且知道此表将不得不分配在多个磁盘的多个数据文件上(例如有3个2GB的磁盘,而表需要3个1.
5GB的区间).
在分配数据库中任何其他区间或加载任何数据之前,可以分配此大型区间.
(4)max_extents是该对象所能占用的最大值,正如在前面的讨论中所阐述的那样,如果有大量的区间,可能要花一些时间在磁盘上定位查询所需要的全部区间并送回数据.
一般而言,一个对象的区间越少,其响应时间越短.
(5)pct_increase是一个总是设其为零的参数,但有一些人使用它,它表示应用于连续区间分配的增加百分比.
举例来说,如果某表next_extent的大小是1000字节,pct_increase为10.
那么第二个空间将是1000字节,第三个将是1100字节,第四个区间将是1210字节,依此类推.
all_tablespaces的另一个特点是状态列.
不必让所有表空间同时联机.
如果不想让一个拥有自己表空间的给定应用数据被改变,那么可以让整个表空间脱机.
当脱机时,用户被第7章Oracle8组件和对象317告知,他们不能存取该表空间的任何对象.
7.
4.
10分区分区(Partitions)设计为允许获得大表和索引,并基于与表相关的一个属性(例如日期),把它分解到多个段中.
分区存储在单独的表空间里,而在Oracle的早期版本中,能够把不同的表或索引存储在单独表空间的不同表和索引中.
Oracle8扩展了这一概念,能够把给定的表分到多个表空间.
这提供如下的好处:(1)增加性能就像为了搜索一个给定表时,调整磁盘间的加载.
甚至能够用并行方式搜索不同的分区.
(2)能为不同的分区改变存储参数,举例来说,那些不可能被改变的老数据,能够使用最小的pctfree和最大的pctused参数.
(3)如果由于磁盘故障丢失了表空间,仍然能够存取与故障磁盘无关的其他分区中的数据.
(4)能够单独地备份/恢复分区.
这里,能不备份旧的、静态的数据,只备份那些经常改变的数据.
下面的例子说明了怎样创建一个分区表:createtableaddresses(employee_idnumber(10),Streetvarchar2(25),Cityvarchar2(25),Statevarchar2(2),Zip_codevarchar2(5),Effective_datedate)Parititionbyrange(zip_code)(partitionvalueslessthan(30000)tablespaceadd1,partitionvalueslessthan(60000)tablespaceadd2,partitionvalueslessthan(99999)tablespaceadd3);如果不处理大表或索引,也许会因为可靠性的原因而考虑分区.
如果有一个在性能方面受到限制的中等大小的表,并且这种性能方面的限制是由于存取它时会耗尽时间(并且它也太大以至不能放到内存的高速缓存中),那么也可以考虑使用分区.
否则,可以不使用分区表.
7.
4.
11对象数据类型在此就Oracle8的新特性做一个初步介绍,以便得到可使用的数据存储工具的完整画面.
Oracle8可以使用对象中的嵌套表选项来处理与一个对象的单独实例有关的给定属性的多值情况.
为创建一个用户定义的对象数据类型,可采用一条如下的命令:createtypeaddressasobject(streetvarchar2(25),cityvarchar2(25),statevarchar2(2));要使用这个对象(这里创建一个包含该数据类型的表),可以发出与下列代码相似的命令:318Oracle8i数据库开发与专业应用createtablepeople(employee_idnumber(10),locationaddress);为了存取对象里的值(这里,为people表分配了一个别名employee),可以给出一条这样的命令:selectemployee.
location.
streetfrompeopleemployee;如果觉得这种表示法比较混乱,那么可能对面向对象的设计复杂性和程序设计工具还不习惯.
记住,Oracle8是一个全功能的关系数据库管理系统.
7.
4.
12约束约束帮助数据库设计者确保只有"好的"数据才由开发者或终端用户放入到不同的表中.
下面是贯穿Oracle8的约束类型:(1)null表示受此约束的列的有效值为空(没有数据能插入到这一列).
(2)notnull表示该列必须有一个规定的值.
(3)default为给定的列定义一个缺省值.
如果insert语句没有为此列定义值,缺省值由Oracle自动插入.
(4)unique规定此列的任何两行都没有相同的值(除非该列为空值,在这种情况下,可以有重复的值(空)).
(5)PRIMARYKEY规定将由此列或几列创建一个唯一的非空索引.
索引中的每一行都有一个不同的值,该值能用于决定引用这一行.
(6)FOREIGNKEY规定此列(或几列)的值必须是空值,或者与定义为外键部分的表中相应的列(或几列)匹配.
这是列出存储在数据库的某表中有效值的好方法,因此,当业务需要改变时,这是一个更新起来的相当容易的方法.
(7)值表规定列包含这样的值,该值位于创建表时所指定的一个固定列表中.
由于它们非常自然,所以对于仅有值集的限制(例如,是/否,真/假)的情况是可以接受的.
能够检查该值是否满足与表中一列或多列相关的特定逻辑判断.
如果需要改变列的可用值列表,那么建议还是使用外键和有效值表.
约束可用于两个地方:第一是在单独的列上,此时约束只应用于列;第二是在表级上,能使用一列或多列.
下面的例子显示了约束在列和表级上的应用:SQL>createtablelocations2(location_idnumber(5),3location_namevarchar2(30)constraintc_location_namenuique,4location_statevarchar2(2),第7章Oracle8组件和对象3195active_flagvarchar2(1)check(active_flagin('Y','N')));Tablecreated.
SQL>createtablelocations22(location_idnumber(5),3location_namevarchar2(30),4location_statevarchar2(2),5active_flagvarchar2(1),6constraintc_loaction_name2unique(location_name),7check(active_flagin('Y','N')));Tablecreated.
7.
5小结1.
问:Oracle的主要组件有哪些答:Oracle体系三个主要组件就是进程、内存区和文件.
2.
问:什么是Oracle进程答:用术语"进程"来描述任一操作系统的程序(线程、作业等依赖于操作系统的术语),在Oracle数据库管理系统中,它执行完整的功能.
Oracle进程分成两类:主进程和选项进程.
主进程是那些与Oracle数据库的最小功能相关的进程;选项进程是那些要改善性能,或者能从几个可选择进程中进行选择的那些进程(例如,专用服务器进程或多线程服务器进程).
3.
问:Oracle有哪几个主进程答:有四个主进程:(1)系统监视进程(SMON);(2)进程监视进程(PMON);(3)数据库写入进程(DBWR);(4)日志写入进程(LGWR).
4.
问:系统监视进程在哪些情况下被激活答:在三种情况下被激活:第一种情况,在启动时,它检查实例,看看是否需要恢复.
第二种情况,系统监视进程也被设计成周期性唤醒,以发现Oracle实例是否需要做一些清理.
第三种情况,当SMON被其他进程调用时,系统监视进程被激活.
5.
问:进程监视进程有什么作用,它在什么情况下被唤醒答:进程监视进程(PMON)专门用于在进程结束后进行清理工作.
它有规律地被唤醒(由操作系统决定),也可由其他进程调用(当其他进程需要此服务时).
(1)删除进程号;(2)删除活动事务表中相应的行;(3)释放进程已有的任何锁;320Oracle8i数据库开发与专业应用(4)删除进程在高速缓存中正在使用的项.
6.
问:Oracel有哪些进程选项答:(1)归档进程;(2)恢复进程;(3)加锁写入进程;(4)专用服务器进程;(5)Net8进程;(6)并行查询进程;(7)Web服务器进程.
7.
问:在Oracle中,想要使用内存以提高速度的多用户DBMS,应该怎样做答:应把下列内容放入内存:(1)已经增加或改变的表中的各行.
它们首先被写入内存,所以用户进程不需要等待从磁盘上获取数据就能继续执行.
(2)那些与用户当前正在工作的行密切相关的行.
在大多数应用中,用户想要的下一行很可能与当前行相关联.
因为,大多数操作系统从磁盘驱动器中读出完整的块(512字节或者更多),如果在内存中存储了这些额外检索的行,那么很幸运,所需要的后续行正在高速内存中等待着.
(3)正在运行的应用程序所需的空间.
计算机执行存储在内存中的指令.
如果想要使一般的应用程序工作,则需要拥有一定的内存空间.
同样的概念适合于各种Oracle后台进程的存储代码.
(4)Oracle数据库进程与终端用户进程之间通信的信息.
该信息使许多操作系统进程能够与应用相关,这些应用使用Oracle数据库协调它们的行动.
8.
问:Oracle的心脏部分是什么,它有什么作用答:系统全局区SGA被认为是Oracle的心脏.
它存储的内容能帮助更快地存取数据.
没有SGA,就不能有Oracle数据库.
9.
问:SGA有哪些组成部分答:SGA个部分的组成如下:数据库(块)高速缓存区;重做日志缓冲区;共享池;进程间通信区;多线程服务器队列(在使用时).
10.
问:关于程序全局区有哪些需要注意的答:几点注意事项如下:(1)PGA属于单用户进程并只有该用户能够读写它;(2)如果未使用多线程服务器,计算机中也没有足够使用的内存,就会从Oracle中接收到一个出错信息;(3)如果正运行在客户/服务器的配置方式下,用户的PGA将在作为数据库服务器的机器上分配;(4)一些资料提到PGA是进程全局区(ProcessGlobalArea)而不是程序全局区(ProgramGlobalArea),其工作是一样的;(5)PGA的大小随着运行在不同操作系统上的Oracle版本而改变.
11.
问:从DBA的角度来看,可将文件划分为哪些类别答:可将文件划分为下列类别:第7章Oracle8组件和对象321(1)Oracle软件;(2)数据文件;(3)重做日志文件;(4)归档日志文件;(5)控制文件;(6)初始化文件;(7)日志和跟踪文件;(8)审计文件.
12.
问:怎样创建一个表答:下面的例子用来创建名为golf_scores的表:createtablegolf_scores(coursechar(20));data_playeddate;partnerchar(20);front_nicenumber(3);back_nicenumber(3);totalnumber(3);initrans1maxtrans100tablespaceuser_datastorage(inital10Knext10Kpctincrease0minextents1maxextents100);13.
问:关于索引需要注意的事项有哪些答:主要注意以下几点:(1)表不受索引的影响.
可以删除或重建索引,而不会影响表中的数据.
(2)在系统中执行大批量更新时,先删除索引,再执行修改,然后重建索引有时会更有好处.
(3)性能优化的规则之一是将某表的索引放到该表分布的不同磁盘上.
这样可以分散访问表和索引查询时所进行的输入/输出加载.
(4)创建唯一索引选项.
如果创建唯一索引选项,当试图插入一行列表中,并且索引列上的值与表中另一行的列值一致,就会给出一个错误.
这是强制表中的主键和以单步方式建立索引的好方法.
(5)如果具有创建或修改的权限,就拥有创建或修改与此表相连的索引的权限.
14.
问:视图可用于实现哪些对象答:(1)用户不想写把一个或多个表连接在一起的复杂的查询.
因此,建立一个逻辑,将这两个表连接成一个视图,让用户存取数据时仿佛是对表操作.
322Oracle8i数据库开发与专业应用(2)也许有这样一些表,其中只允许某些用户存取表中某些列的数据.
对于这种情况可以创建包含允许用户访问列的视图,让那些用户访问该视图而不是基表.
(3)如果拥有表的列名对某些用户无意义,那么可以创建一个视图重新命名这些列,使列名对用户有意义.
(4)可以处理比表更简单的结构.
举例来说,如果表上有上百列数据,那么可以创建一个更容易的视图,使用户只关心这个更容易的视图.
15.
问:存储过程有哪些令人感兴趣的优点答:存储过程展现了几个令人感兴趣的优点:(1)Oracle安全机制,像角色和授权,可用于保护数据和软件.
这也为安全管理提供了一种控制方法.
(2)当执行一个存储过程时,可以像它的创建者一样执行,而正常情况下没有此特权.
(3)存储过程的一个好处是Oracle存储了软件的源代码和分析版本(parsedversion),这样就节省了每次Oracle对外部软件应用中接收的SQL查询进行语句分析的时间.
16.
问:什么是序列,它有什么作用答:序列是一种工具,它用于在所使用的数据表中生成唯一的顺序号.
它是一种优秀的方法,用于在应用中生成确立唯一的号码来作为内部键连接两个表.
17.
问:在什么情况下采用表空间是值得的答:第一种,管理数据库已经很繁忙了,所以不愿意去再控制物理存储.
第二种,通过创建仅有一个数据文件的表空间,就能控制哪个磁盘接收数据.
18.
贯穿Oracle8的约束类型有哪些答:(1)null(2)notnull(3)default(4)unique(5)PRIMARYKEY(6)FOREIGNKEY(7)值表第8章用SQL*Report开发报表8.
1概述SQL*Report把文字格式化输出与SQL查询功能综合在一起,利用它既可以从Oracle数据库中提取信息(进行数据检索),又可以对输出格式加以控制,并可附加用户所要求的其他文字内容,是强有力的数据报表生成工具.
8.
1.
1SQL*Report的组成SQL*Report实际上是由两个Oracle实用程序RPF和RPT组成的.
RPF(ReportFormatter)是Oracle报表正文格式化程序,可以看作一个简单的面向Oracle数据库的排版程序,它控制报表的最终外观和格式;RPT(Reportgenerator)是Oracle报表生成程序,可以通过它与Oracle数据库打交道,执行SQL查询.
RPF与RPT相互配合构成了SQL*Report.
8.
1.
2SQL*Report是怎样工作的使用SQL*Report首先要编写报表控制文件,该文件是由RPT命令、RPF命令和用户所要求的正文材料一起组成的,它是用户要求的最终报表的控制者,是用RPT、RPF命令对最终报表的形式化说明;可以使用任何文本编辑程序来生成报表控制文件,一般后缀为.
RPT.
在建立了报表控制文件之后,就可以借助于RPT、RPF两个实用程序来获得最终的报表.
其处理过程如下:(1)首先由RPT逐行扫描报表控制文件(*.
RPT);(2)根据RPT命令行参数"用户名/口令字",打开相应的Oracle数据库,为提取信息作准备;(3)RPT解释执行报表控制文件的RPT命令,包括条件语句、循环、数据运算以及SQL查询等;(4)在RPT实用程序处理完成时,产生一个中间文件(后缀为.
RPF,名字可由用户指定),该文件包括报表控制程序中提供的正文,从Oracle数据库中按照SQL查询获得的信息,以及规定以上两者在最终报表中怎样格式化的RPF命令;(5)通过实用程序RPF来处理(4)所产生的中间文件(*.
RPF),即可获得最终报表.
如图8-1所示.
下面将对RPF、RPT实用程序的使用及其命令逐一进行介绍.
324Oracle8i数据库开发与专业应用图8-1报表生成过程8.
2报表正文格式化程序——RPF报表正文格式化程序是一个比较简单的文本排版程序,可以用于信函、文件和报表等文字处理应用,按用户要求输出格式化文本.
RPF可以独立使用,对于嵌入了RPF命令的正文文件(可以用任何文本编辑程序来生成)进行处理,产生格式化了的输出文件.
注意,RPT实用程序必须和RPF实用程序结合起来,才能按报表控制文件的要求,产生格式化输出文件.
8.
2.
1RPF的特点说明(1)表:这里表不是指Oracle数据库的表,RPF的表是一个矩形格式窗口,RPF处理的所有内容都将局限于某一表中,实际上,RPF命令是一种面向表的命令集合.
表分为两种:默认表和用户定义表.
默认表是指只有一栏并且栏宽为1~255的表,栏是RPF中另一个重要的概念.
(2)栏:每一张RPF的表,包括默认表至少要有一个栏,最多为255栏,栏规定了可放入正文区域的起始和终止位置,它与表的关系和数据库表中域与记录的关系相类似,在每一栏中,可以输出一个或多个字.
(3)字:是以至少一个空格或行结束符终结的一个或多个字符的集合.
每个字的长度必须小于或等于当前栏,在用中文输出时必须注意,一个中文句子可能被当成一个字来处理.
一个空格可以把两个字分开,但多余的空格对输出格式不起作用,RPF忽略多余空格.
同样制表符、回车换行等只作为分隔符号,对RPF的输出的字的位置没有任何作用.
8.
2.
2RPF句法所有的RPF命令都以.
或#引导,两者可以互换,如果以.
或#引导的字不是合法命令,则把该字做正文处理.
一般RPF命令格式为:#.
.
.
{#}第8章用SQL*Report开发报表325注意:由于RPT命令只能用.
引导,为了在编辑报表控制文件时区分两类命令,RPF命令在以后都用#作为引导或结束符.
RPF命令可以在一行的任何位置开始,每一条命令所带的参数都必须在同一行上,参数之间至少要有一个空格,有些RPF命令还必须以#结束.
8.
2.
3RPF命令介绍1.
RPF表操作命令:(1)DT:定义表语法:#DT.
.
.
#说明:所有的表都必须定义一次,是一个取值在0~29之间的数,作为表的标识符,同一标识符的两次定义,新的定义将取代旧的定义.
是成对出现的,定义表中第i栏的左右边界,它们都是指相对位置,即相对于该表调用时的起始位置而言,其中epi必须大于spi,spi-1必须大于1,如果最后一栏的右边界为0,则表示该栏的终止位置与调用该表时所在栏的终止位置相同.
DT命令必须以#结束.
一个表中最少有一栏,最多255栏.
如果在报表控制文件中(*.
RPT)或RPF文本控制文件中没有出现DT命令,则默认为已定义并调用一个有一栏的栏宽为1~255的表;由于默认表的存在,可以认为一切用DT定义过的表都是在相对于其他表的栏上调用的.
例如:#DT5152080#定义一个表,标识符为1,包括两个栏,第一栏从位置5到15,第二栏从20到80.
(2)T:调用表语法:#T说明:在当前栏中调用指定的表,被调用的表的起始位置与当前栏的起始位置相同.
是DT命令中指定的标识符.
在调用了该表之后,紧跟在后面的正文将在该表的位置以分栏为准.
直到遇到第一个TE命令.
(3)TE:关闭表语法:#TE说明:指示关闭最近调用的一张表,它执行一次仅关闭一张表.
例如:#DT12203050#定义表1#DT250#定义表2#T1调用表1#T2在表1第一栏调用表2.
.
.
#TE关闭表2,表1仍打开有效.
.
.
326Oracle8i数据库开发与专业应用#TE关闭表12.
RPF的栏操作命令(1)CL:栏文字命令语法:#CL.
.
.
.
.
.
.
.
.
#说明:该命令定义若干行文件,并在当前栏中不加格式化地加以输出,但每行文字不得超过当前栏宽,本命令严格按原样输出,并以第一字母为.
或#的空行结束,如果忘记输入结束命令,则以后所有的RPF命令都将被当作正文处理,这将导致RPF消耗大量内存资源.
(2)CS:在当前栏中跳过几行语法:#CS说明:该命令在当前栏中插入指定数目的空行,但对其他栏没有影响,其中lines是指定插入空行的数目.
(3)N:开始新的一行语法:#N说明:在当前栏中开始新的一行.
(4)NC:进入新的一栏语法:#NC说明:该命令结束当前栏进入下一栏(按从左到右的顺序),如果当前栏是最后一栏,则进入当前表的第一栏.
3.
RPF行操作命令(1)B:空行语法:#B说明:该命令插入一空行,对所有栏都起作用.
(2)L:暂停格式化定义,忽略栏定义,进行文字输出.
语法:#L.
.
.
.
.
.
.
.
.
第8章用SQL*Report开发报表327#说明:该命令使表和栏定义失效,指定若干正文行,忽略其中的RPF命令,从位置1开始输出,多空格、指标符可以显示地包含在输出文件中,与CL功能相同.
该命令以第一字符为.
或#的空行结束.
(3)S:跳过若干行语法:#S说明:该命令的作用是跳过指定的行数,应在第一栏内说明,对所有的栏都起作用,执行完S命令后,正文输出从第一栏起始处继续.
(4)SP:控制行间距语法:#SP说明:是从1~4的整数,表示行间距,其作用是全局的,与当前栏无关;缺省垂直间隔为1,此间隔从命令处开始有效,直到遇到另一个SP命令为止.
4.
RPF页操作命令(1)APN:交替页号语法:#APN说明:指明页号第一个字符在双数页上的绝对打印位置,该命令定义双数页号的打印位置.
如果纸的两面都打印,则此命令将双数页号打印在页的外侧.
(2)SPN:开始页编号语法:#SPN说明:该命令定义页编号,参数用来说明起始页号、编号类型以及页号在页上的位置.
该命令要独占一行.
页号总是打印在一页的第一个可打印行上,如果某页既有标题又有页号,则在第一个可打印行打印页号,然后空一行,再打印标题.
取值是1、2、3,表示编号类型.
1表示小节型编号.
页号为m-n,m是节编号,n是页编号.
2表示书信型编号,页号打印成1-n,n是页号,在第一页上不打印.
3表示句点型页编号,页号打印成.
n.
,n是页号.
4表示普通型页编号.
页号打印成n.
.
是表示页编号打印起始字符位置.
表示打印页号后跳过的行数.
是第一个输出页的编号.
仅对类型1有意义,表示页编号的小节编号.
(3)PAGE:定义页的上下边界语法:#PAGE说明:指定在输出正文前应跳过的行数,表示正文在一页中的最后一行.
当一页满时,RPF将自动跳至下一页.
(4)NP:开始新的一页语法:#NP说明:本命令应在第一栏进行说明,RPF无条件跳到下一页.
328Oracle8i数据库开发与专业应用(5)F:给图表保留指定的页语法:#Fpagenon>#说明:是指定的在输出时要跳过的页号,如果使用了页编号,则指定的页号将在输出时缺省.
注意命令结束符#.
5.
RPF打印机控制命令(1)HS:设置Diablo打印机字的间隔语法:#HS说明:为一数值,该数值的一个单位表示打印机的1/60寸.
缺省值为6,即每寸10个字符.
(2)VS:设置Diablo打印机垂直间隔语法:#VS说明:是一整数,乘以1/48,得到行间隔.
缺省值8,即每寸打印6行.
(3)PAUSE:暂停打印输出语法:#PAUSE说明:该命令使处理过程暂停,以便调整格式或继续打印前换纸.
执行此命令后,RPF等待从终端输入任一字符,然后继续处理.
注意,该命令只有在调用RPF命令行输入了W开关的情况下才起作用.
6.
其他格式控制命令(1)CEN:居中命令语法:#CEN#说明:该命令将指定的正文在当前栏内居中,被居中的正文包括从CEN命令之后开始至第一个后面不跟别的语法的#或.
为止,正文中的多重空格、制表符将被忽略.
(2)CUL:居中下划线语法:#CUL#说明:该命令与CEN类似,只是在居中的正文下加上下划线作为修饰.
(3)FR:左右对齐;R:右对齐;RR:右不对齐语法:#FR#R#RR说明:FR命令指示左右边界对齐,为RPF的缺省设置,指明每行的最后一个字在栏内向右对齐,额外的空格均匀地分散在行内.
RR命令指示右边界不对齐,左边界对齐.
R命令指示右边界对齐,左边界不对齐.
FR和RR的设置是互斥的,FR为缺省值,输入RR命令使FR失效;同样,FR也使RR失效.
R命令可以使FR和RR失效,再次调用R命令将使R命令失效.
(4)I:指示正文空格缩进第8章用SQL*Report开发报表329语法:#I说明:I命令使当前栏的下一行缩进参数指令的空格数.
当遇到#TE时该命令结束.
(5)P:命令语法:#P说明:该命令使正文从当前栏的下一行开始并缩进5个空格.
(6)TTL语法:#TTL[|]#说明:该命令指明一个标题,在页顶部宽度为的行中居中输出,标题最长为255个字节长.
标题的格式不受当前表的任何影响,为可选项,但如果选择,则它与必须用"|"分开.
(7)TTUL语法:#TTUL[|]#说明:该命令与TTL命令类似,只是给标题正文加上了下划线修饰.
(8)UL语法:#UL#说明:在指明的正文下加下划线修饰.
8.
2.
4RPF的特殊情况处理1.
嵌套表RPF的一个表的边界是相对于当前栏而言的,当一个表被调用且尚未关闭时,又调用另一新的表,那么新的表将把当前栏细分,并且新表的第一栏成为当前栏,新表的边界将位于原表的栏边界之内.
例如:#DT1545508090120##DT224610##T1545508090120#NC545508090120#T2表1当前栏330Oracle8i数据库开发与专业应用545508090120#TE5455080901202.
反斜线的用处(1)强制增添表格一般情况下RPF忽略输入文件中字之间的空格数,但有些时候用户需要在两个字之间保留一定数目的空格数,用反斜线后跟空格可以使输出中附加空格.
例如:输入正文输出正文MarlMaxlivesMarlMaxlivesMarlMax\livesMarlMaxlivesMarlMax\\\livesMarlMaxlives(2)打印反斜线RPF忽略跟在字后面的反斜线,如果要打印反斜线,则要使用两个连在一起的反斜线.
例如:输入正文输出正文\.
DTisaCommand.
\.
DTisaCommand.
尾部的.
不作为命令结束时也要后跟一反斜线才能正确输出.
8.
2.
5RPF的使用RPF正文控制文件的主要内容包括:定义表、调用表、正文格式输出、关闭表.
在编辑完成后,可通过使用RPF实用程序来得到最后的格式化输出.
语法:RPF表124610当前栏表当前栏表1当前栏第8章用SQL*Report开发报表331说明:是正文输入文件,是输出设备名,是一个或多个开关,用来控制RPF的执行.
由于开关中大部分仅支持Diablo型打印机,所以,开关不经常使用.
8.
2.
6RPF使用举例现有某钢厂一车间生产任务完成情况的正文输入文件,CJ1.
RPF清单.
#DT1586##DT231333436373##PAGE658#T1#S4#CEN某钢厂一车间第一季度##S2#单位:吨#S1#T2一月份#NC二月份#NC三月份#NC#R#S1123.
5#NC127.
6#NC130.
3#TE#L1993.
4##TE运行:RPFCJ1.
RPFCJ1.
LIS最后CJ1.
LIS的内容为:某钢厂一车间第一季度单位:吨一月份二月份三月份123.
5127.
6130.
31993.
48.
3报表生成程序RPTRPT是Oracle的实用程序之一,是SQL*Report的主要组成部分,通过RPT可以把332Oracle8i数据库开发与专业应用数据库信息、正文结合在一起,并进行格式化输出.
使用RPT需要对结构化数据查询语言SQL有一定的了解,并且会使用RPF格式进行格式化输出.
RPT命令文件(即报表控制文件),可以看成是嵌入了SQL语言和RPF命令的一种过程性高级语言文件,可以进行较好的模块化程序设计.
SQL命令和RPF命令在RPT命令文件中主要以宏的概念出现,宏有自己的名字,并可以通过这个名字来调用,有些类似于Foxbase中的过程,因此,对于经常使用过程语言编程的设计者来说,RPT是比较容易掌握的.
8.
3.
1关于RPT的说明(1)RPT允许使用SQL查询来检索Oracle数据库中的信息,并可以通过SQL来操纵这些信息,还可以对这些信息定义其输出格式,并可以附加其他文件,如报表头、报表尾、边框线、修饰线等,以保证输出符合使用者意图的报表.
(2)用户可选用任意文本编辑器来编辑生成报表控制文件(后缀为.
rpt),然后通过RPT实用程序来处理并生成中间文件(后缀为.
rpt),在中间文件中仅仅包括正文和RPT命令,可以使用RPF实用程序来生成最终报表.
以下命令可以执行RPT实用程序:RPT[userid/password]是RPT报表控制程序文件名,是要生成的中间文件的名字,[userid/password]是用户的Oracle账户名和口令.
(3)RPT实用程序的执行过程是这样的:解释执行报表控制程序中的RPT命令,检索数据信息,把这些信息送入中间文件,并进行合理的组织,忽略报表控制程序中的正文和RPF命令,直接把它们拷贝到中间文件中.
(4)一般的报表控制程序可以按三部分进行模块化设计:数据说明部分;宏定义部分;过程部分(报表输出部分).
虽然在RPT命令中仅要求程序变量、宏必须先定义后使用,对其位置没有绝对的要求,但把程序分成以上三部分将对文件的可读性、易维护性提供很大的方便.
8.
3.
2RPT语句解释按功能分类,RPT语句有六种类型:(1)说明语句;(2)宏定义语句;(3)宏执行语句;(4)程序控制语句;(5)算术运算语句;(6)其他语句.
RPT语句的一般格式为:.
.
.
.
其命令必须以.
作为引导符,每条命令必须占一整行,报表正文和其他命令不能在这一行上出现,参数之间以空格分隔,而且必须与命令在同一行上出现.
第8章用SQL*Report开发报表333下面就分类一一介绍RPT命令.
1.
说明语句(1)DECLARE语句语法:.
DECLARE是指定程序变量名,其命名规则要求是第一字符必须是字母,后面可以跟字母、数字、下划线(_)等,其长度限定为1~30字符.
是指变量输出到中间文件时的格式,仅支持三种数据类型:字母数字类型、数字型和日期型.
对数字型来说,格式定义关系到算术运算结果的取舍.
①字母数字变量:包含任意可打印字符,格式为An,n表示字符的个数,例如:.
DECLAREvarlA6变量varl是一长度为6的字母数字型变量.
在程序中,所有字母数字型变量的初始值为NULL.
②数字变量:数字变量的定义格式比较复杂,在格式中使用以下符号来说明:9定义数字变量的各位,不显示前零;.
定义小数点在数字变量中的位置;,把逗号插入在输出数字中,如果左边没数字,输出时省略该逗号;$在输出数字前打印美元符号;MI将负号显示在负数的右边,缺省定义的符号在数值的左边;PR把负数值显示在尖括号中;O代替9来表示一位,在通常情况下不打印前零,但格式中有0则打印每个数字位;V定义数字变量的小数点位置.
此位置用来在算术语句中对数值各位对齐,但输出时不打印小数点;B变量为零时输出空格.
各种数字格式举例:格式值显示999.
9933.
14833.
15999V9933.
14833159,99916881,688099918801889999-1234-12349999MI-12341234-9999PR-1234B99099.
99123.
4423.
44$99.
9954.
31$54.
31如果从数据库中检索到的值超出格式的范围,则打印#号,但如果是由于算术运算造成超出格式,则显示截断值.
③日期变量:在RPT有三种日期格式:分别为YYMMDD,date(NN/DD/YY)和edate334Oracle8i数据库开发与专业应用(DD/MM/YY),一般情况下,除非报表本身要求对日期进行运算,否则,用字符数字型变量来代替日期变量进行输出.
使用者可在SQL中使用TO_CHAR(),TO_DATE()函数来完成字符串和日期之间的转换.
(2)SET语句语法:.
SET""说明:表示已经定义过的一个程序变量,表示与类型相匹配的数字、字符或日期值常量.
例如:.
SETvar2"John".
SETvar31234.
SETvar4$$DATE$$SET命令相当于常量赋值语句,即把一相匹配常量值赋给指定变量.
(3)EQUAL命令语法:.
EQUAL说明:把源变量的值赋给目的变量,对于字符变量,如果比长,那么就将长出的部分截掉,余下的赋给,如果较短,则补以空格.
对数字变量,如果小数部分较短,则对进行四舍五入,但不允许发生溢出.
例如:.
DECLAREA999.
99.
DECLAREB99.
9.
SETA932.
76.
EQUALBA此时B的值为32.
8.
2.
宏定义语句RPT中能够定义两种宏语句,即SELECT宏语句和过程宏语句,前者主要用来执行SQL(SELECT)语句,与数据库打交道;后者可以包括RPT命令和正文.
两种宏语句语法是类似的.
语法:.
DEFINESQL(SELECT)语句或RPF、RPT命令和正文.
.
说明:是宏的名字,其命名规则与变量名的命名规则相同,最后一行的.
.
是宏定义结束标志.
两种宏定义的区别是很大的.
(1)SELECT宏定义第8章用SQL*Report开发报表335SELECT宏语句由一个SQL查询语句构成,这个查询语句可包括任意合法的SQL子句及SELECT语句参数,这样SELECT宏语句就拥有了SQL查询语言所有数据检索功能.
语句中SQL语句的最大长度为2KB.
除了标准的SQL语句外,还必须包括INTO子句,该子句用来指定那些保存查询结果的变量.
下面例子是一个比较典型的SELECT宏定义:.
DEFINEexample1SELECTename,salINTOsename,ssalFROMempWHEREJOB='MANAGER'ANDsal>2000.
.
使用程序变量名前加&号,可以定义带参数的SELECT宏,使宏更加通用.
修改上例:.
DEFINEexample2SELECTename,salINTOsename,ssalFROMempWHEREJOB=&JOB_VALANDsal>2000.
.
JOB_VAL和sal_val是已经定义过的程序变量,分别存放工作种类和工资最低限,如果在程序中对二者赋以不同值,执行宏example2就会得到不同的结果,提高宏应用的灵活性.
此外,利用程序变量还可以在宏之间传递信息.
(2)过程宏过程宏就像是一个有名字的小子程序,在过程宏中可以包括RPT命令语句、RPF命令语句和正文;过程宏是不可以嵌套的,但在过程宏中可以调用另外一个宏语句.
下面是一个过程宏的例子:DEFINEheading#T1#CUL雇员薪水清单##S2.
PRINTssal#S2.
.
3.
宏的执行宏的执行可以分为SELECT宏执行、过程宏执行和REPORT语句三种方式.
(1)SELECT宏执行语法:.
EXECUTE说明:该语句使得SELECT被执行,并返回查询结果的第一行,结果放在由INTO子句定义的相应变量中.
(2)过程宏执行语法:336Oracle8i数据库开发与专业应用.
说明:过程宏的执行不需要其他修饰,直接把过程宏名写在点后面就可以了.
在执行之前,过程宏必须被定义,例如:.
heading过程宏heading被执行.
(3)REPORT语句在使用宏时,如果仅想完成较简单的格式化输出和其他变量输出,一般用过程宏,仅返回一条记录的查询可以用EXCUTE命令来使SELECT宏执行,但在涉及SELECT宏要返回多条记录,并对它们进行格式化输出时,使用REPORT语句是最简洁的方法.
该语句使SELECT宏和过程宏自动联合执行.
.
REPORT[]说明:REPORT语句从要处理的SELECT宏返回每一行,并且对每一行都要执行指定的过程宏.
:查询数据库中的记录.
:是一过程宏,当返回查询结果的第一行时,REPORT语句执行一次头宏,以后就再也不执行头宏.
中一般包括报表的题目和栏标题等内容,头宏是可选项.
:是一过程宏,如果REPORT语句中有头宏的话,体宏的处理范围是宏查询结果的第二行到最后一行,如果没有头宏选项,则从第一行到最后一行;对每一行执行一次体宏.
体宏主要能够完成按指定格式输出每一行数据,数据累计、分页功能.
体宏是必选项.
:当处理完查询结果的最后一行后,执行该宏,在足宏中,一般输出总计和脚注等内容.
足宏是可选的.
REPORT语句的执行可完成多条查询结果的输出,而且在体宏、头宏和足宏中也可以出现REPORT语句,从而产生嵌套的报表输出,完成很复杂的功能.
下面举一个嵌套报表打印的例子:总经理需要知道下属各部项目完成情况,所需要的信息主要存在dept和proj两个表中,它们的数据结果分别是:dept:部门表nochar(3)部门编号namechar(20)部门名称locationchar(40)部门所在城市proj:项目表nochar(3)项目编号namechar(20)项目名称ddatedate完成项目dept_nochar(3)所属部门编号根据以上库结构,就可以编写相应的报表程序了:.
REM.
REM部门报表程序第8章用SQL*Report开发报表337#DT110100##DT21030355560100105125#.
DECLAREdeptnoa3.
DECLAREdeptnamea20.
DECLARElocationa40.
DECLAREprojnoa3.
DECLAREprojnamea20.
DECLAREddatea8.
DEFINEseldeptSELECTno,name,lactionINTOdeptno,deptname,locationFROMdept.
.
.
DEFINEselprojSELECTno,name,ddateINTOprojno,projname,ddateFROMprojWHEREdeptno=&deptno.
.
.
DEFINEprojbody#NC.
PRINTprojno#NC.
PRINTprojname#NC.
PRINTddate#NC.
.
.
DEFINEprojhead#TE#T2#NC#CENprojectNO.
##NC#CENProjectName##NC#CENFinishDate##NC#S1.
projbody338Oracle8i数据库开发与专业应用.
.
.
DEFINEprojfoot#TE.
.
.
DEFINEdeptbody#T2.
REPORTselprojprojbodyprojheadprojfoot.
.
.
REM#T1#CENDEPARTMENT-PROJECTREPORT##TE#T2#CENDepartment##NC#CENDepartment##NC#CENDepartment##NC#NC#CENNumber##NC#CENName##NC#CENLocation##TE.
REPORTseldeptdeptbody#STOP以上程序执行结果是这样的:DEPARTMENT-PROJECTREPORTDepartmentDepartmentDepartmentNumberNamelocation007BellNewYorkProjectNO.
Projectnamefinishdate555BoardDesign04/25/83421chipManufact09/13/85各宏之间的调用关系如图8-2所示.
除了嵌套表之外,还可以通过在SELECT宏中采用多个SELECT语句,检索复杂的问题.
第8章用SQL*Report开发报表339图8-2宏调用关系图4.
程序控制语句程序控制语句与高级语言中的类似,主要是分支和条件转移语句.
它们可以用来解决一些SQL语句或RPF语句无法解决的问题.
(1)标号定义语句语法:.
&说明:标号名的命名规则遵循一般的变量名的命名规则,一般在过程宏中定义标号作为分支控制的转移标志,标号的定义只能在同一个宏中起作用,是局部的,不能够跨越宏,因此,在不同的宏中可以用相同的标号名.
(2)GOTO语句语法:.
GOTO说明:标号名是指在当前宏中已被定义的一个标号,GOTO语句可以控制程序无条件地转移到标号处执行.
GOTO语句是分支控制语句.
(3)IF语句语法:.
IF""THEN[ELSE]说明:IF语句根据表达式值的真假,转移到标号1或标号2处执行,与一般高级语言的IF语句相同.
必须用双引号括起来,而且在表达式中出现的变量前面必须加&,字符常量要用单引号引起来;表达式中允许出现关系算符和逻辑算符,也可出现算术算符,下面是结果表达式的例子.
"&name='ORACLE'""&value>400""&x1>&x2and&x2>200"程序中引用的变量与表达式中参与比较的常量的类型必须是相同的,而且变量不允许是空值,否则,整个表达式是无效的,例如:"&x>'100'and&x5"在允许空值出现的数据库列上,一般要对存放该列数值的变量赋初始值,零或空格.
340Oracle8i数据库开发与专业应用也可以使用NVL函数,在SELECT语句中对该列的值初始化.
例如:SELECTNVL(Z,0)INTOvalueFROMT1这样就可以正确使用value参与表达式的运算了.
IF语句中ELSE是可选项,如果值为假,则表达式就执行IF语句下面的一条语句.
在RPT语句中,IF语句的执行是比较慢的,因此在使用它时应充分考虑效率的问题.
(4)IFNULL语句语法:.
IFNULL说明:IFNULL语句用来检验变量的值是否为空,如果为空,则转移到标号名处,否则,顺序执行程序.
IFNULL语句的执行速度比IF语句快得多,可以在某些时候代替IF语句.
它没有ELSE选项.
(5)STOP语句语法:.
STOP说明:STOP语句使报表停止执行,它可以在RPT程序的过程部分或过程宏中出现.
如果一个RPT程序中没有STOP语句的话,那它在执行完最后一条语句后结束.
5.
算术运算语句语法:.
ADD.
SUB.
MUL.
DIV.
DSUB说明:算术运算语句完成源变量1和源变量2之间的加、减、乘、除运算,结果放在目的变量中.
除去DSUB之外,源变量都是数值变量,而且都可以用数字代替源变量的位置,目的变量都是数值型变量,用来存放源变量的运算结果,如果结果实际值超出了目的变量声明的范围,将产生溢出,但程序不会出错.
例如X=10,Y=2,则.
ADDZXYZ的值是12;.
SUBZXY;Z的值是8;.
MULZXYZ的值是20;.
DIVZXYZ的值是5.
DSUB语句要求源变量必须是日期变量,目的变量是数值变量,用来存放两个日期之第8章用SQL*Report开发报表341间相差的天数.
例如date1=01/02/92date2=12/25/91则.
DSUBZdate1date2Z的值是30.
6.
其他语句(1)PRINT语句语法:.
PRINT[.
.
.
]说明:PRINT语句和下面将要介绍的FPRINT语句是RPT语言中唯一能够把存放在变量中的数据库内容输出到报表中去的命令语句.
变量名是指前面已声明过的变量的名字,其内容根据声明的格式来定义.
在RPT语句中,用PRINT语句来输出变量中的数据,并放在相应的栏中.
(2)FPRINT命令语法:.
FPRINT[空格数变量][空格数变量].
.
.
]说明:FPRINT语句的用法与PRINT类似,空格数常量是一可选项,用来指明后面的变量名前面想要附加的空格数,如果此项省略,则表示不附加空格了,此时FPRINT与PRINT的意义是相同的,变量之间缺省的间隔为两个空格.
例如:.
DECLAREA99.
DECLAREB99.
SETA20.
SETB30.
PRINTAB输出结果为:2030(20与30中间有两个空格).
FPRINT3A3B输出结果为:2030(20与30前面各有两个空格).
FPRINTAOB输出结果为:2030(20与30间没有空格)(3)ASK语句语法:.
ASK"提示信息"说明:ASK语句把在屏幕上显示出来,并等待从键盘输入一个值,把这个值赋给已声明过的,ASK语句是唯一的可以在程序执行过程中与用户交互的语句,利用它可以由用户灵活控制程序的流程.
(4)TELL语句语法:.
TELL"信息"说明:TELL语句原封不动把显示在屏幕上,是一字符常量;通过这条语句可以向用户通报程序的运行情况.
342Oracle8i数据库开发与专业应用(5)REM语句语法:.
REM说明:REM语句完全是由程序开发人员提供的,它允许在源程序中作注释说明,而不影响程序的任何功能,只为了程序便于维护.
REM语句所在的一行均作注释处理.
(6)COMMIT语句和ROLLBACK语句语法:.
COMMIT.
ROLLBACK说明:这两条语句不带任何参数,COMMIT语句结束当前事务,使对数据库的修改成为永久性的,并开始一新的事务;ROLLBACK语句使当前事务返回到刚开始的状态,然后开始一新的事务.
8.
4小结1.
问:SQL*Report的组成有哪些答:SQL*Report实际上是由两个Oracle实用程序RPF和RPT组成的.
RPF(ReportFormatter)是Oracle报表正文格式化程序,可以看作一简单的面向Oracle数据库的排版程序,它控制报表的最终外观和格式.
RPT(Reportgenerator)是Oracle报表生成程序,可以通过它与Oracle数据库打交道,执行SQL查询.
RPF与RPT相互配合构成了SQL*Report.
2.
问:SQL*Report是怎样工作的答:使用SQL*Report首先要编写报表控制文件,该文件是由RPT命令、RPF命令和用户所要求的正文材料一起组成的,它是用户要求的最终报表的控制者,是用RPT、RPF命令对最终报表的形式化说明.
在建立了报表控制文件之后,就可以借助于RPT、RPF两个实用程序来获得最终的报表.
3.
问:RPF句法有哪些限制答:(1)由于RPT命令只能用.
引导,为了在编辑报表控制文件时区分两类命令,RPF命令在以后都用#作为引导或结束符.
(2)RPF命令可以在一行的任何位置开始,每一条命令所带的参数都必须在同一行上,参数之间至少要有一个空格,有些RPF命令还必须以#结束.
4.
问:RPF能否构成嵌套表答:能.
RPF的一个表的边界是相对于当前栏而言的,当一个表被调用且尚未关闭时,又调用另一新的表,那么新的表将把当前栏细分,并且新表的第一栏成为当前栏,新表的边界将位于原表的栏边界之内.
5.
问:反斜线有哪些用处答:(1)强制增添表格;第8章用SQL*Report开发报表343(2)打印反斜线.
6.
问:RPF正文控制文件有哪些主要内容答:主要内容包括:定义表、调用表、正文格式输出、关闭表.
7.
问:RPT语句有哪几种类型答:(1)说明语句;(2)宏定义语句;(3)宏执行语句;(4)程序控制语句;(5)算术运算语句;(6)其他语句.
8.
问:是指变量输出到中间文件时的格式,仅支持哪三种数据类型答:字母数字类型、数字型和日期型.
9.
问:使用EQUAL命令把源变量付给目的变量,要考虑哪些问题答:把源变量的值赋给目的变量,对于字符变量,如果比长,那么就将长出的部分截掉,余下的赋给,如果较短,则补以空格.
对于数字变量,如果小数部分较短,则对进行四舍五入,但不允许发生溢出.
10.
问:RPT中能够定义哪些宏语句,各有什么作用答:RPT中能够定义两种宏语句,即SELECT宏语句和过程宏语句,前者主要用来执行SQL(SELECT)语句,与数据库打交道;后者可以包括RPT命令和正文.
两种宏语句语法是类似的.
11.
问:宏的执行有哪些方式答:宏的执行可以分为SELECT宏执行、过程宏执行和REPORT语句三种方式.
12.
问:程序控制语句有哪些答:程序控制语句与高级语言中的类似,主要是分支和条件转移语句.
它们可以用来解决一些SQL语句或RPF语句无法解决的问题.
(1)标号定义语句;(2)GOTO语句;(3)IF语句;(4)IFNULL语句;(5)STOP语句.
第9章数据库的安全性、完整性、并发控制和恢复为了保证数据库数据的安全可靠和正确有效,DBMS必须提供同一的数据保护功能.
数据保护也称为数据控制,主要包括数据库的安全性、完整性、并发控制和恢复.
9.
1数据库的安全性数据库的安全性是指保护数据库以防止不合法的使用所造成的数据泄露、更改或破坏.
计算机系统都有这个问题,在数据库系统中大量数据集中存放,为许多用户共享,使安全问题更为突出.
在一般的计算机系统中,安全措施是一级一级设置的,如图9-1所示模型.
图9-1计算机系统安全控制模型在数据库存储这一级可采用密码技术,当物理存储设备失窃后,它起到保密作用.
在数据库系统这一级中提供两种控制:用户标识和鉴定,数据存取控制.
在Oracle多用户数据库系统中,安全机制做下列工作:(1)防止非授权的数据库存储;(2)防止非授权的对模式对象的存取;(3)控制磁盘使用;(4)控制系统资源使用(如CPU时间);(5)审计用户动作.
数据库安全性可分为两类:系统安全性和数据安全性.
系统安全性是指在系统控制数据库的存取和使用的机制,包含:(1)有效的用户名/口令的组合;(2)一个用户是否授权可连接数据库;(3)用户对象可用的磁盘空间的数量;(4)用户的资源限制;(5)数据库审计是否是有效的;第9章数据库的安全性、完整性、并发控制和恢复345(6)用户可执行哪些系统操作.
数据安全性是指在对象级控制数据库的存取和使用机制,包含:哪些用户可存取一指定的模式对象及在对象上允许哪些操作类型.
在Oracle服务器上提供了一种任意存取控制,是一种基于特权(privilege)限制信息存取的方法.
用户存取一对象必须有相应的特权授给该用户.
已授权的用户可任意地将它授权给其他用户,由于这个原因,这种安全性类型叫作任意型(discretionary).
Oracle利用下列机制管理数据库安全性:(1)数据库用户和模式;(2)特权;(3)角色(Role);(4)存储设置和空间份额;(5)资源限制;(6)审计.
9.
1.
1数据库的存取控制Oracle保护信息的方法采用任意存取控制(discretionaryaccesscontrol)来控制全部用户对命名对象的存取.
用户对对象的存取受特权控制,一种特权是存取一命名对象的许可,为一种规定格式.
Oracle使用多种不同的机制管理数据库安全性,其中有两种机制:模式和用户.
模式(schema)为模式对象的集合,模式对象如表、视图、聚集、过程和包等.
每一数据库有一组模式.
每一Oracle数据库有一组合法的用户(user),可存取一数据库,可运行一数据库应用(如SQL*FORMS的电子表格、SQL*Plus或预编译程序)和使用该用户名连接到定义该用户的数据库.
当建立一数据库用户时,对该用户建立一个相应的模式,模式名与用户名相同.
一旦用户连接到一数据库,该用户就可存取相应模式中的全部对象,一个用户仅与同名的模式相联系,所以用户名和模式是类似的.
用户的存取权利受到用户安全域(user'ssecuritydomain)的设置所控制,在建立一个数据库的新用户或更改一已有用户时,安全管理员(securityadministrator)对用户安全域有下列决策:(1)是由数据库系统还是由操作系统维护用户授权信息;(2)设置用户的缺省表空间和临时表空间;(3)列出用户可存取的表空间和表空间中可使用空间份额;(4)设置用户资源限制的环境文件,该限制规定了用户可用的系统资源的总量;(5)规定用户具有的特权和角色,可存取相应的对象.
每一个用户有一个安全域,它是一组特性,可决定下列内容:(1)用户可用的特权和角色;(2)用户可用的表空间的份额(磁盘空间);(3)用户的系统资源限制(如CPU处理时间).
1.
用户鉴别为了防止非授权的数据库用户的使用,Oracle提供两种确认方法:操作系统确认和相应的Oracle数据库确认.
346Oracle8i数据库开发与专业应用如果操作系统允许,Oracle可使用操作系统所维护的信息来鉴定用户.
由操作系统鉴定用户的优点是:(1)用户可方便地连接到Oracle,不需要指定用户名和口令.
例如:在用户进入SQL*PLUS时,只需进入:.
SQLPLUS/(2)对用户授权的控制集中在操作系统,Oracle不需要存储和管理用户口令,然而用户名在数据库中仍然要维护.
(3)在数据库中的用户名项和操作系统审计跟踪相对应.
Oracle数据库方式的用户确认:Oracle利用存储在数据库中的信息可鉴定视图连接到数据库的这一用户,这种鉴别方法仅当操作系统不能用于数据库用户鉴别时才使用.
当用户使用一Oracle数据库,执行用户鉴别.
每个用户在建立时有一个口令,用户口令在建立对数据库连接时使用,以防止对数据库非授权的使用.
用户的口令以密码的格式存储在数据库书库字典中,用户可随时修改其口令.
2.
用户的表空间设置和定额关于表空间的使用是用户安全域的部分,可有几种设置选择:(1)用户的缺省表空间;(2)用户的临时表空间;(3)数据库表空间的空间使用定额.
每个用户同一个缺省表空间相联系.
当用户在建立一模式对象时,如果没有指定表空间,那么就使用该表空间.
用户缺省表空间在建立用户时被指定,之后可修改.
每个用户对数据库的任何表空间可赋给一空间定额.
缺省方式时,则每个用户在数据库任何表空间上没有定额.
要建立某种模式对象,该用户必须具有建立该对象的特权,并且在建立对象的表空间中具有空间定额.
还可在另一用户模式下建立,此时另一用户在该表空间中要有空间定额.
3.
用户资源限制和环境文件利用显式地设置资源限制,安全管理员可防止用户无控制地消耗宝贵的系统资源(如CPU时间).
Oracle资源限制的特性大多在多用户系统中非常有用.
资源限制是由环境文件管理.
一个环境文件是命名的一组赋给用户的资源限制.
另外Oracle为安全管理员在数据库级提供能或不能实施环境文件资料限制的选择.
Oracle可限制几种类型的系统资源的使用,每种资源可在会话级、调用级或两者上控制.
在会话级:每一次用户连接到一数据库,建立一会话(session).
每一会话在执行SQL语句的计算机上消耗CPU时间和内存量进行限制.
对Oracle的几种资源限制可在会话级上设置.
如果会话级资源限制被超过,当前语句被中止(回滚),并返回指明会话限制已达到的信息.
此时,当前事务中所有之前执行的语句不受影响,此时仅可作COMMIT、ROLLBACK或删除对数据库连接等操作,进行其他操作都将出错.
在调用级:在SQL语句执行时,处理语句有好几步,为了防止过多地调用系统,Oracle在调用级可设置几种资源限制.
如果调用级的资源限制被超过,语句处理被停止,该语句被回滚,并返回一条错误信息.
然而当前事务的已执行所有语句不受影响,用户会话继续连接.
第9章数据库的安全性、完整性、并发控制和恢复347有下列资源限制:(1)为了防止无控制地使用CPU时间,Oracle可限制每次Oracle调用的CPU时间和一次会话期间Oracle调用所使用的CPU总时间,以0.
01秒为单位.
(2)为了防止过多的I/O,Oracle可限制每次调用的每次会话的逻辑数据块读的数目.
逻辑数据块读包含从内存或磁盘读数据块.
(3)Oracle在会话级还提供其他几种资源限制:①每个用户的并行会话数的限制;②会话空闲时间的限制,如果一次会话的Oracle调用之间时间达到该空闲时间,当前事务被回滚,会话被中止,会话资源返回给系统;③每次会话可消逝时间的限制,如果一次会话期间超过可消逝时间的限制,当前事务被回滚,会话被删除,该会话的资源被释放;④每次会话的专用SGA空间量的限制.
用户环境文件(profile):是指定资源限制的命名集,可赋给Oracle数据库的有效的用户.
利用用户环境文件可容易地管理资源限制.
要使用用户环境文件,首先应将数据库中的用户分类,决定在数据库中全部用户类型需要多少种用户环境文件.
在建立环境文件之前,要决定每一种资源限制的值.
例如一类用户通常不执行大量逻辑数据块读操作,那就可将LOGICAL_READS_PER_SESSION和LOGICAL_READS_PER_CALL设置相应的值.
在许多情况中决定一用户的环境文件的合适资源限制的最好方法是收集每种资源使用的历史信息.
9.
1.
2特权和角色1.
特权特权是执行一种特殊类型的SQL语句或存取另一用户的对象的权力.
Oracle有两类特权:系统特权和对象特权.
(1)系统特权系统特权是执行一种特殊动作或在对象类型上执行一种特殊动作的权力.
Oracle有60多种不同系统特权,每一种系统特权仅允许用户执行一种特殊的数据块操作或一类数据库操作.
系统特权可授权给用户或角色,一般,系统特权授权给管理人员和应用开发人员,终端用户不需要这些相关功能.
授权给一般用户的系统特权具有ADMINOPTION选项时或具有GRANTANYPRIVILEGE系统特权的用户可将该系统特权授权给其他用户或角色.
反之,可从那些被授权的用户或角色回收系统特权.
(2)对象特权对象特权是在指定的表、视图、序列、过程、函数或包上执行特殊动作的权利.
对于不同类型的对象,有不同类型的对象特权.
对于有些模式对象,如聚集、索引、触发器、数据库链没有相关的对象特权,它们由系统特权控制.
对于包含在某用户名的模式中的对象,该用户对这些对象自动地具有全部对象特权,即模式的持有者对模式中的对象具有全部对象特权.
这些对象的持有者可将这些对象上的任何对象特权授权给其他用户.
如果被授权者包含有GRANTOPTION授权,那么该被授权者也可将其权利再授权给其他用户.
348Oracle8i数据库开发与专业应用2.
角色角色(Role)为相关特权的命名组,可授权给用户和角色.
Oracle利用角色更容易地进行特权管理.
有下列优点:(1)减少特权管理,不要显式地将同一特权组授权给几个用户,只需将这特权授给角色,然后将角色授权给每一用户.
(2)动态特权管理,如果一组特权需要改变,只需修改角色的特权,所有授权给该角色的全部用户的安全域将自动反映对角色所作的修改.
(3)特权的选择可用性,授权给用户的角色可选择地使其能(可用)或不能(不可用).
(4)当一用户经用户名执行应用时,该数据库应用可查询字典,将自动地选择使角色能或不能.
(5)专门的应用安全性,角色使能可由口令保护,应用可提供正确的口令使角色使能,达到专用的应用安全性.
因用户不知其口令,不能使角色使能.
一般,建立角色服务于两个目的:为数据库应用管理特权和为用户组管理特权.
相应的角色称为应用角色(applicationrole)和用户角色(userrole).
应用角色是授予的运行一数据库所需的全部特权.
一个应用角色可授权给其他角色或指定用户.
一个应用可有几种不同角色,具有不同特权组的每一个角色在使用应用时可进行不同的数据存取.
用户角色是为具有公共特权需求的一组数据库用户而建立的.
用户特权管理是受应用角色或特权授权给用户角色所控制,然后将用户角色给相应的用户.
角色的使用如图9-2所示.
图9-2角色的使用第9章数据库的安全性、完整性、并发控制和恢复349数据库角色包含下列功能:(1)一个角色可授予系统特权或对象特权;(2)一个角色可授权给其他角色,但不能循环授权;(3)任何角色可授权给任何数据库用户;(4)授权给一用户的每一角色可以是使能的或者不能的,一个用户的安全域仅包含当前对该用户使能的全部角色的特权;(5)一个间接角色(授权给另一角色的角色)对一用户可显式地使其使能或不能.
在一个数据库中,每一个角色必须唯一.
角色名与用户不同,角色不包含在任何模式中,所以建立一角色的用户被删除时不影响该角色.
Oracle为了提供与以前版本的兼容性,预定义下列角色:CONNECT、RESOURCE、DBA、EXP_FULL_DATABASE和IMP_FULL_DATABASE.
9.
1.
3审计审计是对选定的用户动作的监控和记录,通常用于:(1)审查可疑的活动.
例如,数据被非授权用户所删除,此时安全管理员可决定对该数据库的所有连接进行审计,以及对数据库的所有表的成功的或不成功的删除进行审计.
(2)监视和收集关于指定数据库活动的数据.
例如:DBA可收集那些被修改、执行了多少次逻辑的I/O等统计数据.
Oracle支持三种审计类型:(1)语句审计,对某种类型的SQL语句审计,不指定结构或对象.
(2)特权审计,对执行相应动作的系统特权的使用审计.
(3)对象审计,对一特殊模式对象上的指定语句的审计.
Oracle所允许的审计选择限于下列方面:(1)审计语句的成功执行、不成功执行.
(2)对每一用户会话审计语句执行一次或者对语句每次执行审计一次.
(3)对全部用户或指定用户的活动的审计.
当数据库的审计是使能时,在语句执行阶段产生审计信息.
审计记录包含有审计的操作、用户执行的操作、操作的日期和时间等信息.
审计记录可存在数据字典表(称为审计记录)或操作系统审计记录中.
数据库审计记录是在SYS模式的AUD$表中.
9.
2数据完整性数据库数据完整性(dataintegrity)是指数据的正确性和相容性.
DBMS必须提供一种功能来保证数据库的数据完整性,这种功能称为完整性检查.
数据完整性是为了防止数据库存在不符合定义的数据,防止错误信息输入和输出,即数据要遵守由DBA或应用开发者所决定的一组预定义的规则.
Oracle应用于关系数据库的表的数据完整性有下列类型:(1)在插入或修改表时不允许包含有空值的列,称为非空规则;(2)唯一列值规则,允许插入或修改的表行在该列(或组列)上的值唯一;(3)主码值规则,主码的列值唯一地标识表的每一行;350Oracle8i数据库开发与专业应用(4)引用完整性规则,同关系模型定义;(5)用户对列定义的规则,为复杂的完整性检查.
Oracle允许定义和实施上述每一种类型的数据完整性规则,这些规则可用完整性约束(integrityconstraint)和数据库触发器定义.
完整性约束,是对表的定义规则的说明性方法(declarativemethod).
数据库触发器,是使用非说明方法实施完整性规则,利用数据库触发器(存储的数据库过程)可定义和实施任何类型的完整性规则.
9.
2.
1完整性约束Oracle利用完整性约束机制防止无效的数据进入数据库的基表,如果任何DML执行结果破坏完整性约束,该语句被回滚并返回一个错误.
Oracle实现的完整性约束完全遵守ANSIX3.
135_1989和ISO9075_1989标准.
利用完整性约束实施数据完整性规则有下列优点:(1)由于使用SQL命令定义完整性约束,以至在定义或更改表时,不需要程序设计,便很容易地编写程序并可消除程序性错误,其功能是由Oracle控制.
所以完整性约束优于应用代码和数据库触发器.
(2)对表所定义的完整性约束是存储在数据字典中,所以由任何应用进入的数据都必须遵守与表相联的完整性约束.
(3)具有最大应用开发能力.
当由完整性约束所实施的事务规则改变时,管理员只需改变完整性约束的定义,所有应用自动地遵守所修改的约束.
(4)由于完整性约束存储在数据字典中,数据应用可利用这些信息,在SQL语句执行之前或由Oracle检查之前,就可立即提供反馈信息.
(5)由于完整性约束可临时地使不能,以至在装入大量数据时可避免约束检索的开销,因此,当数据装入完成时,完整性约束可容易地使其使能,任何破坏完整性约束检索的新行在例外表中列出.
Oracle的DBA和应用开发者对列的值输入可使用的完整性约束有下列类型:(1)NOTNULL约束;(2)UNIQUE码约束;(3)PRIMARYKEY约束;(4)FOREIGNKEY约束(或称引用约束);(5)CHECK约束.
NOTNULL完整性约束:如果在表的一列的值不允许为空(缺少值),则需在该列指定NOTNULL约束.
UNIQUE码完整性约束:在表指定的列或组列上不允许两行是具有重复值时,则需在该列或组列上指定UNIQUE码完整性约束.
在UNIQUE码约束定义中的列或组列称为唯一码(uniquekey).
所有唯一完整性约束是用索引方法实施.
PRIMARYKEY完整性约束:在数据库中每一个表可有一个PRIMARYKEY约束.
包含在PRIMARYKEY完整性约束的列或组列称为主码,每个表可有一个主码.
Oracle使用索引实施PRIMARYKEY约束.
引用完整性和外来码完整性约束:在关系数据库中的表可通过公共列相关联,该规则第9章数据库的安全性、完整性、并发控制和恢复351控制必须维护的列之间的关系.
包含在引用完整性约束定义的列或组列称为外来码.
由外来码所引用的表中的唯一码或主码,称为引用码.
包含有外来码的表称为子表或从属表.
由子表的外来码所引用的表称为双亲表或引用表.
如果对表的每一行,其外来码的值必须与主码中的一值相匹配,则需指定引用完整性约束.
CHECK完整性约束:表的每行对指定的条件必须是TRUE或未知,则需在一列或列组上指定CHECK完整性约束.
如果在发出一个DML语句时,CHECK约束的条件结算得FALSE时,该语句被回滚.
9.
2.
2数据库触发器Oracle允许定义过程,当对相关的表作INSERT、UPDATE或DELETE语句时,这些过程被隐式地执行.
这些过程称为数据库触发器.
触发器类似于存储的过程,可包含SQL语句和PL/SQL语句,可调用其他的存储过程.
过程与触发器差别在于调用方法:过程由用户或应用显式地执行;而触发器是在一激发语句(INSERT、UPDATE或DELETE)发出时由Oracle隐式地触发.
一个数据库应用可隐式地触发存储在数据库中多个触发器的例子,如图9-3所示.
图9-3触发器在许多情况中触发器补充Oracle的标准功能,提供高度专用的数据库管理系统.
一般触发器用于:(1)自动地生成导出列值;(2)防止无效事务;(3)实施复杂的安全审核;(4)在分布式数据库中实施节点的引用完整性;(5)实施复杂的事务规则;(6)提供透明的事件记录;(7)提供高级的事件记录;(8)维护同步的表副本;(9)收集表存取的统计信息.
注意:在Oracle环境中利用Oracle工具SQL*Forms也可定义、存储和执行触发器,它作为由SQL*Forms所开发的应用的一部分,它与在表上定义的数据库触发器有差别.
352Oracle8i数据库开发与专业应用数据库触发器在表上定义,存储在相关的数据库中,在对该表发出INSERT、UPDATE或DELETE语句时将引起数据库触发器的执行,不管是哪些用户或应用发出这些语句.
而SQL*Forms的触发器是SQL*Forms应用的组成部分,仅当在指定SQL*Forms应用中执行指定触发点时才激活该触发器.
一个触发器由三部分组成:触发事件或语句、触发限制和触发器动作.
触发事件或语句是指引起触发器的SQL语句,可为对一指定表的INSERT、UPDATE或DELETE语句.
触发限制指定一个布尔表达式,当触发器激发时,该布尔表达式必须为真(TRUE).
触发器动作为过程,是PL/SQL块,当触发语句发出、触发限制计算为TRUE时,该过程被执行.
9.
3并发控制数据库是一个共享资源,可为多个应用程序所共享.
这些程序可串行运行,但在许多情况下,由于应用程序涉及的数据量可能很大,常常会涉及输入/输出的交换.
为了有效地利用数据库资源,可能多个程序或一个程序的多个进程并行地运行,这就是数据库的并行操作.
在多用户数据库环境中,多个用户程序可并行地存取数据库,如果不对并发操作进行控制,会存取不正确的数据,或破坏数据库数据的一致性.
例如,在飞机票售票中,有两个订票员(T1,T2)对某航线(A)的机票作事务处理,操作过程见表9-1.
表9-1并行操作实例数据库中的A111100T1READAA:=A–1WRITEAT2READAA:=A–1WRITEAT1工作区中的A110000T2工作区中的A11000首先T1读A,接着T2也读A.
然后T1将其工作区中的A减1,T2也采取同样的工作,它们都得0值,最后分别将0值写回到数据库.
在这过程中没有任何非法操作,但实际上多出售了一张机票.
这种情况称为数据库的不一致性,这种不一致性是由于并行操作而产生的.
所谓不一致,实际上是由于处理程序工作区中的数据与数据库中的数据不一致所造成的.
如果处理程序不对数据库中的数据进行修改,则决不会造成任何不一致.
另一方面,如果没有并行操作发生,则这种临时的不一致也不会造成什么问题.
数据不一致问题是由两个因素造成的:一是对数据的修改;二是并行操作的发生.
因此为了保持数据的一致性,必须对并行操作进行控制.
最常用的措施是对数据进行封锁.
9.
3.
1数据库不一致的类型在多用户数据库中有下列数据一致性的问题:(1)不一致性.
在一事务期间,其他提交的或未提交的事务的修改是显然的,以至由查询所返回的数据集不与任何点相一致.
(2)不可重读性.
在一个事务范围内,两个相同查询将返回不同数据,由于查询注意第9章数据库的安全性、完整性、并发控制和恢复353到其他提交事务的修改而引起.
(3)读脏数据.
如果事务T1将一值(A)修改,然后事务T2读该值,在这之后T1由于某种原因撤消对该值的修改,这样造成T2读取的值是脏的.
(4)丢失更改.
在一事务中修改重写另一事务的修改,如上述飞机票售票的例子.
(5)破坏性的DDL操作.
在一用户修改一表的数据时,另一用户同时更改或删除该表.
9.
3.
2封锁在多用户数据库中一般采用某些数据封锁来解决并发操作中的数据一致性和完整性问题.
封锁(lock)是防止存取同一资源的用户之间破坏性的干扰的机制,该干扰是指不正确地修改数据或不正确地更改数据结构.
在多用户数据库中使用两种封锁:排它(专用)封锁和共享封锁.
排它封锁(exclusivelock)禁止相关资源的共享,如果一事务以排它方式封锁一资源,仅仅该事务可更改该资源,直至释放排它封锁.
共享封锁(sharelock)允许相关资源可以共享,几个用户同时读同一个数据,几个事务可在同一资源上获取共享封锁.
共享封锁比排它封锁具有更高的数据并发性.
在多用户系统中使用封锁后会出现死锁(deadlcok),引起一些事务不能继续工作.
当两个或多个用户彼此等待所封锁数据时可发生死锁.
9.
3.
3Oracle多种一致性模型Oracle利用事务和封锁机制提供数据并发存取和数据完整性.
在一事务内由语句获取的全部封锁在事务期间被保持,防止其他并行事务的破坏性干扰(读脏数据、丢失更改及破坏性DDL操作).
一个事务的SQL语句所作的修改在它提交之后所启动的事务中才是可见的.
在一事务中由语句所获取的全部封锁在该事务提交或回滚时被释放.
Oracle在两个不同级上提供读一致性:语句级读一致性和事务级读一致性.
Oracle总是实施语句级读一致性(statement_levelconsistency),保证单个查询所返回的数据与该查询开始时刻相一致.
所以一个查询从不会看到在查询进入执行过程中提交的其他事务所作的任何修改.
为了实现语句级读一致性,在查询进入执行阶段时Oracle将注视当前SCN(系统修改号systemchangenumber).
在查询执行时,直到注视SCN的时候为止所提交的数据是有效的,而在语句执行开始之后其他事务所提交的任何修改,查询将是看不到的.
Oracle允许选择实施事务级读一致性(transaction_levelreadconsistency),它保证在同一事务内所有查询的数据与一个时间点相一致.
所以事务级读一致性可以重复读.
Oracle可使用不同方法提供事务级读一致性:(1)只读事务.
该事务只能包含查询,不能包含其他任何DML语句.
为了在只读事务中提供重复读,Oracle注视事务起始点,在该事务期间,只有在该事务起始之前提交的数据才是可用的.
(2)排它的表封锁和行封锁.
如果一事务包含有DML语句并需要重复读,那么该事务对要重复读的表可显式地获取共享封锁或行的排它封锁.
利用这种方法提供事务级读一致性,会降低数据并发存取的程度.
9.
3.
4封锁机制Oracle自动地使用不同封锁机制来控制数据的并行存取,防止用户之间的破坏干扰.
354Oracle8i数据库开发与专业应用Oracle为一事务自动地封锁一资源以防止其他事务对同一资源的排它封锁.
在某种事件出现或事务不再需要该资源时封锁自动地释放.
Oracle自动获取不同类型的封锁取决于封锁的资源及所执行操作.
Oracle将封锁分为下列几类:数据封锁(DML封锁)、字典封锁(DDL封锁)、内部封锁、分布式封锁和并行缓冲管理封锁.
1.
数据封锁数据封锁保护表数据,在多个用户并行存取数据时保证数据的完整性.
数据封锁防止相冲突的DML和DDL操作的破坏性干扰.
DML操作可在两个级获取数据封锁:指定行封锁和整个表封锁.
如果一事务获取行封锁,行封锁总是排它封锁,该事务还获取对相应表的表封锁,在防止冲突的DDL操作时也需表封锁.
当行要被修改时,事务在该行获取排它数据封锁.
表封锁可以有下列方式:行共享(RS)、行排它(RX)、共享封锁(S)、共享排它(SRX)和排它封锁(X).
(1)行共享表封锁(RS):该封锁表明该事务对已封锁行的表的封锁,并试图修改它们.
该封锁在作下列语句时自动获取:SELECT.
.
.
FROM表名.
.
.
FORUPDATEOF.
.
.
;LOCKTABLE表名INROWSHAREMODE;当一事务在一表持有行共享表封锁时,允许其他事务可并行查询、插入、修改、删除或在该表上进行行封锁,允许其他事务可同时对该表获取行共享、行排它、共享或共享行排它表封锁,但禁止其他事务以排它方式存取该表.
(2)行排它表封锁(RX):该封锁表明该事务保持该封锁,该事务已对表的行作过一次或多次修改.
该封锁在作下列语句时自动获取:INSERTINTO表名.
.
.
;UPDATE表名.
.
.
;DELETEFROM表名.
.
.
;LOCKTABLE表名INROWEXCLUSIVEMODE;当一事务在一表持有行排它表封锁时,允许其他事务并行查询、插入、修改、删除或封锁同一表中的行.
允许多个事务在同一表上获得行排它和行共享表封锁,但禁止其他事务使用下列语句进行并发封锁:LOCKTABLE表名INSHAREMODE;LOCKTABLE表名INSHAREEXCLUSIVEMODE;LOCKTABLE表名INEXCLUSIVEMODE;(3)共享表封锁(S):在下列语句中指定的表上自动获取共享封锁.
LOCKTABLE表名INSHAREMODE;当一事务在一表上持有共享表封锁时,则允许其他事务在该表可做查询、用SELECT.
.
.
FORUPDATE封锁指定行和执行LOCKTABLE.
.
.
INSHAREMODE语句,但不允许作修改.
允许多个事务在同一表上可并发地持有共享表封锁.
如果在一表上只有一事务持有共享表封锁,该事务可修改表.
共享表封锁可防止其他事务修改同一表.
当在一表上有多个事务持有共享封锁,则事务在该表不能插入、修改或删除表中的行.
如果要执行这些操作,封锁要改成SHAREROWEXCLUSEVE封锁.
如果一事务在一表上持有共享封锁,将禁止其他事务执行下列语句:第9章数据库的安全性、完整性、并发控制和恢复355LOCKTABLE表名INSHAREROWEXCLUSIVEMODE;LOCKTABLE表名INEXCLUSIVEMODE;LOCKTABLE表名INROWEXCLUSIVEMODE;(4)共享行排它表封锁(SRX):它比共享表封锁具有更多的限制,在下列语句中指定的表获取共享排它封锁:LOCKTABLE表名INSHAREROWEXCLUSIVEMODE;如果一事务在一表上持有共享行排它封锁,则只允许其他事务作查询或用SELECT.
.
.
FORUPDATE封锁指定行,但不允许修改表.
一事务在一表上持有共享行排它封锁可防止其他事务获取同样封锁和修改表,也禁止其他事务获取共享封锁、行共享排它封锁和排它表封锁,即其他事务不能执行下列语句:LOCKTABLE表名INSHAREMODE;LOCKTABLE表名INSHAREROWEXCLUSIVEMODE;LOCKTABLE表名INROWEXCLUSIVEMODE;LOCKTABLE表名INEXCLUSIVEMODE;(5)排它表封锁(X):该封锁是表封锁中最严格的方式,允许持有封锁的事务对该表作写存取.
在下列语句中指定的表获取排它封锁:LOCKTABLE表名INEXCLUSIVEMODE;当一事务在一表上获得排它封锁,仅允许其他事务在该表上查询,但禁止在该表执行任何的DML语句,即不能插入、修改和删除该表中的行、封锁该表中的行或以任何方式封锁表.
2.
字典封锁DDL封锁保护模式对象(如表)的定义,DDL操作将影响对象,一个DDL语句隐式地提交一个事务.
当任何DDL事务需要时由Oracle自动获取字典封锁,用户不能显式地请求DDL封锁.
在DDL操作期间,被修改或引用的模式对象被封锁.
3.
内部封锁内部封锁保护内部数据库和内存结构,这些结构对用户是不可见的.
9.
3.
5手工的数据封锁在所有情况下,Oracle自动地执行封锁,确保数据并发存取、完整性和语句级读一致性.
然而允许使用选择代替Oracle缺省的封锁机制.
在下列情况下代替缺省封锁是有用的:(1)应用需要事务级读一致性或可重复读.
事务级读一致性可使用显式封锁、只读事务或代替系统的缺省封锁来达到.
(2)应用需要一事务对一资源可排它存取,为了继续它的语句,具有对资源排它存取的事务不必等待其他事务完成.
Oracle自动封锁可在两级被替代:(1)事务级:包含下列SQL语句的事务替代Oracle缺省封锁:LOCKTABLE命令、SELECT.
.
.
FORUPDATE命令、具有READONLY选项的SETTRANSACTION命令.
由这些语句所获得的封锁在事务提交或回滚后释放.
(2)系统级:通过调整初始化参数SERIALIZABLE和ROW_LOCKING,实例可用非缺省封锁启动.
该两参数的缺省值为:356Oracle8i数据库开发与专业应用SERIALIZABLE=FALSEROW_LOCKING=ALWAYS9.
4数据库备份和恢复当我们使用一个数据库时,总希望数据库的内容是可靠的、正确的,但由于计算机系统的故障(硬件故障、软件故障、网络故障、进程故障和系统故障)影响数据库系统的操作,影响数据库中数据的正确性,甚至破坏数据库,使数据库中全部或部分数据丢失.
因此当上述故障发生后,希望能重新建立一个完整的数据库,该处理称为数据库恢复.
恢复子系统是数据库管理系统的一个重要组成部分.
恢复处理随所发生的故障类型和所影响的结构而变化.
9.
4.
1数据库恢复所使用的结构Oracle数据库使用几种结构针对可能的故障来保护数据:数据库备份、日志、回滚段和控制文件.
数据库备份是由构成Oracle数据库的物理文件的操作系统备份所组成.
当介质故障时进行数据库恢复,利用备份文件恢复毁坏的数据文件或控制文件.
日志(redolog),每一个Oracle数据库实例都提供,记录数据库中所作的全部修改.
一个实例的日志至少有两个日志文件(redologfile)组成,当实例故障或介质故障时进行数据库部分恢复.
数据库日志由两部分组成:在线日志(onlineredolog)和归档日志(archiveredolog).
每一个运行的Oracle数据库实例相应地有一个在线日志,它与Oracle后台进程LGWR一起工作,立即记录该实例所作的全部修改.
在线日志由两个或多个预分配的文件组成,以循环方式使用.
归档(离线)日志是可选择的,一个Oracle数据库实例一旦在线日志填满后,可形成在线日志的归档文件.
归档的在线日志文件被唯一标识并合成归档日志.
回滚段(rollbacksegment)用于存储正在进行的事务(为未提交的事务)所修改值的老值,该信息在数据库恢复过程中用于撤消任何非提交的修改.
控制文件一般用于存储数据库的物理结构的状态.
控制文件中某些状态信息在实例恢复和介质恢复之间用于引导Oracle.
9.
4.
2在线日志一个Oracle数据库的每一实例都有一个相关的在线日志.
一个在线日志由多个在线日志文件组成,在线日志文件(onlineredologfile)填入日志项(redoentry),日志项记录的数据用于重构对数据库所作的全部修改.
后台进程LGWR以循环方式写入在线日志文件.
当当前的在线日志文件写满后,LGWR写入到下一可用在线日志文件;当最后一个可用的在线日志文件填满后,LGWR回到第一个在线日志文件.
填满的在线日志文件对LGWR可否重新使用决定于归档是否实施.
如果归档不实施,一个已填满的在线日志文件当包含该在线日志文件的检查点(checkpoint)已完成时即可使用.
如果归档实施,一个已填满的在线日志第9章数据库的安全性、完整性、并发控制和恢复357文件当包含该在线日志文件的检查点完成,该文件已被归档后即可使用.
在任何时候,仅有一个在线日志文件被写入存储日志项(由日志缓冲区写入),它被称为活动的(active)或当前在线日志文件,其他的在线日志文件为不活动的在线日志文件.
Oracle结束写入一在线日志文件并开始到另一个在线日志文件的点称为日志开关(logswitch).
日志开关总是在当前在线日志文件完全填满,必须继续写入到下一个在线日志文件时出现,也可由DBA强制日志开关.
每一日志开关出现时,每一在线日志文件赋给一个新的日志序列号.
如果在线日志被归档,在归档日志文件中包含有它的日志序列号.
Oracle后台进程DBWR(数据库写)将SGA中所有被修改的数据库缓冲区(包含提交的和未提交的)写入到数据文件,这样的事件称为出现一个检查点(checkpoint).
检查点的作用如下:(1)检查点确保将内存中经常改变的数据段块每隔一定时间写入到数据文件.
由于DBWR使用最近最少算法,经常修改的数据段块从不会作为最近最少使用块,如果检查点不出现,它从不会写入磁盘.
(2)由于直至检查点时所有的数据库修改已记录到数据文件,先于检查点的日志项在实例恢复时不再需要应用于数据文件,所以检查点可加快实例恢复.
虽然检查点有一些开销,但Oracle既不停止活动又不影响当前事务.
由于DBWR不断地将数据库缓冲区写入到磁盘,所以一个检查点一次不必写许多数据块.
一个检查点保证自前一个检查点以来的全部修改数据块写入到磁盘.
检查点不管填满的在线日志文件是否正在归档,它总是出现.
如果不实施归档,检查点所影响的一个在线日志文件要被LGWR重用之前,该检查点必须完成.
如果实施归档,在LGWR重用在线日志文件之前,检查点必须完成并且所填满的在线日志文件必须被归档.
检查点可对数据库全部数据文件出现(称为数据库检查点),也可对指定的数据文件出现.
下面说明一下什么时候出现检查点及出现什么情况:(1)在每一个日志开关处自动出现一数据库检查点.
如果前一个数据库检查点正在处理,由日志开关实施的检查点优于当前检查点.
(2)初始化参数LOG_CHECKPOINT_INTERVAL设置所实施的数据库检查点,当预定的日志块(redologblock)数被填满后(自最后一个数据库检查点以来),实施一数据库检查点.
另一个参数LOG_CHECKPOINT_TIMEOUT可设置自上一个数据库检查点开始之后指定秒数后实施一数据库检查点.
这种选择对使用非常大的日志文件时有用,它在日志开关之间增加检查点.
由初始化参数所启动的数据库检查点只有在前一个检查点完成后才能启动.
(3)当一在线表空间开始备份时,仅对构成该空间的数据文件实施一检查点,该检查点压倒仍在进行中的任何检查点.
(4)当DBA使一表空间离线时,仅对构成该表空间的在线文件实施一检查点.
(5)当DBA以正常或立即方式关闭一实例时,Oracle在实例关闭之前实施一数据库检查点,该检查点压倒任何运行检查点.
(6)DBA要求实施一数据库检查点,该检查点压倒任何运行检查点.
检查点的机制:当检查点出现时,检查点后台进程(CKPT)记住写入在线日志文件的下一日志行的位置,并通知数据库写后台进程(DBWR)将SGA中修改的数据块缓冲区写入到磁盘上的数据文件.
然后由CKPT修改全部控制文件和数据文件的标头,反映该最后检查点.
如果检查点不发生,当DBWR需要时仅将最近最少使用的数据库缓冲区写入磁盘,358Oracle8i数据库开发与专业应用为新数据准备缓冲区.
镜像在线日志文件:为了安全,Oracle提供的镜像将实例的在线日志文件镜像到它的在线日志文件功能.
当具有镜像在线日志文件时,LGWR同时将同一日志信息写入到多个同样的在线日志文件.
日志文件分成组(group),每个组中的日志文件称为成员(member),每个组中的全部成员同时活动,由LGWR赋给相同的日志序列号.
如果使用镜像在线日志,可建立在线日志文件组,在组中的每一成员要求是同一大小.
镜像在线日志文件实例如图9-4所示.
图9-4镜像在线日志文件实例镜像在线日志的机制:LGWR总是寻找组的全部成员,对一组的全部成员并行地写,然后转换到下一组的全部成员,再并行地写.
每个数据库实例有自己的在线日志组,这些在线日志组可以是镜像的或不是镜像的,称为实例的在线日志线索(threadofonlineredo).
在典型配置中,一个数据库实例存取一个Oracle数据库,于是仅存在一个线索.
然而在运行Oracle并行服务器中,两个或多个实例并行地存取单个数据库,在这种情况下,每个实例都有自己的线索.
9.
4.
3归档日志Oracle要将填满的在线日志文件组归档时,则要建立归档日志(archiveredolog),或称离线日志(offlineredolog).
其对数据库备份和恢复有下列用处:(1)数据库备份以及在线和归档日志文件,在操作系统或磁盘故障中可保证全部提交的事务可被恢复.
(2)在数据库打开时和正常系统使用下,如果归档日志是永久保持,在线备份可以进行和使用.
如果用户数据库要求在任何磁盘故障的事件中不丢失任何数据,那么归档日志必须要存在.
归档已填满的在线日志文件可能需要DBA执行额外的管理操作.
归档机制:决定于归档设置,归档已填满的在线日志组的机制可由Oracle后台进程ARCH自动归档或由用户进程发出语句手工地归档.
当日志组变为不活动、日志开关指向下一组已完成时,ARCH可归档一组,可存取该组的任何或全部成员,完成归档组.
在线日志文件归档之后才可为LGWR重用.
当使用归档时,必须指定归档目标指向一存储设备,第9章数据库的安全性、完整性、并发控制和恢复359它不同于具有数据文件、在线日志文件和控制文件的设备,理想的是将归档日志文件永久地移到离线存储设备,如磁带.
数据库可运行在两种不同方式下:NOARCHIVELOG方式或ARCHIVELOG方式.
数据库在NOARCHIVELOG方式下使用时,不能进行在线日志的归档.
在该数据库控制文件指明填满的组不需要归档,所以当填满的日志文件组变为不活动、日志开关的检查点完成时,该组即可被LGWR重用.
在该方式下仅能保护数据库实例故障,不能保护介质(磁盘)故障.
利用存储在在线日志中的信息,可实现实例故障恢复.
如果数据库在ARCHIVELOG方式下运行,可实施在线日志的归档.
在控制文件中指明填满的日志文件组在归档之前不能重用.
一旦日志文件组变为不活动,执行归档的进程立即可使用该组.
在实例启动时,通过参数LOG_ARCHIBVE_START设置,可启动ARCH进程,否则ARCH进程在实例启动时不能被启动.
然而DBA在任何时候都可交互地启动或停止自动归档.
一旦在线日志文件组变为不活动时,ARCH进程自动对它归档.
如果数据库在ARCHIVELOG方式下运行,DBA可手工地归档填满的不活动的日志文件组,不管自动归档是可以还是不可以.
9.
4.
4数据库备份不管将Oracle数据库设成什么样的备份或恢复模式,数据库数据文件、日志文件和控制文件的操作系统备份是绝对需要的,它是保护介质故障的策略部分.
操作系统备份分为完全备份和部分备份.
1.
完全备份一个完全备份(fullbackup)将构成Oracle数据库的全部数据文件、在线日志文件和控制文件的一个操作系统备份.
一个完全备份在数据库正常关闭之后进行,不能在实例故障后进行.
此时,所有构成数据库的全部文件是关闭的,并与当前点相一致.
在数据库打开时不能进行完全备份.
由完全备份得到的数据文件在任何类型的介质恢复模式中都是有用的.
如:(1)如果数据库是在NOARCHIVELOG方式下运行,一磁盘故障损坏了构成数据库的某些全部文件,可使用最近的完全后备来恢复数据库原状.
由于归档文件不能用于恢复数据库到当前点,因此自完全备份以来执行的数据库工作必须重新执行.
(2)如果数据库是在ARCHIVELOG方式下运行,一磁盘故障将构成数据库的一些或全部文件破坏,由最近完全备份之后所收集的数据文件可用于数据库部分恢复,在数据库恢复之后利用归档日志文件和当前在线日志将数据文件恢复到当前点.
2.
部分备份部分备份(partialbackup)为除完全备份外的任何操作系统备份,可在数据库打开或关闭下进行.
如:单个表空间中全部数据文件备份、单个数据文件备份和控制文件备份.
部分备份仅对在ARCHIVELOG方式下运行数据库有用,因为存在的归档日志、数据文件可由部分备份恢复.
在恢复过程中与数据库其他部分一致.
9.
4.
5数据库恢复在每一个数据库系统中,系统故障的可能性总是存在.
如果发生系统故障,应尽快地360Oracle8i数据库开发与专业应用恢复数据库,使对用户不利的影响减到最小.
下面讨论实例故障恢复和介质故障恢复.
1.
实例故障的恢复当实例被意外地(如掉电、后台进程故障等)或预料地(发出SHUTDOWNABORT语句)中止时出现实例故障,此时需要实例恢复.
实例恢复将数据库恢复到故障之前的事务一致状态.
如果在在线备份发现实例故障,则需要介质恢复.
在其他情况Oracle在下次数据库启动时(对新实例装配和打开),自动地执行实例恢复.
如果需要,从装配状态变为打开状态,自动地激发实例恢复,有下列处理步骤:(1)为了恢复数据文件中没有记录的数据,进行向前滚(rollingforward).
该数据记录在在线日志,包括对回滚段的内容恢复.
(2)回滚未提交的事务,按步骤(1)重新生成回滚段所指定的操作.
(3)释放在故障时正在处理事务所持有的资源.
(4)解决在故障时两个阶段提交的任何悬而未决的分布事务.
2.
介质故障的恢复介质故障是当一个文件、一个文件的部分或以磁盘不能读或写时出现的故障.
介质故障的恢复有两种形式,取决于数据库运行的归档方式.
(1)如果数据库是可运行的,以致它的在线日志仅可重用但不能归档,此时介质恢复为使用最新的完全后备的简单恢复.
在完全后备执行的工作必须手工地重做.
(2)如果数据库可运行,其在线日志是被归档的,该介质故障的恢复是一个实际恢复状态过程,重构受损的数据库恢复到介质故障前的一个指定事物一致状态.
不管哪种形式,介质故障的恢复总是将整个数据库恢复到故障之前的一个事物一致状态,如果数据库是在ARCHIVELOG方式下运行,可有不同类型的介质恢复:完全介质恢复和不完全介质恢复.
完全介质恢复可恢复全部丢失的修改,即没有工作会丢失.
完全介质恢复仅当所有必要日志可用时才能使用.
不同类型的完全介质恢复的使用决定于毁坏文件的数据库的可用性.
例如:(1)关闭数据库的恢复.
当数据库可被装配却是关闭的,完全不能正常使用时,此时可进行全部的或单个毁坏数据文件的完全介质恢复.
(2)打开数据库的离线表示空间的恢复,但数据库是打开的,完全介质恢复可以处理.
未损的数据库空间是在线的,可以使用.
而受损的空间是离线的,其所有数据文件作为恢复的单位.
(3)打开数据库的离线表间的单个数据文件的恢复.
如果数据是打开的,完全介质恢复可以处理.
未损的数据库表空间是在线的,可以使用,而所损的空间是离线的,该表空间指定所损的数据库文件可被恢复.
(4)使用后备地控制文件的完全恢复.
当被控制文件所有拷贝由于磁盘故障而受损时,可进行介质恢复而不是丢失数据.
不完全数据恢复(incompletemediarecovery)是在完全借助恢复不可能或不要求时进行的介质恢复,重构受损的数据库,使其恢复介质故障前或用户出错之前的一个事务一致性状态,不完全介质恢复有不同类型的使用,决定于需要不完全介质恢复的情况,有以下类型:基于撤销、基于时间和基于修改的不完全恢复.
基于撤销恢复:在某种情况,不完全介质恢复必须被控制,DBA可撤销在指定点操作.
第9章数据库的安全性、完整性、并发控制和恢复361基于撤销的恢复是在一个或多个日志组(在先的或归档的)易被介质故障所损坏,不能用于恢复过程时使用,所以介质恢复必须控制,以致在使用最近的、未损的日志组与数据文件中停止恢复操作.
基于时间和基于修改的恢复:如果DBA希望恢复到过去的某个指定点,那么不完全介质恢复是比较理想的.
可在下列情况下使用:(1)当用户意外的删除一表,并注意到错误提交的估计时间,DBA库立即关闭数据库,恢复它到用户错误之前时刻.
(2)由于系统故障,一个在线日志文件忽然不可使用,实例被中止,此时需要介质恢复.
在恢复中可使用当前在线日志文件的未损部分,DBA利用基于时间的恢复,一旦有效的在线日志用于数据库文件后停止恢复过程.
在这两种情况下,不完全介质恢复的终点可由时间点或系统修改号(SCN)来指定.
9.
5小结1.
问:什么是数据库安全性答:数据库的安全性是指保护数据库以防止不合法的使用所造成的数据泄露、更改或破坏.
计算机系统都有这个问题,在数据库系统中大量数据集中存放,为许多用户共享,使安全问题更为突出.
2.
问:在Oracle多用户数据库系统中,安全机制需要做哪些工作答:(1)防止非授权的数据库存储;(2)防止非授权的对模式对象的存取;(3)控制磁盘使用;(4)控制系统资源使用(如CPU时间);(5)审计用户动作.
3.
问:安全管理员(securityadministrator)对用户安全域有什么决策答:(1)是由数据库系统还是由操作系统维护用户授权信息;(2)设置用户的缺省表空间和临时表空间;(3)列出用户可存取的表空间和表空间中可使用空间份额;(4)设置用户资源限制的环境文件,该限制规定了用户可用的系统资源的总量;(5)规定用户具有的特权和角色,可存取相应的对象.
4.
问:由操作系统鉴定用户有什么优点答:由操作系统鉴定用户的优点是:(1)用户可方便地连接到Oracle,不需要指定用户名和口令.
例如:在用户进入SQL*PLUS时,只需进入:.
SQLPLUS/(2)对用户授权的控制集中在操作系统,Oracle不需要存储和管理用户口令.
然而用户名在数据库中仍然要维护.
(3)在数据库中的用户名项和操作系统审计跟踪相对应.
362Oracle8i数据库开发与专业应用5.
问:Oracle利用角色更容易地进行特权管理,有哪些优点答:(1)减少特权管理,不要显式地将同一特权组授权给几个用户,只需将这特权授权给角色,然后将角色授权给每一用户.
(2)动态特权管理,如果一组特权需要改变,只需修改角色的特权,所有授权给该角色的全部用户的安全域将自动反映对角色所作的修改.
(3)特权的选择可用性,授权给用户的角色可选择地使其能(可用)或不能(不可用).
(4)当一用户经用户名执行应用时,该数据库应用可查询字典,将自动地选择使角色能或不能.
(5)专门的应用安全性,角色使能可由口令保护,应用可提供正确的口令使角色使能,达到专用的应用安全性.
因用户不知其口令,不能使角色使能.
6.
问:什么是数据完整性答:数据库数据完整性(dataintegrity)是指数据的正确性和相容性.
DBMS必须提供一种功能来保证数据库的数据完整性,这种功能称为完整性检查.
数据完整性是为了防止数据库存在不符合定义的数据,防止错误信息输入和输出,即数据要遵守由DBA或应用开发者所决定的一组预定义的规则.
7.
问:Oracle应用于关系数据库的表的数据完整性有哪些类型答:(1)在插入或修改表时不允许包含有空值的列,称为非空规则;(2)唯一列值规则,允许插入或修改的表行在该列(或组列)上的值唯一;(3)主码值规则,主码的列值唯一地标识表的每一行;(4)引用完整性规则,同关系模型定义;(5)用户对列定义的规则,为复杂的完整性检查.
8.
问:Oracle的DBA和应用开发者对列的值输入可使用的完整性约束有哪些类型答:(1)NOTNULL约束;(2)UNIQUE码约束;(3)PRIMARYKEY约束;(4)FOREIGNKEY约束(或称引用约束);(5)CHECK约束.
9.
问:什么是数据库触发器答:Oracle允许定义过程了,当对相关的表作INSERT、UPDATE或DELETE语句时,这些过程被隐式地执行.
这些过程称为数据库触发器.
触发器类似于存储的过程,可包含SQL语句和PL/SQL语句,可调用其他的存储过程.
10.
问:过程和触发器有什么区别答:区别在于调用方法:过程由用户或应用显式地执行;而触发器是在一激发语句(INSERT、UPDATE或DELETE)发出时由Oracle隐式地触发.
11.
问:为什么需要并发控制答:数据库是一个共享资源,可为多个应用程序所共享.
这些程序可串行运行,但在许多情况下,由于应用程序涉及的数据量可能很大,常常会涉及输入/输出的交换.
为了有效地利用数据库资源,可能多个程序或一个程序的多个进程并行地运行,这就是数据库的并行操作.
在多用户数据库环境中,多个用户程序可并行地存取数据库,如果不对并发操作进行控制,会存取不正确的数据,或破坏数据库数据的一致性.
第9章数据库的安全性、完整性、并发控制和恢复36312.
问:在多用户数据库中有哪些数据一致性的问题答:(1)不一致性.
在一事务期间,其他提交的或未提交的事务的修改是显然的,由查询所返回的数据集不与任何点相一致.
(2)不可重读性.
在一个事务范围内,两个相同查询将返回不同数据,由于查询注意到其他提交事务的修改而引起.
(3)读脏数据.
13.
问:什么是封锁答:在多用户数据库中一般采用某些数据封锁来解决并发操作中的数据一致性和完整性问题.
封锁(lock)是防止存取同一资源的用户之间破坏性的干扰的机制,该干扰是指不正确的修改数据或不正确地更改数据结构.
14.
问:为什么要进行数据库的备份和恢复答:当我们使用一个数据库时,总希望数据库的内容是可靠的、正确的,但由于计算机系统的故障(硬件故障、软件故障、网络故障、进程故障和系统故障)影响数据库系统的操作,影响数据库中数据的正确性,甚至破坏数据库,使数据库中全部或部分数据丢失.
因此当上述故障发生后,希望能重新建立一个完整的数据库,该处理称为数据库恢复.
恢复子系统是数据库管理系统的一个重要组成部分.
恢复处理随所发生的故障类型和所影响的结构而变化.
15.
什么是完全备份,什么是部分备份答:一个完全备份(fullbackup)将构成Oracle数据库的全部数据文件、在线日志文件和控制文件的一个操作系统备份.
部分备份(partialbackup)为除完全备份外的任何操作系统备份,可在数据库打开或关闭下进行.

SugarHosts糖果主机六折 云服务器五折

也有在上个月介绍到糖果主机商12周年的促销活动,我有看到不少的朋友还是选择他们家的香港虚拟主机和美国虚拟主机比较多,同时有一个网友有联系到推荐入门的个人网站主机,最后建议他选择糖果主机的迷你主机方案,适合单个站点的。这次商家又推出所谓的秋季活动促销,这里一并整理看看这个服务商在秋季活动中有哪些值得选择的主机方案,比如虚拟主机最低可以享受六折,云服务器可以享受五折优惠。 官网地址:糖果主机秋季活动促...

wordpress公司网站模板 wordpress简洁高级通用公司主题

wordpress公司网站模板,wordpresss简洁风格的高级通用自适应网站效果,完美自适应支持多终端移动屏幕设备功能,高级可视化后台自定义管理模块+规范高效的搜索优化。wordpress公司网站模板采用标准的HTML5+CSS3语言开发,兼容当下的各种主流浏览器: IE 6+(以及类似360、遨游等基于IE内核的)、Firefox、Google Chrome、Safari、Opera等;同时...

华纳云不限流量¥324/年,香港双向CN2(GIA)云服务器/1核1G/50G存储/2Mbps

华纳云(HNCloud Limited)是一家专业的全球数据中心基础服务提供商,总部在香港,隶属于香港联合通讯国际有限公司,拥有香港政府颁发的商业登记证明,保证用户的安全性和合规性。 华纳云是APNIC 和 ARIN 会员单位。主要提供香港和美国机房的VPS云服务器和独立服务器。商家支持支付宝、网银、Paypal付款。华纳云主要面向国内用户群,所以线路质量还是不错的,客户使用体验总体反响还是比较好...

oracle数据库学习为你推荐
外挂购买自动充值软件站酷zcool北京站酷网络科技有限公司怎么样?sonicchat苹果手机微信显示WeChataccess数据库ACCESS数据库和SQL有什么区别?钟神发战旗TV ID:新年快乐丶未央不见是哪个主播m.yushuwu.org花样滑冰名将YU NA KIM的资料谁有?www.175qq.com求带名字的情侣网名!弗雷德疯皮囊第四季EFFY为什么突然不对劲了。红玉头冠和田红玉皮越厚越好还是皮越薄越显示红玉,更加好,开窗后见红肉了,是不是代表红玉了,浪子成神介绍一些主角无敌的现代都市小说,修真.异能都可以的!
vps服务器租用 过期备案域名查询 如何注销域名备案 hawkhost优惠码 512m realvnc 美国免费空间 33456 卡巴斯基是免费的吗 什么是web服务器 万网空间 免费个人网页 测试网速命令 google搜索打不开 美国代理服务器 wannacry勒索病毒 香港打折信息 饭桶 装修瓦工培训 台式机主机 更多