从Oracle数据库体系结构中的各个组件的存在的必要性角度来思考,尽量结合实际应用场景,加深对各个组件的理解。
Oracle数据库服务是典型的C/S服务模式。
用户要连接到Oracle数据库库,需要安装Oracle客户端软件,并配置连接信息,之后连接到数据库;对于Java应用,可通过JDBC驱动,并设置连接字符串,通过程序连接到数据库。
通过Oracle Client软件连接数据库时,客户端需要知道数据库的主机名(或IP),端口,协议,服务名(或SID)信息,客户端可以采用Local Naming的或Easy Connect等命名方式来设定这些参数信息。
对于Local Naming方式,需要在客户端tnsnames.ora文件中定义tnsname信息;而通过Easy Connect方式时,可直接在连接字符串中体现这些信息,在这个字符串中并未体现连接协议类型,因为Easy Connect方式只支持TCP协议。
服务端侦听器进程收到客户端的连接请求后,如果服务模式是Dedicated,则侦听器会启动一个Server Process进程来处理和响应用户的请求,Server Process是连接客户端与Oracle数据的纽带。
而如果服务模式是Shared,则侦听器会交由Dispatcher进程来接收用户的请求;之后,dispatcher进程将请求交由shared server process来处理,并将shared server process的处理结果返回给用户;(这里还有请求队列和响应队列来辅助该过程)
这里Shared Server模式的适用场景是什么呢?
当一些联机应用中并发用户数量很大,比如达到了1000,但大多数用户均处于空闲状态的,如果采用Dedicated模式,有如下缺点:
1)需要为每个用户分配一个Service Process以及PGA内存,那么会耗费很大的PGA内存;
2)此外,由于操作系统的CPU时间片算法,大量的Service Process做上下文切换也是不小的开销;
而如果采用Shared Server模式,通过dispatcher将用户的请求进行排队,并交由预先设定一定数量的shared Server Process来处理,这样就缓解了前面出现的问题。但这样做的缺点是单个会话的响应不如Dedicated模式快。
此外,11g中Oracle还提供了DRCP方式来支持大量用户的接入。
对于J2EE应用,在并发用户量很大的情况下,一般会使用中间件(如WAS,WebLogic等)提供的数据库连接池来解决该问题。
Oracle数据库指的是数据库的物理结构,包括控制文件、数据文件、重做日志文件,此外还有参数文件、口令文件、归档日志文件。
数据库的启动以下4种状态的跳转,
1)stopped表明数据库属于停止状态;
2)nomount表明数据库实例已启动;
3)mount表明数据库控制文件已加载;
4)open表示数据库已打开;
数据从停止状态启动到nomount状态,需要读取参数文件,从而启动实例。
实际测试时,我们只需要提供DB_NAME即可启动实例,说明在不设置参数时,Oracle启用了默认参数值。而如果我们调整了参数的默认值,在数据启动时的alert_.log的日志中,会展示出这些非默认参数值。
参数文件可分为pfile和spfile两种类型。
其中pfile的内容是文本格式,但是用pfile启动实例后,pfile中的参数不可以被修改,这是一个很大的缺点。而spfile的内容是二进制格式,在实例启动后,可以支持参数的动态修改,但是不容易直接读取,需通过其他方式读取。
参数文件放在$ORACLE_HOME/dbs目录下,如果有多个参数文件,Oracle的查找顺序依次是:
spfile.ora
spfile.ora
init.ora
init.ora
按照参数是否可以被修改,以及修改的范围,参数又可以有如下一些类型:
1) 值固定的参数,不可修改;
2) 实例中不可以修改,但可以在spfile中修改的参数,重启方可生效,可通过alter system set … scope=spfile;
3) 可以在实例中生效的参数:
a) 可以在会话级别生效,可通过alter session进行修改;
b) 可以在实例和spfile中同时生效,可通过alter system [deferred] scope=memory或scope=both进行修改的参数;
数据库从nomount阶段到mount阶段,需根据control_files参数提供的路径读取控制文件。控制文件中包含了一下一些内容:
1)包括数据库的基本信息
例如:每个数据库会生成唯一的ID来标识该数据库;maxlogfiles, maxlogmemebers等参数用于预设值;
2)数据库的结构信息,包括数据文件、日志文件、在线日志文件的路径;
数据库在启动时会校验各个数据文件是否一致,如果一致,则表示这些数据文件可以一致性打开;
如果不一致,则需根据控制文件中记录的信息,对数据文件进行恢复。
3)包含RMAN备份的元数据(当RMAN不使用Catalog方式时,会使用controlfile来
保存);
4)包含最后一次检查点的信息;
记录该信息,当需要实例恢复时,其起点即为该检查点;
5)包括归档日志的信息;
记录默认查找的归档信息;
6)包含在线日志文件的日志序号;
通过此与日志文件保持同步?还是有其他的SCN信息。
控制文件很重要,因此RMAN有控制文件自动备份的选项,当开启该选项时,当备份数据,或是数据库结构改变时,RMAN均会自动备份控制文件和spfile;此外,当system表空间备份时,无论是否开启该选项,RMAN均会自动备份。
数据库从mount阶段到open阶段,需要根据控制文件中提供的数据文件、日志文件等路径,进行校验,通过后打开数据库。
数据库open时,会校验数据文件头上的SCN信息,确保各个数据文件是一致的,否则需要根据控制文件中记录的日志信息来进行数据文件的恢复;
数据库还会校验控制文件与数据文件版本是否一致,如果不一致,还需要对数据文件进行media recovery,方可打开。例如:采用备份的控制文件打开数据库时,会发现file1较新,不能打开,可通过recover database做恢复后打开。
表空间与数据文件是一对多的关系,数据文件按照所属的表空间,有如下一些类别:
1)system表空间数据文件,存放数据字典、数据库内部使用数据信息;
2)sysaux表空间数据文件,存放收集的快照信息,AWR资料库等;
3)undo表空间数据文件,使用自动undo管理,存放undo数据,用于提供一致性读,提供闪回特性;
4)临时表空间,主要用于磁盘排序;
5)用户表空间,用于存放用户数据,供应用使用;
当用户执行一条修改数据的语句时,从磁盘读取该条数据到缓存(或在缓存中已存在),Oracle会构造出undo缓存,存放被修改数据的原值,之后修改缓存中的数据,并将对这些块的修改写入redo log buffer,为了保证可恢复性,redo log buffer需要优先写入日志文件。
在用户commit时,oracle不强制脏数据块写入磁盘,而是保证将log buffer写入日志文件。一方面强制脏数据块写入,如果该数据块是频繁DML操作的,那么可能会影响数据块的共享,从而增加了磁盘IO;另一方面,日志文件是一种增量顺序的写出,而且redo信息只记录块的变化的内容,所以日志文件是一种批量式的写出。它的效率要高于DBWR离散的写入。
日志文件用于提供数据库的可恢复性。
在日志文件中记录了所有的数据操作,可以看到,当数据库出现故障时,不论是实例故障或是介质故障,均需要通过日志文件来辅助恢复。
在线日志文件至少需要有2组。
一般在一个日志组中添加多个日志成员进行多工,从而保护日志组成员的损坏;此外,考虑将一个日志组的不同成员放在不同的磁盘上,以减少磁盘IO争用。
在线日志组文件是增量写入、顺序写入、并且是循环使用的,历史的日志文件被转入归档方便管理。
通过Oracle的实例,用户可以高效的使用Oracle数据库。
Oracle Instance包括内存结构和后台进程。内存结构通过后台进程与Oracle数据库进行交互。
在RAC模式下,一个Oracle数据库可以对应多个Oracle实例,从而提供了实例的高可用性。
内存结构中,有部分组件的数据是可共享的,例如Buffer Cache,第一个会话查询产生的数据块缓存,可供第二个会话来使用;而有一部分缓存是与用户相关的,例如一个会话查询的排序的结果信息、会话、游标等信息,显然不能与另一个会话共享。因此,Oracle将内存结构分为了2大部分,即SGA和PGA。
10g中,SGA和PGA可分别实现自动管理;11g中可实现内存的自动管理。
其中,10g中SGA中可自动管理的内存组件有Buffer Cache、Shared Pool、Large Pool、Java Pool和Stream Pool。(不包括非标准大小块的Buffer Cache)
SGA_MAX_SIZE参数表示SGA的内存允许调整的最大值;SGA_TARGET表示启动时初始内存值。值得注意的是SGA_TARGET表示的是所有SGA内存组件的大小。
数据库中最重要的是数据,这些数据是存放在各种数据文件中的,而这些文件又是存放在磁盘上的。
当用户第一次发起业务数据的查询操作时,需要读取磁盘的数据,如果这部分数据不保存在缓存中;那么后续该用户或其他用户继续读取同样的数据时,仍需要从磁盘读取该批数据,这样磁盘的IO就会很高。所以有必要将数据在内存中缓存起来,类似于2-8原则,数据库采用LRU算法,将频繁使用的数据缓存在热端,以减少整体的磁盘IO。
我们在创建数据库时,通过DB_BLOCK_SIZE指定了数据库的默认块大小(默认为8K),那么通过DB_CACHE_SIZE、SGA_TARGET参数可调节默认块缓存区的大小。而对于非标准块,我们可以使用DB_nK_CACHE_SIZE(其中n可取值为2,4,8,16,32)参数来指定非标准块缓存的大小。
共享池,它包含Library Cache和Data Dictionary Cache(又称为row cache),分别用来缓存SQL语句的执行计划,以及数据字典信息。
用户提交的SQL语句,在语法校验时需要读取数据字典信息,通过数据字典缓存避免了重复读取system表空间中数据字典表的IO开销;
在解析后会生成执行计划,并保存在库缓存中,由于SQL语句的解析是个耗费CPU的过程,所以通过缓存该SQL的执行计划,在后续提交同样的SQL语句时,可以共享该执行计划,避免CPU开销。
如何匹配以前SQL语句呢,SQL语句会按照一定的规则生成Hash值,通过匹配前面SQL的Hash值来重用它的执行计划。那么根据应用要求,希望尽量复用原来的SQL的执行计划,那么我们需要按照绑定变量的方式来编写SQL语句。
一般来讲,对于CPU敏感的OLTP应用,要考虑使用绑定变量,提高SQL语句软解析;而对于IO敏感的OLAP应用,不使用绑定变量,以期获取更优的执行计划,从而提高SQL语句的执行效率。
当数据库中存在大量DML操作时,可能会生成大量Redo Log;如果不使用缓存,而是直接更新磁盘上的日志文件,必然会存在较长的IO等待以及文件锁定等待;而如果通过redo log buffer,一条DML操作,写入到缓存中后就立即返回,那么会极大的客户端的提高响应速度。
此外,LGWR通过相应的触发机制,近似于实时的速度不断在将redo log buffer中的数据写入redo log file。
当然,如果用户执行commit操作,需要同步等待log buffer写入log file。
Redo log buffer的块大写一般为操作系统的块大小,以防止出现分裂块。
Log buffer的设置也不宜过大,因为有可能commit时写入缓存数据量较大;
待续。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/9430546/viewspace-1210611/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/9430546/viewspace-1210611/