Oracle是目前应用最广泛的数据库系统。一个完整的数据库系统包括系统硬件、操作系统、网络层、DBMS(数据库管理系统)、应用程序与数据,各部分之间是互相依赖的,对每个部分都必须进行合理的配置、设计和优化才能实现高性能的数据库系统。本文讨论笔者使用Oracle开发局域网中、小型数据库应用中,系统硬件的选择与使用、应用数据库系统设计与开发方面的一些心得和建议。应用数据库系统包含应用数据库和应用两方面的内容,应用数据库就是生产数据库,与系统数据库相对。
系统硬件的选择与使用
与数据库系统密切相关的硬件主要有CPU、内存、集群、存储设备等,这里不对集群进行讨论。
1、CPU
CPU的数目和速度直接影响数据库操作的速度,Oracle数据库提供并行查询选项,允许SQL操作以协同方式在多个CPU上执行,可以很大程度的发挥多CPU的性能。为系统添加CPU前,首先要对应用程序的SQL代码做优化,提高应用程序的效率,质量低劣的应用可能会引起CPU资源的无谓的消耗;其次,要了解操作系统对CPU数目的限制及系统的可扩展性。在系统CPU资源已定的情况下,要对各类应用进行分析,在保证关键应用正常运行的前提下,尽可能将大量占用CPU资源的应用放在系统相对空闲的时候进行。良好的工作调度可以有效减少对CPU的竞争使用,加快系统的响应时间。
2、内存
数据库系统中,应保证有足够大的内存。在UNIX系统中,如果系统的物理内存小于1GB,可将交换区的大小设为内存的4倍,否则,可设为内存的2倍,交换区要放在磁盘速度最快的硬盘上。Oracle 的SGA区大小直接关系到数据库操作的性能,一般来说,SGA区的大小可设为系统可用内存的55%到57%,SGA区过多占用系统内存反而会降低性能。在应用系统运行中,应定期监测系统的内存使用情况,对关键应用进行分析,根据应用适时调整SGA区各部分的大小。Oracle9i可在不重新启动数据库的情况下修改SGA区的参数,实时改变SGA区的大小。
3、存储设备
在网络时代,信息资源的积累和广泛应用对数据存储技术的发展提出了更大的挑战,数据存储模式从传统的总线连接模式进入了网络存储模式。但存储设备依然是硬盘、磁带(带库)、磁盘阵列,在中、小型数据库应用中传统存储模式仍占主导地位。
磁盘I/O是数据库操作的瓶颈之一,磁盘的合理选择和使用在数据库系统中显得尤为重要。在最初做数据库系统规划时,应充分考虑到系统的容量和预期的增长,尽可能为以后的扩展留足空间。在硬盘和磁盘阵列的选择与使用中,应注意以下几点:
?选择支持热插拔功能的硬盘,这样在出现硬盘Oracle 平台应用数据库系统的设计与开发失败时,可以在系统正常运行的情况下更换硬盘;
?不要选择太大的硬盘,切记对Oracle 应用程序,1~4GB大小的硬盘是比较合适的,最好购买大量的中小型硬盘,这样在配置RAID时可提供更大的灵活性;
?如果选用了磁盘阵列,对于Oracle数据库应用,如果经费能够支持,RAID 0+1是最佳的配置方法。在RAID 5中,读操作性能得到了一定的改善,但写性能损失很大,如果某个硬盘失败,硬盘重建的工作量非常大,RAID 5 适用于DSS(决策支持系统)应用,对OLTP(联机事物处理)应用不太合适;
?在实现RAID时,要正确地选择分条的大小,决定分条大小的三个主要因素是:应用程序的特性(DSS、OLTP、批处理)、操作系统与数据库的数据块大小、磁盘阵列中的硬盘数目。数据库的数据块大小应是操作系统数据块大小的整数倍,同样分条大小也必须是操作系统数据块大小的整数倍。如果使用裸设备,分条大小应是操作系统物理数据块的大小。分条可按照水平方向进行,也可按照垂直方向进行。水平分条跨越每个硬盘控制器进行,垂直分条跨越整个硬盘集合进行,分条集合中的成员数应不大于硬盘控制器数。OLTP应用程序,数据访问的数据量不大,一般可选择32KB 或64KB 的分条大小,而DSS应用程序访问的数据量大,可考虑使用64KB、128KB或256KB的分条大小。
应用数据库的设计与开发
Oracle数据库软件安装和配置完成后,就进入了应用数据库的设计阶段,应用数据库设计包括逻辑设计与物理设计。合理的逻辑设计会大大提高数据库的性能,增强数据库的可维护性。在设计中根据应用,抽象出实体关系模型,将实体关系图映射为标准化(数据完整、与应用无关、存储优化)的关系模型(数据库对象),当前有一些辅助工具(Oracle Designer等)来实现实体关系图到SQL代码的映射;数据库的物理设计就是数据库对象的存储设计,即如何为数据库对象分配存储空间。
在进行数据库对象的设计前,数据库的管理和开发人员对应用和应用的数据及其应用关系要有一个详尽的理解,根据应用进行数据库对象的规划和设计,大概包含以下几个方面:
?确定需建立的数据库用户,明确用户的系统权限和表空间限额,为用户设计资源限制profile;
?确定应用数据应分多少个表进行设计,各表分别属于的用户,各用户对各个表的操作权限;
?明确各表的结构,确定表的主键及约束;
?明确哪些表是应用运行的关键表,哪些是事务表;
?分析哪些表是主表,哪些表是从表,确定表和表之间的外键约束,选择合适的表作为表连接的驱动表;
?根据应用,确定在哪些表上对哪些列建立合适的索引;
?根据表和索引的设计,确定要创建的表空间和回滚段,为表空间和回滚段选择合适的磁盘,尽可能创建本地管理的表空间,减少数据库空间管理方面的工作;
?明确需要编写的触发器及过程;
?为数据库对象选择备份和恢复策略。
在数据库设计阶段,有时未必能完全确定合适的数据库对象的特征,应用设计和开发中还可能发现不合适的地方,需要回过头来进行调整和修改。但设计阶段的工作越细致,出现问题的可能性就越小,工作的效率就越高。
创建数据库对象时,要根据数据库对象的特点,结合存储设备的大小、数量及速度等,对数据库对象分类进行存储,最大限度地消除或减少资源竞争。在数据库对象创建时主要应遵循以下原则:
?应用数据应放在单独的表空间,不要将应用数据放在系统表空间,为防止无意的使用系统表空间,将应用用户的系统表空间限额设为0。
?索引和表应放在位于不同硬盘上的不同的表空间,这样会提高数据库操作的速度。
?需要同时被访问的表要分开存放,利于并发访问的实施。
?如果磁盘数量有限,可把不常联合访问的表放在相同的磁盘上。
?预分配的原则。创建数据库对象(表空间、回滚段、表、索引等)时,根据对象的情况设置合适的storage参数非常重要。创建对象设计时,对对象的容量和预期的增长有一个估计,这样才能确定存储参数的大小。一般来说,应预先给表和索引等数据库对象分配足够的空间,数据库段不要太多地做动态扩展,因为会影响数据库性能。一个段(segment)由一个区(extent)构成是最理想的,initial 参数可以稍大一点,如果可能,可设为最大容量的大小,initial必须是db_block_size的整数倍;next参数的设置比较灵活,根据应用进行相应的设置,但也必须是db_block_size的整数倍;为了减少数据库碎片的产生,pctincrease参数应该尽量设为0;更新操作比较少的段,pctfree要设置得小一点,更新操作很多的段要设置得大一些;inittrans和freelists的值要相等,大小与并发事务数相关。
?分而治之的原则。大的数据库表和索引可考虑进行分区存放,不同的分区可位于不同的磁盘上,更好地均衡I/O。Oracle可以只对表的某些分区进行查询,这样会提高查询的速度;可对分区进行数据的删除、装载,还可以移动分区,对表的管理和控制具有更大的灵活性;可以有更多的策略选择,更好地执行备份和恢复操作。注意,对某些分区进行操作后,在Oracle8i下必须重建全局索引。
?大小和增长趋势类似的表最好放在相同的表空间,可以有效控制硬盘碎片的产生,提高空闲块的可重用性。
?相同备份和恢复策略的表最好放在同一个表空间,这样有助于备份和恢复工作的完成。
?对响应时间要求苛刻的应用所访问的对象放在速度快的磁盘上。
数据库应用系统的设计与开发
1、应用设计
不论使用何种工具或语言来开发应用程序,都需要进行应用的全面设计。应用设计包括:
首先,分析应用要完成的功能,确定应用类型,是OLTP(联机事务处理)系统、DSS(决策支持)系统还是批处理系统;
其次,了解应用在何时由谁使用、应用访问的数据、应用程序用到的组件、应用被要求的响应时间等,在设计前,必须对这些问题尽量进行解答,这对应用设计特别是大规模的应用设计非常重要;
第三,根据上面的资料,确定应用的体系结构,是采用client/server两层架构的方式,还是采用browser/server多层架构的方式实现一个开放的分布式应用系统,如何对应用服务器进行选择与配置;
第四,将应用按功能划分为一个或多个应用程序,明确应用程序的具体功能、类型、组成,使用时间及高峰时间、事务的流量、用户组成、访问的数据库对象等,确定应用程序间的关联和互操作特性,对各个应用程序的执行时间合理地进行安排;
第五,对应用程序进行模块化设计,选择实现应用的数据库组件和开发语言及工具。
2、应用开发
在应用开发阶段,根据应用的不同,实现的方法和步骤会有很大的差异。这里只讨论以下在应用开发中需要重点注意的几个问题。
1) 在开发会话关键型应用程序时,尽可能使用Pro*C/C++或OCI。在编写后备实例和数据库失败恢复等需要进行数据库重新连接的代码时,用Pro*C/C++ 或OCI比用PL/SQL要容易实现,在Oracle8/8i中,OCI可以实现透明应用程序失败恢复(TAF)。编写数据库操作繁重的应用程序,使用OCI,OCI程序对数据库的访问是通过调用OCI库函数实现的,能够直接到达系统内核,比Pro*C/C++速度更快。
2) 在开发会话关键型应用程序时,尽量实现失败检查和恢复能力,如指定后备数据库或实例、终止出错客户进程等。
3) 编写代码时,要考虑应用程序的可维护性,尽量将应用程序独立于数据库的变化。可使用视图、相对变量类型定义(%TYPE)、记录型变量定义(%ROWTYPE),采用表驱动的应用程序设计模式。
4) 进行充分的单元测试和模块测试,为应用集成打下坚实的基础。
5) 对关键表操作的应用程序实现要特别当心,必要的话,在应用中对关键表先做备份,应用成功执行后再删除备份表。
6) 编码结束后,应对代码进行优化。前面提到过,代码优化在数据库应用中非常重要,很高比例的性能问题与编码拙劣的应用程序有关。
7) 定期对应用操作的数据库对象增长的情况进行监控,避免因空间不足引起的应用程序的失败。
8) 对应用的数据定时进行整理。有些应用中,存放在数据库表中的数据只要求保存一段时间,就需要定时对数据进行删除。如果手工进行删除操作,工作量很大,可以用Oracle提供的作业来完成, unix系统下可用cron进程来实现。笔者在工作中经常使用cron来做数据的定时删除,根据应用要求,编制Pro*C/C++程序,编写Shell脚本调用应用程序,将Shell脚本提交给cron进程。
注意:在Shell脚本中必须设置相应的Oracle环境变量,如ORACLE_BASE、ORACLE_HOME、NLS_LANG、LD_LIBRARY_PATH、PATH等,用户环境文件中的定义是无效的。
9)对于大量删除操作的应用程序,如果表是分区存放的,可对数据分区执行截断(truncate)操作,截断操作执行速度快并且不会产生碎片,但截断后可能需要进行重建索引的工作。对大量的数据做删除(delete)操作,会引起数据库回滚段的急剧增长,建议根据删除数据量为这类应用创建特殊的专用回滚段,为专用回滚段指定合适的storage参数。平常,专用回滚段可以是离线的(offline),在事物开始前,使专用回滚段在线(online),指定事物使用专用回滚段,事物结束后再使专用回滚段离线,笔者使用的部分代码 (Pro*C/C++) 如下所示。
..
EXEC SQL WHENEVER SQLERROR goto Error;
EXEC SQL CONNECT :uid;
..
EXEC SQL ALTER ROLLBACK SEGMENT RBS_SPEC ONLINE;
EXEC SQL SET TRANSACTION USE ROLLBACK SEGMENT RBS_SPEC;
..
EXEC SQL DELETE FROM .. WHERE ..;
EXEC SQL ALTER ROLLBACK SEGMENT RBS_SPEC OFFLINE;
..
结束语
Oracle数据库是一个功能强大的数据库系统,适用于各种各样的应用系统,系统规模可大可小,应用设计或简单或复杂,因此在使用过程中要根据各自不同的应用进行设置与调整,以上是笔者在使用Oracle进行应用开发过程中一点心得和体会,写出来与大家共勉,谢谢。