Oracle的体系结构大体上分为两部分:Instance(实例)和Database(数据库)。
如图1所示:
图1 Oracle 数据库体系结构
我们平时说的Oracle Server(Oracle服务器)就是由 Oracle Instance 和 Oracle Database 组成的,如图2:
图2 Oracle Server
Oracle InstanceInstance中主要包含 SGA 以及一些 Backgroud Process (后台进程)(例如:PMON、SMON、DBWR、LGWR、CKPT等)。
SGA
SGA包含6 个基本组件:Shared Pool(Library Cache,Data Dictionary Cache)、Database Buffer Cache、Redo Log Buffer、Java Pool、Large Pool、stream pool。
下面将分别介绍这6个基本组件的功能。
1) shared pool
- 共享池是对 SQL、PL/SQL 程序进行语法分析、编译、执行的内存区域。
- 共享池由 Library Cache(库缓存)、Data Dictionary Cache(数据字典缓存)和 Server Result Cache(结果缓存)等组成。
它们分别都有哪些作用呢?
Library Cache: SQL 和 PL/SQL 的解析场所,存放着经过编译解析后的SQL和PL/SQL语句的内容,以备所有用户共享。
* 如果下次再执行同样的 SQL 语句的时候,就不需要解析了,立即从 Library Cache 获取执行。
* Library Cache的 SIZE 会决定着编译解析 SQL 语句的频度,从而决定了性能。
* Library Cache中又包含两部分内容:Shared SQL Area和Shared PL/SQL Area。
Data Dictionary Cache: 存放重要的数据字典信息,以备数据库使用。
* Data Dictionary是使用最频繁的,几乎所有的操作都需要到数据字典去查询。为了提高访问Data Dictionary的速度,此时需要一个Cache,需要的时候访问内存即可。
* Data Dictionary Cache里面的信息包含了Database Files、Tables、Indexes、Columns、Users、Privileges和其他的数据库对象。
Server Result Cache: 存放服务器端的 SQL 结果集及 PL/SQL 函数返回值。
看了上面的讲解,或许会觉得有些抽象,下面将通过一个例子进行讲解。
假设在客户端提交一个命令,如下:
1 |
|
如果数据库是第一次被提交这条语句,则需要进行解析,解析过程分为硬解析和软解析。
- 硬解析:检查语法、语义、权限,分析绑定变量等,最终生成一个执行计划;
- 软解析:依据执行计划去具体执行它。若是select语句,执行完后还会返回结果集,若是update、delete语句则无需返回结果集。
Library Cache会把这条 sql 语句和执行计划装入其中。 装入这些东西有什么作用呢? 下次再敲一摸一样(标点符号、大小写、空格完全一致)的语句时,就不需要硬解析了。
小问答: 如果此时客户端再提交一条命令:
1 |
|
猜测一下,这条语句需要被解析吗? 答案:需要。
小说明:注意哦,语句必须完全一样才不需要解析哦。标点符号、大小写、空格等都要完全一致哦!平时规范书写的好处在这里就体现啦。
前面有说到,若是 select 语句,执行完后还会返回结果集。那结果集存放在哪里呢?
1 |
|
该语句执行返回的结果集将存放在 Server Result Cache 中。
2) Database Buffer Cache
- Database Buffer Cache用于存储从磁盘数据文件中读入的数据,为所有用户共享。
- Server Process(服务器进程)将读入的数据保存在数据缓冲区中,当后续的请求需要这些数据时可以在内存中找到,则不需要再从磁盘读取。
小说明:逻辑读(从内存读)的速度是物理读(从磁盘读)的1万倍呦,所以还是想办法尽量多从内存读哦。 所以,数据缓冲区的大小对数据库的读取速度有直接的影响。
例如用户访问一个表里面的记录时,数据库接收到这个请求后,首先会在Database Buffer Cache中查找是否存在该数据库表的记录,如果有所需的记录就直接从内存中读取该记录返回给用户(有效提升了访问的速度),否则只能去磁盘上去读取。
继续看上面的例子:
1 |
|
该条语句以及它的执行计划被放在Library Cache里,但语句涉及到的数据,会放在 Database Buffer Cache 里。
小问答: Database Buffer Cache是怎么工作的呢?
这就要说一说Database Buffer Cache的设计思想了。 磁盘上存储的是块(block),文件都有文件号,块也有块号。 若要访问磁盘上的块,并不是CPU拿到指令后直接访问磁盘,而是先把块读到内存中的Database Buffer cache里,生成副本,查询或增删改都是对内存中的副本进行操作。如图3所示。 另外,如果是增删操作,操作后会形成脏块,脏块会在恰当时机再写回磁盘原位置,注意哦,可不是立刻写回呦。
也许你会问,为什么不立刻写回呢? 因为: (1)减少物理IO; (2)可共享,若后面又有对该块的访问,可直接在内存中进行逻辑读。
图3 访问数据块
小问答: 为什么要通过内存访问数据块,而不是CPU直接访问磁盘呢? 答:因为相较于CPU,IO的速度实在是太慢了,CPU的速度是IO 的100万倍呢?如果CPU直接访问磁盘的话,会造成大量的IO等待,CPU的利用率会很低。所以,利用速度相当的内存(CPU速度为内存的100倍)做中间缓存,可以有效减少物理IO,提高CPU利用率。
但是,这里会有一个问题。前面说到查询或增删改都是对内存中的副本进行操作,当增删改操作产生脏块时不会立刻写回磁盘。
小问答: 我们设想一下,如果在 Database Buffer Cache 中存放大量未来得及写回磁盘的脏块时,突然出现系统故障(比如断电),导致内存中的数据丢失。而此时磁盘中的块存放的依然是修改前的旧数据,这样岂不是导致前面的修改无效? 要怎样保持事务的一致性呢? 答:如果我们能够保存住提交的记录,在 Database Buffer Cache 中一旦有数据更改,马上写入一个地方记录下来,不就可以保证事务一致性了嘛。
小说明:Instance在断电时会消失,Instance在内存中存放的数据将丢失。这就需要 Redo Log Buffer 发挥它的作用啦。
3)Redo Log Buffer
- 日志条目(Redo Entries )记录了数据库的所有修改信息(包括 DML 和 DDL),一条Redo Entries记录一次对数据库的改变 ,为的是数据库恢复。
- 日志条目首先产生于日志缓冲区。日志缓冲区较小,它是以字节为单位的,它极其重要。
- 在Database Buffer Cache中一旦有数据更改,马上写入Redo Log Buffer,Redo Log Buffer在内存中保留一段时间后,会写入磁盘,然后归档(3级结构)。
4)Large Pool(可选)
为了进行大的后台进程操作而分配的内存空间,与 shared pool 管理不同,主要用于共享服 务器的 session memory,RMAN 备份恢复以及并行查询等。
5)Java Pool(可选)
为了 java 虚拟机及应用而分配的内存空间,包含所有 session 指定的 JAVA 代码和数据。
6)Stream Pool(可选)
为了 stream process 而分配的内存空间。stream 技术是为了在不同数据库之间共享数据, 因此,它只对使用了 stream 数据库特性的系统是重要的。
Background process
在正式介绍 Background Process 之前,先简单介绍 Oracle 的 Process 类型。
Oracle Process 有三种类型:
- User Proces
客户端要与服务器连接,在客户端启动起来的进程就是 User Process,一般分为三种形式(sql*plus, 应用程序,web 方式(OEM))。
- Server Process
User Process 不能直接访问 Oracle,必须通过相应的 Server Process 访问实例,进而访问数据库。 用户登录到 Oracle Server 就是 User Process 和 Server Process 建立Connection。
- background process
Oracle Instance的重要组成部分。接下来会对其做详细讲解。
小补充: Connection & Session Connection是指一个Oracle的客户端和后台和后台的进程(Server Process)建立的TCP连接。如图4所示:
图4 Connection
Connection 建立过程可简单描述如下:
1.首先建立 TCP 连接,Oracle 对用户的身份进行认证、进行安全审计等等; 2.当这些都通过后, Oracle 的 Server Process 才会允许客户端使用Oracle提供的服务; 3.当 Oracle 的连接建立起来以后,就意味着开始了一个 Session (会话),当连接断开的时候这个会话就消失了。
Session 是和 Connection 相辅相成的。Session信息会存储在 Oracle 的 Data Dictionary 中。 可通过图5直观看出 Connection 和 Session 的区别。
图5 Connection & Session
Background Process(后台进程)主要包括:SMON(系统监控器进程 )、PMON(进程监控器进程)、DBWR( 数据库写入程序进程)、LGWR(日志写入程序进程)、CKPT(检查点进程)。
1)PMON(Process Monitor)
PMON的主要作用如下:
- 监控各个Oracle后台进程是否正常,发现异常的进程将其清除掉,重新生成该进程。
- (说明:当用户进程断掉时,Server Process 留着就没用了,但是还占着空间,PMON 会定时检查 Server Process ,如果和 User Process 连接不上了,PMON 会把 Server Process 收回,把 PGA 空间收回,里面的锁也收回。)
- 监控空闲会话是否到达阀值。
- 动态注册监听。
2)SMON(System Monitor)
SMON的主要作用如下:
- 当Oracle运行时突然宕机,下次启动需要实例恢复(Instance Recovery),SMON负责实例恢复的全程监控;
- 当Oracle运行时突然宕机,在下一次启动Oracle Instance的时候,它里面一些没有释放的资源会由SMON进行清理;
- 一些事务失败的时候也由SMON进行清理;内存空间很分散(不连续)时需要SMON将这个分散的空间整合起来;
- 释放不再使用的临时段(Segment)。
3)DBWR(Database Writer)
DBWn是Oracle中工作最繁重的进程。主要作用如下:
- 将 Database Buffer Cache 中的脏块(Dirty Buffer)写到 Data File 中。
- 释放Data Buffer Cache空间。
小说明: 如果数据库的负荷比较大,来自于客户端的请求比较多,存在大量的IO操作,需要频繁的将缓冲区的内容写到磁盘文件上,那么这时就可以配置多个DBWn(一共Oracle支持20个DBWn,DBW0-DBW9,DBWa-DBWg)。通常一个中小型的Oracle只需要一个DBW0 Process就可以了。
注意:以下几种情况发生时,都会触发DBWR Process将 Database Buffer Cache 的内容写到Data Files :
- Checkpoint Occurs
- Dirty Buffer reach threshold
- There are no free Buffers
- Timeout occurs
- RAC ping request is made
- Tablespace OFFLINE
- Tablespace READ ONLY
- Table DROP or TRUNCATE
- Tablespace BEGIN
- BACKUP
小补充: 服务器进程对数据文件执行读操作,而 DBWR 负责对数据文件执行写操作。
小问答: Commit 时 DBWR 有何动作? 答:什么也不做!
4)LGWR((LOG Writer))
Oracle Instance中只有一个LGWR Process,这个Process的工作和DBWR Process类似。主要作用如下:
将 Redo Log Buffer 中的内容写入到 Redo Log Files 中(必须在 DBWR 写脏块之前写入日志)。
(Redo Log Buffer 是一个循环的Buffer,对应的 Redo Log Files 也是一个循环的文件组,从文件头开始写,当文件写满了,又会从文件头开始写,会把前面的内容覆盖掉,为了避免将 Redo Log Files 覆盖掉可以选择将其写入到 Archived Redo Log Files 中。)
注意:以下几种情况发生时,都会触发LGWR Process将 Redo Log Buffer 中的内容写到 Redo Log Files :
- At Commit
- When one-third full
- When there is 1 MB of redo
- Every three seconds
- Before DBWn writes
怎么保证提交的事务永久保留呢? 答:已执行update操作为例 。 1. 当写提交语句的时候,修改已经写到 Redo Log Buffer 里了; 2. 当看到返回提交成功时,说明修改已经写到磁盘 Redo Logfile 里了; 3. 所以提交成功后,改动已经同步到磁盘了,不会丢了。
5)CKPT(Checkpoint)
CKPT的主要作用如下:
- 生成检查点, 通知或督促 DBWR 写脏块;
- *完全检查点:保证数据一致性。
- *增量检查点:不断更新控制文件中的检查点位置,当发生实例崩溃时,可以尽量缩短实例恢复的时间。在Data File的在文件头更新检查点信息;在Control File中更新检查点的信息。
6)ARCn(Archiver)
- ARCn是一个可选的后台进程(几乎可看作必选进程)。
- Oracle可以运行在两种模式下:ARCHIVELOG MODE(归档模式)、NOARCHIVELOG MODE(非归档模式)。
- DBA 必须做出的一个重要决策是,配置数据库在ARCHIVELOG模式下运行,还是在NOARCHIVELOG模式下运行。
- 联机重做日志文件填满后,oracle实例开始写入下一个联机重做日志文件。
- 从一个联机重做日志文件切换到另一个联机重做日志文件的过程称为日志切换。
ARCn的主要作用如下:
当Oracle运行在归档模式时
- ARCn进程在每次进行日志切换时都会开始对已填满的日志组进行备份或归档。
- ARCn进程会在可以重新使用日志之前自动归档重做日志文件,因此会保留对数据库所做的所有更改。
这样,即使磁盘驱动器损坏,也可以将数据库恢复到故障点。
通过上面的学习,先把图1更新如下:
图6 Oracle 数据库体系结构
Database
Database 其实就是由一堆物理文件组成的,主要是用于存储数据,Database 中主要包含三种类型的文件:Data Files、Control Files、Redo Log Files。 另外还有Parameter File、Password File、Achieved Log Files等。
1)Data Files(数据文件)
Data Files 就是用于存储数据的,Table 中的数据都是保存在 Data Files 中的。
2)Control Files(控制文件)
Oracle为了操作Data File,提供了一些 Control Files,这些 Control Files 主要是记录数据库的一些控制信息。
3)Redo Log Files(重做日志文件)
Redo Log Files 记录着数据库的改变,如果向数据库中放入数据或者是修改里面的数据,只要对数据库作了修改,那么就要将修改之前的状态、修改之后的状态都记录在 Redo Log Files 中,其作用就是恢复Data File。 * 例如:数据库有一个事务需要提交,但是提交失败了,事务就要回滚,那么事务回滚的依据就来自于这个 Redo Log Files。Redo Log Files 中记录着数据库的改变,关于这个事务的改变,如果需要回滚就需要把Redo Log Files中的数据取出来,依照 Redo Log Files 中的数据把 Data Files 恢复到修改之前的状态。
4)Parameter File(参数文件)
任何一个数据库都必须要有参数文件,这个参数文件规定了Oracle中的一些基本的参数、初始化的参数的值。
5)Archived Log Files(归档日志文件)
Archived Log Files 和 Redo Log Files 是相辅相成的,Redo Log Files 其实是一个反复利用的过程,会有几个(一般为3个)固定的文件,这些固定文件会被依次使用,用满了以后,Oracle就会再次写这个文件头,就把以前的东西冲掉了。为了进一步加强数据库的备份恢复能力,在覆盖之前把这些修改的信息都归档到 Archived Log Files 中。
6)Password File(密码文件)
用户客户端连接到后台数据库系统时候存储口令的。
小问答: Instance 和 Database 的对应关系是怎样的呢?
答:Instance :Database = n :1 1个 Instance 只能属于1个数据库,可以多个 Instance 同时访问1个数据库。
小补充: Oracle 的内存结构(Memory Structure)
Oracle 的 Memory Structure 实际上包含两部分内容:SGA和PGA
SGA(System Global Area系统全局区)
- 一个 Oracle Instance 对应一个SGA,SGA 在Oracle Instance启动的时候被分配,SGA 是Oracle Instance 的基本组成部分。
- 一个 Oracle Instance 仅有一个 SGA,SGA是一个非常大的内存空间,甚至可以占据物理内存的80%。
PGA(Program Global Area程序全局区)
- 一个 Server Process 启动的时候就会分配一个 PGA。在 Oracle Instance 中 PGA 可能会很多。例如启动10个Server Process就会有10个PGA。
- PGA 存放用户游标、变量、控制、数据排序、存放 hash 值。
- 与 SGA 不同,PGA 是独立的,非共享。是分配给一个进程并归该进程私有的内存区域。