范例
实例的体系结构
当用户希望访问数据库时,需要在操作系统中运行相关的应用程序,如SQL*Plus ,启动用户进程。
用户进程通过实例访问数据库。
实例和数据库组成了数据库服务器,-个数据库服务器中至少有一个实例。
在单机环境中,实例和数据库是一一对应的,一个实例只能和一个数据库建立关联关系,一个数据库也只能被一个实例加载。
在RAC环境中,一个数据库可以对应多个实例,用户进程可以通过任何一个实例访问数据库。
实例的概念
实例( Instance )是-组内存结构和后台进程的集合。
当用户访问数据库时,在数据库服务器端首先要启动一个实例,在内存中分配一定的存储空间,并启动一些后台进程。
内存空间的作用是存储与用户访问有关的重要数据,后台进程的功能是监视系统的运行状态,并负责在实例和数据库之间交换数据。
在支持线程的操作系统中,这些后台进程以线程的方式运行。
用户访问数据库的操作是通过实例来完成的。
实例通过后台进程与数据库中的文件进行交互,将用户修改过的或新增加的数据写入文件,而用户对数据的所有访问都是在实例的内存结构中进行的。
引入实例的好处是显而易见的:数据位于内存中,用户读写内存的速度要比直接读写磁盘快得多,而且内存中的数据可以在多个用户之间共享,从而提高了数据访问
的并发性。
单机版的数据库(如FoxPro )没有实例的概念,用户对数据的访问是通过直接访问数据文件来完成的,这样在性能上大大低于Oracle 。
而且因为数据无法在多个用户之间共享,多个用户只能以串行的方式访问数据。
可想而知,在一个大型的应用系统中,如果同时有成千上万个
用户同时访问数据库时,采用性能低下的数据库是件非常可怕的事情。
由此可见, Oracle的实例对于数据库的性能是多么的重要。
实例的组成
当数据库服务器启动时,首先启动实例,然后加载并打开数据库。
当用户访问数据库时,数据库服务器便为用户进程启动一个服务器进程,负责处理用户进程的所有请求,例如将用户访问的数据从数据文件读到内存中。
在计算机的内存中不仅要存储数据库中的数据,还要存储数据字典的信息、重做日志以及经过解析的SQL代码等。
实例中的这部分内存结构叫做系统全局区( SGA, System GlobalArea )。
SGA是实例中最重要的组成部分,一个实例只有一个SGA 。
SGA 中的数据可以在多个用户进程之间共享。
SGA 由若干个缓存和缓冲区组成,不同类型的数据存储在不同的缓存和缓冲区中。
SGA的大小可以定制,通过在参数文件中为各个缓存和缓冲区分别指定大小,可以确定SGA的大小。
用户对数据的操作实际上是在SGA 中进行的,当启动数据库服务器时,首先启动实例,然后数据库被打开。
当用户进程向服务器进程发出请求时,服务器进程将用户请求的数据读到SGA中,用户对数据的所有访问直接在SGA中完成,其他用户进程也可以在SGA中访问相同的数据。
当关闭实例时,未保存的数据写人数据文件中, SGA被撤销,所有的数据从SGA中清除。
当用户访问数据库时,实例为用户进程启动一个服务器进程,并分配一段内存区,用来保存用户进程的私有信息和控制信息,这段内存区叫做进程全局区( PGA, Process Gl9bal Area )。
SGA是所有用户进程共享的,只要实例被启动,无论是否有用户访问数据库, SGA都存在。
而PGA是用户进程私有的,当用户进程向数据库服务器发出请求时,实例为用户进程分配PGA,当用户进程结束时, PGA 自动释放。
由此可见,实例中的内存结构包括SGA和PGA两部分。
SGA是所有用户共享的,它在实例的运行过程中一直存在。
严格地说, PGA并不属于实例,它是服务器进程的一部分,是用户进程私有的,是一种临时的内存结构。
Oracle允许成千上万个用户同时访问数据库,并提供了一种巧妙的机制来保证用户对数据的安全、高效访问。
在Oracle实例中包含一组后台进程,它们负责完成复杂的数据访问和维护工作。
在Oracle实例中可以启动以下后台进程: SMON, DBWR, PMON, CKPT, LGWR,ARCH, RECO 。
其中有些进程是必须启动的,而另外一些是可选的。
在默认情况下实例将启动SMON 、DBWR 、PMON 、CKPT和LGWR等五个后台进程。
实例的组成如下图所示。
在接下来的几节中,将分别对实例的内存结构和后台进程进行详细的介绍。
实例的内存结构
当实例启动时,系统为实例分配了一段内存空间,并启动若干后台进程。
内存空间分成不同的部分,分别用来存储不同的信息。
具体来说,在这段内存空间中存储以下信息:
·程序代码: Oracle的可执行代码。
·缓冲数据: 用户要访问的数据、重做日志等。这部分内存叫做SGA 。
.与会话有关的信息。
·与进程间通信有关的信息,如加锁的信息。
在上述内存区域中,最重要的是SGA 。
SGA是由多个缓存和缓冲池组成的,在这些内存结构中存储不同类型的数据。
根据存储数据的类型, SGA 中主要包含以下类型的内存结构:
·数据库高速缓存
·重做日志缓冲区
.共享池
•Java池
.大池
其中数据库高速缓存由许多缓冲区组成,共享池由数据字典缓存和库缓存两部分组成。
在这里之所以使用了缓存和缓冲区两个概念,是因为它们来自不同的英文单词,缓存是从单词cache翻译来的,而缓冲区来自单词buffer 。
当实例运行时,可以通过命令查看SGA的大小。
SGA是由不同的内存结构组成的,所以查看的结果是分别列出了不同组成部分的大小。
例如,在SQL*Plus 中执行下面的SHOW命令可以查看当前SGA 的大小:
SHOW SGA
SGA的更详细的信息可以从动态性能视图v$sga 、v$sgainfo和v$sgastat中获得。
从这些视图中可以获得每种缓冲区和缓存的大小信息。
下面是关于V$SGA的相关信息:
V$SGA
displays summary(概要) information about the system global area (SGA).
Column | Datatype | Description |
---|---|---|
|
|
SGA component group(元件组) |
|
|
Memory size (in bytes) |
|
|
The ID of the container to which the data pertains(属于). Possible values include:
|
下面是关于V$SGAINFO的相关信息:
V$SGAINFO
displays size information about the SGA, including the sizes of different SGA items(名目), the granule size(颗粒大小), and free memory.
Column | Datatype | Description |
---|---|---|
|
|
Name of the SGA size item |
|
|
Size of the item (in bytes) |
|
|
Indicates whether the item is resizeable ( |
|
|
The ID of the container to which the data pertains. Possible values include:
|
下面是有关V$SGASTAT相关信息:
V$SGASTAT
displays detailed(详细) information on the system global area (SGA).
Column | Datatype | Description |
---|---|---|
|
|
Designates(划定) the pool in which the memory in
|
|
|
SGA component name |
|
|
Memory size (in bytes) |
|
|
The ID of the container to which the data pertains. Possible values include:
|
数据库高速缓存
数据库高速缓存是SGA 中的一段存储区域,用来存放用户最近访问的数据。
当用户访问数据文件中的数据时,服务器进程首先查看这样的数据是否已经存在于数据库高速缓存中。
如果是,则直接在数据库高速缓存对数据进行访问,并将处理结果返回给用户,这次数据访问叫做“命中”,这样的读操作称为“逻辑读”。
否则,服务器进程将数据从数据文件的数据块中读到数据库高速缓存中,然后在数据库高速缓存对数据进行访问,这次数据访问叫做“未命中”,这样的读操作称为“物理读”。
显然,如果直接在数据库高速缓存访问数据,要比从数据文件中读数据快得多。
所以,访问数据的命中率越高,数据库的性能就越高。
对数据库进行性能优化的一个重要方面就是提高逻辑读在所有读操作中所占的比例。
数据库高速缓存的大小通过初始化参数DB_CACHE_SIZE来指定。
提高数据访问命中率的最直接方法是增加数据库高速缓存的大小,但它的大小不能无限制地增加,它要受到物理内存大小的限制。
用户访问的数据都存储在数据文件中,数据文件被划分为许多大小相同的数据块。
数据块是Oracle进行读写的基本单位,也就是说,即使用户只希望访问一个字节的数据,那么数据所在的整个数据块也将被读到数据高速缓存中。
同样,在写数据时,也是以数据块为单位的。
这样做的好处是提高了数据库服务器的吞吐量。
数据库高速缓存是由一个个的缓冲区组成的,数据从数据文件中被读到数据库高速缓存中之后,就放在这些缓冲区中。
缓冲区的大小与数据块的大小一致,一个数据块的内容恰好放在一个缓冲区中。
数据块的大小由初始化参数DB_BLOCK_SIZE指定,并且在数据库创建后不能被修改,那么缓冲区的大小也由这个参数决定。
所有缓冲区大小的总和由初始化参数DB_CACHE_SIZE指定。
假设在参数文件中定义了以下两个初始化参数:
DB_BLOCK_SIZE=8192
DB_CACHE_SIZE=25165824
这说明每个缓冲区的大小为8192字节,即8KB ,而所有缓冲区的总的大小为25165824字节,即24MB ,这也是整个数据库高速缓存的大小。
由此可以计算组成整个数据库高速缓存的缓冲区个数,即25165824/8192=3072个。
前面已经提到,提高数据访问命中率的一个有效方法是增加数据库高速缓存的大小。
但是由于受到物理内存的限制,数据库高速缓存不可能无限大。
如果将数据库高速缓存设置得过大,操作系统可以使用的内存将减少,这样就要使用虚拟内存,反而会降低系统性能。
所以数据访问的命中率不可能达到100% 。
如果用户访问的数据不在数据库高速缓存中,就需要把数据读到某个缓冲区中。
一个数据块的内容到底放在哪个缓冲区中,如果没有足够的空闲缓冲区该怎么办呢?
有必要分析一下缓冲区的使用情况。
根据缓冲区的使用情况,我们可以把缓冲区分为空闲缓冲区、脏缓冲区和忙缓冲区三种类型。
如果一个缓冲区中存放的是由SELECT命令检索的数据,而且这样的数据没有被修改过,这样的缓冲区就是空闲缓冲区。
如果缓冲区中存放的是由DML命令处理过的数据,而且这样的数据已经被写入了数据块中,这样的缓冲区也是空闲缓冲区。
空闲缓冲区的内容与对应数据块中的内容是完全一致的,这样的缓冲区可用来存放用户即将访问的数据。
如果用户执行了INSERT 、UPDATE或者DELETE命令,相应的访问将在缓冲区中进行。
如果数据被修改后还没有写入数据块,这时缓冲区中的内容与数据块不一致,这样的缓冲区就是脏缓冲区。
脏缓冲区中的数据必须写人数据文件的数据块中,这个任务是由后台进程DBWR完成的。
脏缓冲区中的数据被写入数据块后,脏缓冲区又成为空闲缓冲区。
忙缓冲区是指正在被访问的缓冲区。
两个用户进程不能同时访问同一个忙缓冲区。
如果用户进程要访问的数据不在缓冲区中,服务器进程将把对应数据块中的数据读入数据库高速缓存的空闲缓冲区中,这个缓冲区中以前的数据将被覆盖。
现在考虑一种情况:假设一个缓冲区中的内容被覆盖,恰在这时,另一个用户进程要再一次访问这个缓冲区中以前的数据,服务器进程将不得不把数据所在的数据块重新从数据文件读到另一个缓冲区中,这种情况显然会降低数据库的性能。
为了保证数据访问的命中率, Oracle采用了LRU (最近最少使用LeastRecently Used )算法,确定每次使用的空闲缓冲区。
LRU算法的思想是基于这么一个假设:在最近一段时间内使用最少的缓冲区,在以后的一段时间内也将使用最少,而最近一段时间被频繁访问的缓冲区,在以后的一段时间也将被频繁访问,这个缓冲区中的数据就不应该被覆盖。
基于这个思想,每次将数据读到缓冲区中时,服务器进程总是选择那些最近访问次数最少的空闲缓冲区。
这种方法虽然不能完全杜绝,但是可以尽量减少上述情况的发生。
在实例中维护了一个LRU队列,在这个队列中记录了各个缓冲区的使用情况。
队列的操作遵循“先进先出”的原则,那些最近访问最频繁的缓冲区位于队列尾部,而那些最近最少被访问的缓冲区则位于队列头部。
如果用户访问的数据恰好在缓冲区中,则该缓冲区被标志为“最近访问”,并被移动到队列尾部。
如果用户访问的数据不在缓冲区中,服务器进程将在队列头部寻找合适数量的空闲缓冲区,将数据读到这些缓冲区中,并将它们标志为“最近访问”,然后将它们移动到队列尾部。
如果在搜索LRU队列的过程中遇到一个忙缓冲区,服务器进程将忽略它。
如果找到一个脏缓冲区,服务器进程将这个脏缓冲区写入另外一个“脏队列”中,然后继续查找LRU队列,直到找到足够数量的空闲缓冲区。
在脏队列中记录了数据库高速缓存中的脏缓冲区,实例中的DBWR后台进程在一定的时机下将这个队列中的缓冲区写入数据文件中。
上面我们考虑了缓冲区的一种使用情况,即在数据库高速缓存总有足够数量的空闲缓冲区。
一种经常发生的情况是,在搜索LRU队列时没有找到足够数量的空闲缓冲区,这时服务器进程将激活实例中的DBWR后台进程,将脏队列中的脏缓冲区内容写入到数据文件中,这些脏缓冲区重新成为空闲缓冲区,它们将被从脏队列中清除,而重新被写入LRU队列,服务器进程将继续在LRU队列中搜索。
当用户进程执行事务时,将在数据库高速缓存中产生脏缓冲区,这些脏缓冲区并不是立刻被写入数据文件,而是在一定的时机下,由DBWR进程一起写入,这样做的好处是减少了磁盘I/O ,从而提高了数据库的性能。
前面说过,数据块的大小由初始化参数DB_BLOCK_SIZE指定,而且不能改变。
设置数据块大小的一个基本原则是:如果在数据库中主要执行SELECT语句,如在数据仓库中,这个参数可以设置得大一些,如果主要执行DML语句,这个参数可以设置得小一些。
但是在一个数据库中,可能会对一部分数据主要执行SELECT语句,对另外一部分数据主要执行DML语句。
在这种情况下,可以在数据库中定义不同的数据块大小,根据数据的不同访问要求,把它们放在不同的数据块中,从而从整体上提高数据库的性能。
由初始化参数DB_BLOCK_SIZE指定的数据块称为标准块,在数据库在中还可以定义其他大小的非标准数据块,非标准数据块的大小可以是2KB 、4KB 、8KB 、16KB 、32KB 等。
为了访问非标准块中的数据,在SGA 中也需要为它们定义相应的数据库高速缓存,而缓存中缓冲区大小与非标准块的大小也是一致的。
Oracle提供了一套新的初始化参数DB_nK_CACHE_SIZE,用于定义与nKB的非标准数据块对应的数据库高速缓存大小:
DB_2K_CACHE_SIZE 为2KB的数据块定义缓存大小,缓存由2KB的缓冲区组成
DB_4K_CACHE_SIZE 为4KB的数据块定义缓存大小,缓存由4KB的缓冲区组成
DB_8K_CACHE_SIZE 为8KB的数据块定义绥存大小,缓存由8KB的缓冲区组成
...
例如,假设在参数文件中有以下初始化参数:
DB_BLOCK_SIZE=8192
DB_CACHE_SIZE=25165824
DB_2K_CACHE_SIZE=48M
DB_16K_CACHE_SIZE=56M
这说明标准数据块的大小为8KB ,由8KB 的缓冲区组成的数据库高速缓存为24MB ,同时定义了两种大小的非标准块和对应的缓存,由2KB 的缓冲区组成的数据库高速缓存大小为48MB ,由16KB 的缓冲区组成的数据库高速缓存大小为56MB ,总的数据库高速续存大小为三者之和。
注意,在上面这种情况下使用初始化参数DB_8K_CACHE SIZE是非法的,因为标准块的大小为8KB 。
为了使用非标准数据块,首先需要定义对应的数据库高速缓存,然后在创建表空间时为数据文件指定数据块大小。
例如:
ALTER SYSTEM SET DB_2K_CACHE_SIZE=48M SCOPE=BOTH;
CREATE TABLESPACE test DATAFILE 'C:\Users\john\Desktop\test1.dbf' SIZE 2M BLOCKSIZE 2K;
当用户访问标准数据块中的数据时,数据将被读入与标准块大小一致的缓冲区中,同样,非标准数据块中的数据将被读入与非标准块大小一致的缓冲区中。
在SQL*Plus中可以通过SHOW命令查看数据块的大小和每种缓冲区的大小,默认缓冲区的大小与标准数据块的大小一致。
例如,下面的命令将显示标准数据块的大小:
SHOW PARAMETER DB_BLOCK_SIZE
下面的命令将显示2kB缓存的大小:
SHOW PARAMETER DB_2K_BLOCK_SIZE
重做日志缓冲区
重做日志是对用户事务所产生的记录,通过重做日志能够重新产生数据,它是保证数据安全的一种重要方法。
当用户执行DML (INSERT 、UPDATE和DELETE )或者DDL (CREATE 、DROP 、ALTER等)操作时,服务器进程首先将这些操作记录在重做日志缓冲区中,然后才去修改相应的数据。
重做日志缓冲区中的内容在一定的时机下,被LGWR后台进程写入重做日志文件。
如果数据库系统出现了故障,可以根据重做日志文件中的重做日志对数据库进行恢复。
引人重做日志缓冲区的好处是显而易见的:将日志记录在重做日志缓冲区中,比直接写入重做日志文件要快得多。
另外, LGWR进程并不是在每次用户访问数据之后,都要将重做日志缓冲区中的日志写入重做日志文件,而是将最近一段时间产生的重做日志一起写人,这样可以减少访问磁盘的次数,从而提高系统的性能。
重做日志缓冲区的大小由初始化参数LOG_BUFFER指定。
在一定的时机下,后台进程LGWR会将重做日志缓冲区中的内容写入重做日志文件。
例如,在重做日志缓冲区被消耗了1/3时。
由此可见,重做日志缓冲区越大,就可以记录越多的用户操作,写重做日志文件的次数也就越少,这样也可以提高数据库的性能。
当然,重做日志缓冲区的大小是受物理内存大小的限制的。
共享池
数据库中的数据是以表的形式组织在一起的。
当用户访问数据时,数据库服务器首先检查对应的表是否存在,然后检查指定的列是否存在,还要检查权限和加锁等信息。
当这些检查都通过时,数据库服务器将对用户的命令进行分析,产生分析代码和执行计划,然后按照这样的执行计划访问数据,并将执行结果返回给用户。
为了提高数据库的性能, Oracle在SGA 中开辟了一个共享池,用于存放与SQL语句的执行有关的信息。
共享地主要由三部分组成,即数据字典高速缓存、库高速缓存和服务器结果缓存。
共享池的大小由初始化参数SHARED_POOL SIZE指定。
总的来说,共享池几乎和数据库中的所有操作都有关。
当用户访问数据库中的数据时,数据库服务器首先要查询相关的数据字典,确定要访问的对象是否存在,如表、视图等,以及表和视图上的列等。
然后检查权限等信息,最后才执行这样的命令。
数据字典信息存储在SYSTEM表空间中,也就是说,存储在磁盘上的数据文件中。
如果数据库服务器进程每次都要从磁盘上读数据字典信息,那么SQL 语句的执行效率是很低的。
为了加快这个SQL语句的执行速度, Oracle在共享池中开辟了数据字典缓存,用来存放最近访问的数据字典的信息。
这样查询相关的数据字典时,可以直接在数据字典缓存中进行。
库高速缓存用于存放最近执行的SQL命令的相关信息。
数据库服务器在执行SQL命令时,首先要对SQL命令进行解析,产生分析代码,并生成执行计划,然后才按照执行计划执行SQL命令,最后把命令的执行结果返回给用户。
在整个执行过程中,分析阶段所用的时间是最长的。
如果能减少分析所用的时间,那么整个SQL命令的执行效率将大大提高。
Oracle的做法是:在执行一条SQL命令时,服务器进程对它进行分析,然后把SQL命令文本、解析结果和执行计划就存储在库高速缓存中。
服务器进程在执行一条SQL命令时,首先要到库高速缓存中查看是否存在这条SQL命令的信息,如果发现SQL语句相关信息已经存储在库高速缓存中,就直接取出执行计划并执行它,这样就省去了分析所用的时间,可以大大加快SQL命令的执行速度。
否则,服务器进程需要按部就班地对SQL命令进行解析,然后生成执行计划,并将这些信息存储在库高速缓存中。
当两条SQL命令的文本完全相同时,可以认为它们是同一条命令,这时它们可以共享库高速缓存中的信息。
如果命令文本中的大小写、空格个数或参数的数值不同,就认为是两条不同的命令,它们在执行时需要单独进行分析,最终将生成不同的分析代码和执行计划。
例如,考虑以下两条命令:
SELECT ename,sal FROM emp WHERE empno=7902;
SELECT ENAME, SAL FROM EMP WHERE EMPNO=7902;
这两条命令看似相同,实际上是有差别的。
首先,命令中的大小写不同。
其次,两个列之间的空格个数不同,所以它们将生成不同的分析代码和执行计划。
由此可见,命令的书写风格对命令的执行结果没有什么影响,但对命令的执行效率却大有影响。
JAVA池
Java地是SGA 中一段可选的存储区域。
如果要在数据库中运行Java应用程序,那么对用户的每个会话来说,都需要一个单独的Java虚拟机。
实际情况是,每个Java虚拟机仅仅需要很小的一段内存空间,大约是35KB 。
Java虚拟机为什么能在这么小的内存空间中运行呢?
在实例启动时,可以为在SGA 中分配一个Java池,用来存放运行Java所必需的共享代码和共享数据。
多个Java应用程序可以共享Java池中的代码和数据。
在有些情况下,每个用户的Java会话信息也存储在Java池中。
Java池的大小由初始化参数JAVA_POOL_SIZE指定,默认大小为20MB ,在运行Java应用程序时,每个类大约需要4KB ~ 8KB 的Java池空间,这样可以根据Java应用程序中类的个数来大概估计一下所需的Java地空间。
另外,我们还可以通过查询动态性能视图v$sgastat来了解Java池的使用情况。
例如:
SELECT * FROM v$sgastat WHERE pool='java pool';
PGA
PGA (进程全局区, Program Global Area )是内存中一段特殊的区域,它包含了服务器进程的数据和控制信息,它是一段非共享的内存区域。
当服务器进程启动时,数据库服务器为它分配一段PGA ,这个PGA只能由当前服务器进程访问。
实际上, PGA并不属于实例,而是属于服务器进程私有的。
PGA包括两个部分:私有SQL 区和会话内存区。
在私有SQL 区中保存了SQL语句的绑定信息和运行时内存结构。
当用户执行一条SQL语句时,服务器进程即为这条语句分配一段私有SQL区。
如果两个用户执行了相同的SQL语句,那么这两段私有SQL区就被映射为一个共享的SQL 区。
当用户执行SQL语句时,将显式或隐式地使用游标,每个游标都有一段私有SQL区。
私有SQL区由持久区和运行时区组成,其中持久区保存SQL语句的绑定信息,仅当游标关闭时它才被释放。
运行时区是在服务器进程接收到SQL语句的执行请求时才产生的,在语句执行结束时被释放。
私有SQL 区的位置与会话的连接方式有关。
如果会话是以专用方式与数据库服务器连接的,那么它位于服务器进程的PGA 中。
如果会话以共享方式连接数据库服务器,那么它将位于SGA 中。
会话内存区保存会话变量和其他会话信息。
对于共享服务器,这部分内存区是共享的,而不是私有的,这些信息被所有的共享服务器进程所共享。
对于复杂的查询操作,私有SQL区中的运行时区大部分被用作排序、位图的创建、位图的合并等特殊操作,这部分特殊区域叫做“ SQL 工作区”。
例如,用户执行排序操作时,要用到排序区,排序区就位于SQL工作区中。
SQL工作区的大小是可以控制的。
这部分内存区域越大,数据库的性能就越高。
如果这部分内存区域的大小不足以执行排序等操作,那么将使用临时表空间中的临时段。
在以前Oracle版本中,用于排序、位图索引的创建等操作的内存区域分别由初始化参数SORT_AREA_SIZE 、CREATE_BITMAP_AREA_SIZE 、BITMAP_MERGE_AREA_SIZE等指定。
在Oracle 11g 中,可以对这部分内存区域进行自动管理。
首先通过设置初始化参数WORKAREA_SIZE_POLICY ,将SQL工作区的管理方式设置为自动方式,然后设置初始化参数PGA_AGGREGATE_TARGET ,指定SQL工作区的大小。
用户在进行排序等操作时,使用的内存区域的总和不能超过SQL工作区的大小,服务器进程将根据用户操作的需求,自动分配所需的内存区域。
初始化参数WORKAREA_SIZE_POLICY 的值有两个: AUTO 和MANUAL 。
如果设置为AUTO ,则SQL工作区的管理是自动进行的,这时就不需要通过SORT_AREA_SIZE等初始化参数为不同的操作分别指定内存区域了,只要通过初始化参数PGA_AGGREGATE_TARGET指定PGA的大小就可以了。
如果设置为MANUAL ,那么需要分别为用户的各种操作指定所需内存区域的大小。
实例中的后台进程
在一个大型数据库系统中,每时每刻都可能处理大量的用户请求,在数据库服务器中需要执行非常复杂的处理。
例如,将脏缓冲区中的内容写入数据文件,将重做日志缓冲区中的重做日志写入重做日志文件,发出检查点以维护数据文件、控制文件和重做日志文件间的一致状态,
在数据库服务器重新启动时进行实例恢复,进行重做日志归档等,这些任务都由实例中的后台进程来完成。
当实例启动时,这些后台进程将自动启动。
每个进程都有特定的功能,同时,这些进程之间也会相互协作。
例如, LGWR进程用于把重做日志缓冲区中的重做日志写入重做日志文件,当重做日志文件被写满后, LGWR进程将向ARCH进程发信号,由ARCH进程对重做日志文件进行归档。
需要注意的是,并不是所有的后台进程都需要启动。
常用的后台进程及其功能如下所示。
DBWR 将数据库高速缓存中的脏缓冲区内容写入数据文件
LGWR 将重做日志缓冲区中的内容写入重做日志文件
CKPT 发出检察点,维护数据文件、控制文件和重做日志文件之间状态的一致性
SMON 在数据库服务器重新启动时进行实例恢复
PMON 当用户进程执行失败时,释放服务器进程所占用的资源
ARCH 对重做日志文件进行归档
实例启动后,可以查看正在运行的后台进程。
在SQL*Plus 中查询动态性能视图V$BGPROCESS ,可以获得正在运行的后台进程。
下面是V$BGPROCESS有关的信息:
V$BGPROCESS
displays information about the background processes.
Column | Datatype | Description |
---|---|---|
|
|
Address of the process state object(进程状态对象) |
|
|
Process state object serial number(序列号) |
|
|
Name of this background process |
|
|
Description of the background process |
|
|
Error encountered(遇到的错误) |
|
|
The ID of the container to which the data pertains.(数据所属的容器ID) Possible values include:
|
例如:
SELECT name FROM v$bgprocess WHERE paddr<>'00';
其中条件paddr<>'OO·’限定了“正在运行的后台进程”。
实例中的后台进程与SGA 、数据文件、控制文件和重做日志文件的关系如图所示。
DBWR进程
DBWR进程的功能是将数据库高速缓存中的脏缓冲区内容写入数据文件中的数据块。
当用户执行DML命令时,服务器进程在数据库高速缓存中的缓冲区中修改数据,并将修改后的缓冲区标志为“脏缓冲区”。
DBWR进程将在一定的条件下将脏缓冲区的内容写入数据文件。
用户执行了DML命令后,被修改的缓冲区并不是被立即写人数据文件,而是保留一段时间,即使用户执行了COMMIT操作。
DBWR进程开始工作时,它将把一批脏缓冲区的内容一块写入数据文件。
这样做的好处有两点,一是减少了写磁盘的次数,因为多次写磁盘的操作被合并为一次写操作。
二是减少了读磁盘的次数,因为如果另外一个用户正好也要对同样的数据进行处理,便可直接在脏缓冲区中进行。
如果脏缓冲区被写入了数据文件,它将成为空闲缓冲区,并且可能马上被其他的访问所使用。
一旦空闲缓冲区被再次使用,那么当另外一个用户要访问这个缓冲区中以前的内容时,只好重新从数据文件中读取。
用户访问数据库时,服务器进程如果发现需要的数据不在数据库高速缓存中,它将把数据从数据文件读到空闲缓冲区中,在此之前,服务器进程要在LRU队列中搜索合适数量的空闲缓冲区,在搜索过程中如果遇到一个脏缓冲区,服务器进程将把它记录在脏队列中,然后继续搜索。
如果遇到忙缓冲区,将忽略它。
DBWR进程工作时,将扫描脏队列,把那些位于脏队列中,并且最近很少被访问的脏缓冲区写人数据文件。
而那些虽位于脏队列,但最近仍被频繁访问的脏缓冲区,或者那些还没有被记录在脏队列中的脏缓冲区,仍然可以保持“脏”状态,直到被写人数据文件。
在一个实例中可以启动多个DBWR进程,在默认情况下只启动一个。
如果用户的事务很频繁,那么在数据高速续存中将瞬间产生大量的脏缓冲区,对于一个DBWR进程来说,要把这些脏缓冲区写入数据文件,负载是很重的。
这时候可以考虑启动额外的DBWR进程,以提高写数据的效率。
DBWR进程的数目由初始化参数DB_WRITER_PROCESSES指定,最多可以启动20个( DBW0-DBW9以及DBWa-DBWj )。
DBWR进程并不是越多越好,一个基本的原则是,这个进程的数目不要超过CPU 的数目,如果计算机中只有一个CPU ,多个DBWR进程在CPU 中只能以串行方式运行。
而且计算机中如果只有一个硬盘,对数据库的写操作也只能以串行方式进行,如果多个DBWR进程同时写数据文件,将发生磁盘访问冲突。
DBWR进程在以下几种情况执行写操作:
·固定的时间间隔(如每隔3秒)。
·当数据库服务器发出检查点时。
·当脏队列中的缓冲区数目达到一定值时,也就是说在数据库高速缓存中不能有太多的脏缓冲区。
·当用户执行了某操作,需要在数据库高速缓存中搜索一定数量的空闲缓冲区时,空闲缓冲区的数量不能满足要求,这时DBWR进程将把脏队列中的一部分脏缓冲区写入数据文件,这部分脏缓冲区将重新成为空闲缓冲区。
LGWR进程
LGWR进程的功能是将重做日志缓冲区中的重做日志写入重做日志文件,这是Oracle保证数据库一致性的一种重要手段。
当用户执行DML或DDL命令时,服务器进程首先在重做日志缓冲区中生成重做日志,然后才修改数据库高速续存中相应的缓冲区。
在一定的条件下, LGWR进程将重做日志缓冲区中的重做日志写入重做日志文件,而DBWR进程也将在一定的条件下,把数据库高速缓存中的脏缓冲区写人数据文件,这两个进程并不是同步的。
LGWR进程被启动执行的时机有以下几种情况:
·固定的时间间隔(如每隔3秒)。
·用户执行了COMMIT操作。
·重做日志缓冲区已经有1/3 的空间被写满。
•DBWR将脏缓冲区写入数据文件之前。
由此可见,如果脏缓冲区中的数据被写入了数据文件,那么重做日志一定被写入了重做日志文件。
而用户数据还没有被写人数据文件时,重做日志也可能被写入了重做日志文件,也可能没有。
SGA 中的重做日志缓冲区是一段可循环使用的存储区域。
一方面,服务器进程将生成的重做日志写入重做日志缓冲区,占用一部分空间。
另一方面, LGWR进程将重做日志写入重做日志文件,释放一部分空间。
由于LGWR进程将重做日志写入重做日志文件的速度高于服务器生成重做日志的速度,所以在任何情况下重做日志缓冲区中始终都有足够的空闲空间。
重傲日志缓冲区的使用情况如图所示。
当用户执行事务时,服务器进程一方面在重做日志缓冲区中产生重做日志; 另一方面,在数据高速缓存中修改数据。
对重做日志缓冲区和重做日志文件是按顺序写的,效率很高,而对数据高速缓存和数据文件都是随机写的,因为数据的分布并没有什么规律,所以效率较低。
如果写日志和写数据是同步进行的,那么整个数据库的性能就不可能很高。
为了提高处理事务的效率, Oracle采取了“快速提交”的机制。
当用户执行一个事务时,这个事务将获得一个SCN ,同时产生重做日志,重做日志被写入重做日志缓冲区。
在此之后,服务器进程才在数据高速缓存中修改数据。
如果用户提交了事务, SCN也将被写入重做日志缓冲区,然后LGWR进程立即开始工作,将这个事务的重做日志和SCN一起写入重做日志文件,这个事务就算成功地执行结束了。
而与这个事务有关的脏缓冲区这时并没有写入数据文件,而是由DBWR进程在适当的时候写入。
在这里向大家介绍一个概念,即SCN (系统改变号, System Change Number )。
SCN是用于记录数据库变化的一个数字,它是一个正整数。
当一个事务执行之后,便获得一个新的SCN,每个SCN在整个数据库中都是唯一的,而且所有SCN的值是递增的,随着数据库的运行, SCN不断增大,并且永远不会重复,也没有消艳完的时候。
SCN被同时记录在数据文件、控制文件和重做日志文件中,如果这三个文件的SCN完全一致,数据库就达到了一个完全一致的状态。
现在考虑一个非常复杂的问题,
Oracle如何利用重做日志保证数据库的一致性?
如果发生了系统断电,用户执行的事务是否有效?
Oracle如何利用重做日志进行数据库的恢复?
假设用户执行了一条DML命令,如UPDATE。
假设在执行这条命令之前数据库的SCN值为
2000 ,在执行这条DML命令之后,这个事务获得的SCN是2010 。
现在我们来分析两种常见的情况。
首先我们考虑用户没有提交事务的情况。
根据DBWR进程、LGWR进程的工作机制可知,这次事务带来的变化可能已经被写入了数据文件和重做日志文件,也可能没有。
但是无论是否写入,这次事务都是无效的,因为新的SCN没有被写人数据文件,控制文件和重做日志文件,这三种文件中记录的还是原来的SCN值,即2000 。
如果此刻系统突然断电,那么数据库服务器在重新启动时,将检查这三种文件中记录的SCN ,并且回退最后一个SCN之后的所有事务。
也就是说,用户执行了一条DML命令,但是因为没有提交该事务,系统发生断电等故障时,数据将丢失,无法恢复。
现在再考虑事务被提交的情况。
当用户执行COMMIT命令提交事务时,重做日志缓冲区中的重做日志和新的SCN将被写入重做日志文件。
尽管这个事务所产生的脏缓冲区可能还没有被DBWR进程写入数据文件,但这个事务已经有效。
考虑上面提到的UPDATE命令,这时重做日志文件记录的是新的SCN值,即2010 ,但是这个SCN值还没有被写人数据文件和控制文件。
如果这三个文件的SCN不一致,那么重做日志文件中记录的SCN一定大于数据文件和控制文件中的SCN 。
如果此刻系统突然断电,那么数据库服务器在重新启动时,将检查这三种文件中记录的SCN ,并且重新执行两个SCN之间的所有事务, 然后将其中未提交的事务回滚,这样三种文件中的SCN将达到一致,然后才打开数据库,这时数据库达到了一致的状态。
数据库的这种操作称为“实例恢复”,实例恢复是根据重做日志文件的内容进行的,这个过程由后台进程SMON完成。
SMON进程将重做日志文件中记录的事务重新执行一次,从而保证了数据不会因为系统故障而丢失。
那么在系统运行过程中,三种文件中的SCN能不能达到一致呢?
答案是肯定的,这要依赖于后台进程CKPT 。
当CKPT进程开始工作时, SCN将被写入数据文件和控制文件,使三种文件的SCN完全一致。
同时CKPT进程通知DBWR进程开始工作,把脏缓冲区中的数据写入数据文件。
这时数据库将达到完全一致的状态,系统断电时数据库将不受任何影响,也不需要进行实例恢复。
由此可见,只有当事务被提交后,才有可能进行实例恢复,用户的数据才不至于丢失。
如果事务没有提交,数据是无法进行恢复的。
CKPT进程
CKPT进程的功能是发出检查点。
检查点是一种数据库事件,当数据库服务器发生检查点时, SCN将被写入数据文件和控制文件,而且数据库高速缓存中的脏缓冲区将被DBWR进程写入数据文件,这时数据库达到完全一致的状态。
我们知道,数据库服务器是依靠SCN来维护数据文件、控制文件和重做日志文件之间的一致状态的。
如果一个事务没有提交,脏缓冲区及其重做日志缓冲区中的内容可能已经被写入了数据文件和重做日志文件。
这时如果数据库服务器发出检查点,三种文件的SCN达到一致,数据库达到一种一致状态。
但这三种文件中记录的是该事务之前的SCN 。
数据库服务器如果重新启动,这个事务将被回滚,因为它处于最后一个SCN之后。
如果事务被提交,新的SCN将首先被写入重做日志文件,这时数据库服务器如果发出检查点,新的SCN被写人数据文件和控制文件,三种文件的SCN完全相同,数据库达到一致状态,在这种情况下,数据库服务器在重新启动时就不需要进行实例恢复。
相反,如果没有发出检查点,那么在数据文件和控制文件中保持原来的SCN 。
如果系统断电,数据库服务器在重新启动时,将进行实例恢复,两个SCN之间的所有事务将被重新执行一次,使数据库达到一致状态。
CKPT进程的任务有两个:一是通知DBWR进程,将数据库高速缓存中所有脏缓冲区写入数据文件,二是发出检查点,将SCN的值写入数据文件和控制文件的头部。
可见,当数据库服务器发出检查点时,将带来大量的磁盘I/O ,因此,应该尽量减少检查点的发生。
CKPT进程在以下几种情况下被启动执行:
·正常关闭数据库服务器时。
·进行日志切换时。
·手工发出检查点(执行ALTER SYSTEM CHECKPOINT命令)。
·由初始化参数LOG_CHECKPOINT_TIMEOUT和LOG_CHECKPOINT_INTERVAL指定的时机来到时。
与检查点的发生时机有关的两个初始化参数为:
• LOG_CHECKPOINT_TIMEOUT :用于指定两个检查点之间的时间间隔(以秒为单位)。
Oracle 11g 中这个参数的默认值为1800 ,即30分钟。
如果设置为0 ,将取消固定时间间隔方式的检查点。
• LOG_CHECKPOINT_INTERVAL :这个参数指定了一个操作系统块的数目,可以看做是检查点在空间上发生的间隔。
当往重做日志缓冲区中写人指定块数的重做日志时,将发出检查点。
在管理数据库时,应该为检查点设置合理的时间、空间间隔。
如果间隔太大,对数据文件的写操作次数将减少,数据文件与重做日志文件的SCN将相差较大,在系统断电时,进行实例恢复的时间将加长。
反之,如果间隔太小,磁盘写操作将被频繁执行,数据库的性能将降低,但这样做的好处是,在系统断电时实例恢复的时间将被缩短。
现在以一个不合理的检查点间隔的例子来说明如何消除不必要的检查点。
假设操作系统块的大小为1024字节,初始化参数LOG_CHECKPOINT_INTERVAL的值为4608 ,重做日志文件的大小为10MB 。
那么每当向重做日志文件中写入1024 x 4608=4.5MB 的重做日志时,数据库服务器将发出检查点。
这样在两个检查点之后,重做日志文件将被写满9MB。
如果再写入1MB,就会进行日志切换,并自动发出一个检查点。
这样最后两个检查点的间隔仅为IMB ,显然间隔太短。
所以在设置LOG_CHECKPOINT INTERVAL参数时要考虑重做日志文件的大小,尽量将一些检查点与切换日志时发出的检查点合并。
SMON进程
SMON是系统监视进程,它的功能是监视数据库服务器的运行状况,并执行一些必要的清理工作。
在数据库服务器启动时, SMON进程将检查数据文件、控制文件和重做日志文件,并根据三个文件的SCN值进行实例恢复,或者回滚未提交的事务。
另外, SMON进程还可以对数据库的存储空间进行一些常规的管理。
具体的功能如下:
·回收临时表空间中不再使用的临时段。
·在字典管理表空间中合并相邻的空闲存储空间。
在数据库服务器重新启动时, SMON进程负责进行实例恢复,并对数据库的存储空间进行管理。
在实例正常运行时, SMON进程也会经常工作,或者被其他进程调用,这时它的功能仅限于对存储空间进行管理。
PMON进程
PMON进程的功能是定期检查用户进程,并进行回收资源的操作。
当用户访问数据库时,用户进程与服务器进程建立连接。
当用户进程断开连接时, PMON进程负责回收为其服务的服务器进程所占用的资源。
如果由于某种原因使连接非正常断开,如用户进程异常终止,或网络发生故障,用户进程所占用的资源还没有释放。
PMON进程负责检查所有用户进程的状态,清除非正常终止的用户进程,并回收它们所占用的资源,如锁、存储区域等,终止相应的子进程,并释放对应服务器
进程所占用的资源。
PMON进程还有一个功能,就是将实例和调度器注册到网络监听器中。
当实例启动时,PMON进程负责将实例的信息注册到监听器中。
如果监听器没有启动, PMON进程将周期性地察看它的状态。
ARCH进程
ARCH进程的功能是对重做日志文件进行归档。
数据库的重做日志记录在重做日志文件中。
在一个数据库中往往需要若干组重做日志文件,这些文件是循环使用的。
当一组重做日志文件被写满时,数据库服务器自动进行日志切换,重做日志接着被写入下一组重做日志文件。
当数据库服务器再一次使用一组重做日志文件时,文件中以前的内容将被覆盖,而且永远无法恢复。
随着数据库服务器的运行,重做日志文件不断被覆盖。
可以想象,如果系统发生故障,造成数据丢失,这时候要对数据进行恢复。
数据恢复需要用到对数据库所进行的备份,以及重做日志。
如果重做日志缺失,那么最后一段时间的数据将无法恢复。
为了防止这种情况的发生,Oracle提供了一种归档日志模式。
在这种模式下,数据库服务器将自动对重做日志文件进行归档。
如果数据库处于归档日志模式下, ARCH进程将自动启动,当一个重做日志文件被写满时,要进行日志切换, ARCH进程将对刚刚写满的重做日志文件进行归档,将重做日志文件的内容保存在归档日志文件中。
有了归档日志文件,数据库管理员再也不用担心重做日志文件被覆盖的事情发生了。
由于日志归档是自动进行的,所以数据库服务器可以顺利地进行日志切换,无需人工干预。
如果数据库处于非归档日志模式下,重做日志文件是不会被归档的。
只有数据库处于归档日志模式下,并且启动了ARCH进程,数据库服务器才会自动对重做日志进行归档。
在一个实例中可以启动多个ARCH进程,默认情况只启动4个。
与ARCH进程有关的初始化参数有以下几个:
• LOG_ARCHIVE_MAX_PROCESSES :指定可以启动的ARCH的最大数目。
• LOG_ARCHIVE_FORMAT :指定归档日志文件的名称。
• LOG_ARCHIVE_DEST n :指定归档日志文件的存储路径,其中n的取值范围为1-31。
• LOG_ARCHIVE_DEST_STATE_n :指定对应的归档路径是否可用。
如果数据库服务器写重做日志文件的速度比日志归档的速度要快,那么将发生数据库服务器被阻塞的现象。
所以在服务器写重做日志的操作非常频繁的情况下,可以启动多个ARCH进程,以加快日志归档的速度。
实例内存结构管理
内存结构管理主要涉及对SGA 中的各种缓冲区进行最佳设置,使实例对内存的利用率达到最高,从而提高数据库的性能。
从Oracle 11 g开始,可以对SGA和PGA进行完全的自动管理,也就是说,只要分别指定SGA和PGA的最大大小,实例将自动确定每种缓冲区的大小,以及每个服务器进程的PGA大小,随着数据库服务器的运行,实例可以根据需要随时调整这些内存区个服务器进程的PGA大小,随着数据库服务器的运行,实例可以根据需要随时调整这些内存区域的大小。
有三种方法可以对实例的内存结构进行管理:
.自动内存管理。
·自动共享内存管理。
.手工共享内存管理。
自动内存管理
这是一种完全自动的内存管理方式,只要通过初始化参数MEMORY _TARGET 和MEMORY_MAX_ TARGET指定实例可用的最大内存大小,实例就可以自动确定SGA和PGA的大小, SGA 中的每种缓冲区大小也根据需要自动确定。
随着数据库服务器的运行,实例将根据需要,在指定的范围内自动调整SGA和PGA的大小。
MEMORY_TARGET参数可以动态修改,管理员可以随时修改这个参数的值,而不用重新启动实例。
MEMORY_MAX_ TARGET是不能动态修改的,它的作用是为实例指定了可用内存的上限,也就是说,指定了MEMORY_ TARGET 参数的最大可取值。
设置初始化参数MEMORY_MAX_ TARGET的目的是防止管理员将MEMORY_TARGET参数设置过大,从而给操作系统留下太少的内存。
为了使用自动内存管理方法,需要对以下初始化参数进行适当的设置:
SGA_TARGET 应该设置为0
PGA_AGGREGATE_TARGET 应该设置为0
LOCK_SGA 应该设置为false
如果希望了解SGA和PGA 目前的实际大小,以及SGA中每种缓冲区的实际大小,可以查询动态性能视图v$memory_dynamic_components。
下面是有关动态性能视图v$memory_dynamic_components的信息:
V$MEMORY_DYNAMIC_COMPONENTS
displays information about the dynamic SGA components. This view summarizes information based on all completed SGA resize operations since instance startup. All sizes are expressed(表示) in bytes.
Column | Datatype | Description |
---|---|---|
|
|
Component name |
|
|
Current size of the component |
|
|
Minimum size of the component since instance startup |
|
|
Maximum size of the component since instance startup |
|
|
Value of the user parameter for the component |
|
|
Number of operations since instance startup |
|
|
Last completed(完成) operation for the component:
|
|
|
Mode of the last completed operation:
|
|
|
Start time of the last completed operation |
|
|
Granularity(粒度) of the |
|
|
The ID of the container to which the data pertains. Possible values include:
|
例如,下面的SQL语句用于查看PGA以及SGA中每种缓冲区目前的大小、以及可以调整的范围:
SELECT component, current_size, min_size, max_size FROM V$MEMORY_DYNAMIC_COMPONENTS;
自动共享内存管理
自动共享内存管理用来对SGA 进行自动设置。
只要通过初始化参数SGA_TARGET 和SGA_MAX_SIZE指定SGA的最大大小,那么SGA 中的各种缓冲区大小就可以根据需要自动确定,可以说,这是一种半自动化的内存管理方法。
需要注意的是,重做日志缓冲区、非标准块对应的高速缓存、KEEP缓冲池和RECYCLE缓冲区的大小仍需自己设置。
为了使用自动共享内存管理,首先为初始化参数SGA_TARGET和SGA_MAX_SIZE指定适当的大小,然后把以下初始化参数的值设为0。
MEMORY_MAX_TARGET
MEMORY_TARGET
SHARED_POOL_SIZE
LARGE_POOL_SIZE
JAVA_POOL_SIZE
DB_CACHE_SIZE
STREAMS_POOL_SIZE
而以下初始化参数仍然需要进行适当的设置:
LOG_BUFFER
DB_KEEP_CACHE SIZE
DB_RECYCLE_CACHE_SIZE
DB_nK_CACHE_SIZE
如果需要了解SGA 中每种缓冲区的实际大小,可以查询动态性能视图v$sgainfo 。
手动共享内存管理
这种内存管理方法很好理解, SGA 中每种缓冲区的大小都需要手工设置, SGA的总大小就是这些缓冲区之和。
如果SGA设置过大,操作系统可用的内存将减少,这时将使用交换空间,把SGA 的一部分数据放到交换空间中,这样会降低数据库的性能。
可以把初始化参数LOCK_SGA的值设置为TRUE ,这样就可以把SGA锁定在物理内存中。
为了使用手工共享内存管理,需要把以下初始化参数的值设置为0 。
MEMORY_MAX_TARGET
MEMORY_TARGET
SGA_TARGET
PGA_AGGREGATE_TARGET
·以下参数需要根据实际情况进行适当的设置:
SHARED_POOL_SIZE
DB_CACHE_SIZE
LOG_BUFFER
LARGE_POOL_SIZE
JAVA_POOL_SIZE
DB_KEEP_CACHE_SIZE
DB_RECYCLE_CACHE_SIZE
DB_nK_CACHE_SIZE