Oracle服务器主要由实例、数据库、程序全局区(PGA)和前台进程组成。
实例
实例可以划分为:系统全局区(SGA)和后台进程(PMON、SMON等)两部分,其中,SGA使用操作系统的内存资源,而后台进程需要使用CPU和内存资源。
系统全局区(SGA):
是所有用户进程共享的一块内存区域,也就是说,SGA中的数据资源可以被多个用户进程共同使用。SGA主要由高速数据缓冲区、共享池、重做日志缓存区、Java池和大型池等内存结构组成。SGA随着数据库实例的启动而加载到内存中,当数据库实例关闭时,SGA区域也就消失了。
高速数据缓冲区(Database buffer cache):存放着Oracle系统最近访问过的数据块(数据块在高速缓冲区中也可称为缓存块)。
若无法在高速数据缓冲区中找到所需要的数据,则Oracle首先从数据文件中读取指定的数据块到缓冲区,然后再从缓冲区中奖请求的数据返回给用户。由于高速数据缓冲区被所有用户共享,只要数据文件中的某些数据块被当前用户或其他用户请求过,那么这些数据块就会被装载到高速数据缓冲区中。经常或最近被访问的数据块会被放置到高速数据缓冲区前端,不常被访问的数据块会被放置到高速数据缓冲区的后端,当高速数据缓冲区填满时,会自动挤掉一些不常被访问的数据块。
- 高速数据缓冲区分为以下三个部分:
- 脏数据区:脏数据区中存放着已被修改过的数据,这些数据等待被写入数据文件中。 - 空闲区:空闲区中的数据块不包含任何数据,这些数据块可以被写入数据,Oracle可以从数据文件中读取数据块,并将其放到该区中。 - 保留区:保留区包含那些正在被用户访问的数据块和明确保留以作为将来使用的数据块(即缓存块),这些数据块将被保留在缓冲区中。
- 高速数据缓冲区分为以下三个部分:
重做日志缓冲区(Red log buffer cache):存放对数据库进行修改操作时所产生的日志信息,这些日志信息在写入到重做日志文件之前,首先存放到重做日志缓冲区中,然后,在检查点发生或重做日志缓冲区中的信息量达到一定峰值时,最后由日志写入进程(LGWR)将此缓冲区的内容写入到重做日志文件。
重做日志缓冲区的大小由LOG_BUFFER参数指定,该参数也可以在树立启动后动态修改。相对于高速数据缓冲区而言,重做日志缓冲区的大小对数据库性能的影响较小,通常较大的重做日志缓冲区能减少重做日志文件的对I/O的读取次数,对数据库的整体性能有一定的提高。
共享池(Shared Pool):共享池是SGA保留的内存区域,用于缓存SQL语句、PL/SQL语句、数据字典、资源锁、字符集以及其他控制结构等。共享池包含库高数缓冲区(Library cache)和字典高速缓冲区(Dictionary cache)。
库高速缓冲区是共享池的一部分,主要包括共享SQL区和私有SQL区两个组成部分。每条被缓存的SQL或PL/SQL语句都被分成两个部分,分别被存放在共享SQL区和私有SQL区中。共享SQL区存放SQL或PL/SQL语句的语法分析结果和执行计划,如果以后要再次执行类似的语句,则可以利用共享SQL区已缓存的语法分析结果和执行计划。私有SQL区存放SQL语句中的绑定变量、环境和会话等信息,这些信息属于执行该语句的用户的私有信息,其他用户则无法共享这些信息。
字典高速缓冲区用于存放Oracle系统内部管理所需要的数据字典信息,例如用户名、数据对象和权限等。
大型池(Large pool):大型池在SGA区中不是必需的内存结构,只在某些特殊情况下,实例需要使用大型池来减轻共享池的访问压力,常用的情况有以下几种:
- 当使用恢复管理器进行备份和恢复操作时,大型池将作为I/O缓冲区使用。
- 使用I/O Slave仿真异步I/O功能时,大型池将被当作I/O缓冲区使用。
- 执行具有大量排序操作的SQL语句。
- 当使用并行查询时,大型池作为并行查询进程彼此交换信息的地方。
Java池:用来提供内存空间给Java虚拟机使用,目的是支持在数据库中运行Java程序包,其大小由JAVA_POOL_SIZE参数决定。
流池:Oracle流池用于在数据库与数据库之间进行信息共享。如果没有用到Oracle流,就不需要设置该池。流池的大小由参数STREAMS_POOL_SIZE决定。
程序全局区(PGA):
也称作用户进程全局区,它的内存区在进程私有区而不是共享区中。虽然PGA是一个全局区,可以把代码、全局变量和数据结构都可以存放在其中,但区域内的资源并不像SGA一样被所有的用户进程所共享,而是每个Oracle服务器进程都只拥有属于自己的那部分PGA资源。
各个服务进程的PGA区的总和即为实例的PGA区的大小。通常PGA区由私有SQL区和会话区组成:
- 私有SQL区:用于存储变量以及SQL语句运行时的内存结构信息,当每个用户连接到实例时,都会在实例中创建一个会话。这些会话可能会在SGA区中创建一个共享SQL,但在PGA区中可能会创建多个私有SQL区。把一个私有SQL区与对应的共享SQL区合并在一起,就可以获得一条SQL语句的完整缓存数据。私有SQL区可以再分为静态区和动态区两个部分。静态区的信息在会话过程中保持不变,只有当会话结束时,静态区才会被释放掉;而动态区的信息在整个会话过程中是不断变化的,一旦SQL语句执行完毕,即使会话还没有结束,动态区也被释放掉。
- 会话区:用于存放用户的会话信息(如登陆用户名)。如果数据库处于共享服务器连接模式下,则会话区将位于SGA区域,而不是PGA中,这点需要用户特别注意。
前台进程:
前台进程包括用户进程和服务进程,它不属于实例的一部分,但是用户在不知不觉中经常会用到它,使用前台进程能够实现用户和实例沟通。
用户进程:指那些能够产生或执行SQL语句的应用程序。在用户进程中有两个非常重要的概念:连接和会话。
服务器进程:用于处理用户会话过程中想数据库实例发出SQL语句,它可以分为专用服务器模式和共享服务器模式。在专用服务器模式下,每个用户进程都有一个专用的服务器进程,这个服务器进程代表用户进程执行SQL语句,必要时还可以回传执行结果给用户进程。在共享服务器模式下,每个用户进程不直接与服务器连接,而是连接到分派程序,每个分派程序可以同时连接多个用户进程。
后台进程:
是一组运行于Oracle服务器端的后台程序,是Oracle实例的重要组成部分。其中SMON、PMON、DBWR、LGWR和CKPT这5个后台进程必需正常启动,否则导致数据库实例崩溃。
数据写入进程(DBWR):主要任务是负责将内存中的脏数据块回写到数据文件中通常在以下几种情况发生时,DBWR进程会将脏数据块写入数据文件:
- 当用户进程执行插入或修改等操作时,需要将“新数据”写入高速数据缓冲区,如果在高速数据缓冲区中没有找到足够大的空闲数据块来存放这些“新数据”。
- 当检查点进程启动后,它会强制要求DBWR将某些脏数据块写入数据文件中。
- 当脏数据块在高速数据缓冲区中存放超过3秒钟,DBWR进程会自行启动并将某些脏数据块写入到数据文件中。
在某些比较繁忙的应用系统中可以修改服务器参数文件SPFILE的DB_WRITER_PROCESSES参数,以允许使用多个DBWR进程。但是DBWR进程的数量不应当超过系统处理器的数量,否则多余的DBWR不但无法发乎作用,反而会耗费系统资源。
检查点进程(CKPT):检查点进程可以看作一个时间,当检查点时间发生时,CKPT会要求DBWR将某些脏数据块回写到数据文件。当用户进程发出数据请求时,Oracle系统从数据文件中读取需要的数据并存放到高速数据缓冲区中,用户对数据的操作是在缓冲区中进程的。当用户操作数据时,就会产生大量的日志信息并存储在重做日志缓冲区,当Oracle系统满足一定条件时,日志写入进程(LGWR)会将日志信息写入到重做日志文件组中,当发生日志切换时,就会启动检查点进程。
- 可以通过修改初始化参数文件SPFILE中的CHECKPOINT_PROCESS参数为TRUE来启动检查点进程。
日志写入进程(LGWR):用于将重做日志缓冲区中的数据写入重做日志文件。
- 当发生提交命令、或者重做日志缓冲区的信息满1/3、或者日志信息存放超过3秒钟时,LGWR进程就会将日志信息从重做日志缓冲区中读出写入到日志文件组中序号较小的文件中,一个日志组写满后接着写另外一组。当LGWR进程将所有的日志文件都写过一遍之后,它将再次转向第一个日志文件组重新覆盖。
归档进程(ARCH):归档进程是一个可选择的进程,只有当Oracle数据库处于归档模式时,该进程才可能起到作用。若Oracle数据库处于归档模式,当各个日志文件组都被写满而即将被覆盖之前,先由归档进程(ARCH)把即将被覆盖的日志文件中的日志信息读出,然后再把这些“读出的日志信息”写入到归档日志文件中。
- 当系统比较繁忙而导致LGWR进程处于等待ARCH进程时,可通过修改LOG_ARCHIVE_MAX_PROCESSES参数启动多个归档进程,从而提高归档写磁盘的速度。
系统监控进程(SMON):系统监控进程是在数据库系统启动时执行恢复工作的强制性进程。比如,在并行服务器模式下,SMON可以恢复另一个处于失败的数据库,使系统切换到另一台正常的服务器上。
进程监控进程(PMON):用于监控其他进程的状态,当有进程启动失败时,PMON会清除失败的用户进程,释放用户进程所用的资源。
锁定进程(LCKN):这是一个可选进程,并行服务器模式下可以出现多个锁定进程以利于数据库通信。
恢复进程(RECO):这是在分布式数据库模式下使用的一个可选进程,用于数据不一致时进行恢复工作。
调度进程(DNNN):这是一个可选进程,在共享服务器模式下使用,可以启动多个调度进程。
快照进程(SNPN):快照进程用于处理数据库快照的自动刷新,并通过DBMS_JOB包运行预定的数据库存储过程。