体系结构---实例

实例

**
我们来看一下单实例进程的交互流程:
**用户进程:**可以是一般的客户端软件,像Oracle的sqlplus,sql developer,或者是一些驱动程序等等都属于用户进程
**服务器进程:**服务器进程有时会称为前台进程,当然是相对于后台进程(后面会提到的数据库写入器,日志写入器等)来说的,服务器进程的主要作用就是处理连接到当前实例的用户进程的请求,对客户端发来的sql进行执行并返回执行结果,感觉服务器进程就是讲数据读出来,放在缓存中,而后台进程主要是把数据写入物理文件中
流程:
首先:用户与用户进程进行交互,然后用户进程再与服务器进程进行交互,在然后服务器进程与实例进程进行交互,最后,实例与数据库进程进行交互

举个例子,用户在淘宝买东西,选好相应的条件之后,数据会发送到web服务器上,而web服务器会向实例发送很多连接,这些连接叫做
连接池,oracle实例针对web服务器的每一个连接建立一个相应的服务器进程(前台进程)例如用户想买鞋子,将条件发送给web服务器,Web服务器会选中一个连接,通过这个连接给实例发送相应的SQL语句。实例接到SQL语句之后,解析,执行并将结果返给Web服务器,web服务器将结果通过界面的形式返回给用户

实例的进程和内存结构:
内存结构和进程结构关系较紧密,进程会作用到对应的内存区域,比如数据库写入器作用到数据库缓冲区缓存中,日志写入器会作用到日志缓冲区,所以内存结构和进程结构会相互配合地进行描述
oracle实例内存结构由两部分组成SGA(系统全局区)和PGA(用户全局区)组成,SGA是一块共享的内存区域,也是最大的一块内存区域;PGA则是用户会话专有的内存区域,每个会话在服务器端都有一块专有的内存区域就是PGA。
oracle所有的后台进程都共享SGA内存
每个进程都有自己的进程空间,这个空间是PGA提供的。PGA有一块大的内存空间,每当进程运行,PGA都会拿出一小块内存空间供进程使用,PGA进程主要供前台进程使用,但是后台进程也有自己的PGA内存
本文主要对SGA进行分析描述。SGA组成如下
Shared Pool/共享池
Database Buffer Cache/数据库缓冲区高速缓存
Redo Log Buffer/重做日志缓冲区
Large Pool/大池
Java Pool/JAVA池
Streams Pool/流池
在这里插入图片描述
在这里插入图片描述

SGA–缓存区缓存

我们举个简单的例子,来详细的说一下缓存的机制
一条SQL语句的执行流程:客户端输入一条SQL语句,通过连接送给了服务器进程,oracle单独分配一个PGA空间供服务器进程使用。服务器进程接收到SQL语句之后,将SQL语句解析成执行计划,然后拿着执行计划去执行,去数据文件中取数据,返回给用户。

解析过程:服务器首先判断SQL语句语法有没有错误,然后在判断SQL中的表或者视图有没有权限,存不存在。还要去判断这表SQL语句怎么执行(选取最优执行方案),最后生成执行计划。解析过程中会消耗很多资源:CPU,IO。但是有很多时候,可能很多用户都在执行相同的业务,这种情况下会同时消耗CPO,但是如果相同的SQL语句解析出执行计划,缓存起来,下一个相同的业务执行的时候,就可以直接拿着缓存的执行计划去执行,这样就会避免重复解析消耗不必要的CPU资源。oracle提供这种机制,会把首次执行的执行计划放进共享池。这样下次有重复业务的时候就可以直接拿共享池中的执行计划去执行。
取数据
服务器进程拿着执行计划去数据文件中取出数据,返给用户,数据库缓冲区高速缓存是用来缓存服务器进程取出来的数据,我们完全有必要进行这样的缓存,假如说a用户访问数据文件中一个表的数据,但是其他用户访问这个表的数据可能性也非常的大,没有数据库缓冲区高速缓存的话,每次访问一个表中数据,都需要重新访问数据文件,发生物理IO,降低性能。但是如果把这个表中数据缓存到数据库缓冲区高速缓存中的话,再有用户访问这个表,直接在缓存中获取数据,性能就会大大提高。所以获取数据的时候,首先去数据库缓冲区高速缓存找,如果没有再会去数据文件中去找,找到之后,也并不是直接返回给用户,而是先放在数据库缓冲区高速缓存中,从这里面返回给用户
逻辑IO:服务器进程读取数据时,先去数据库缓冲区高速缓存读取数据,这样叫做逻辑读取(内存读)
物理IO:数据库缓冲区高速缓存没有数据,去数据文件读取时,叫做物理读取(磁盘读)
命中率:逻辑/逻辑+物理,命中率越高,逻辑读越多,速度越快

修改过程同样,执行修改,删除同样需要先读取数据,服务器进程从数据文件中读取,放在数据库缓冲区高速缓存中,然后在数据库缓冲区高速缓存修改数据,修改的时候会产生日志,日志是服务器进程产生的 。这个时候内存里面的数据就和数据文件中的数据不一致了,
这就需要把缓存区的最新数据写入到数据文件中了,写入到数据文件中需要另一个后台进程DBWn。由重做日志缓存区写入到log日志文件中去需要lgwr进程

select * from caozyxx where caozyxm = 'admin';

我们来看这么一条简单的查询语句,oracle是如何处理的。首先,当用户提交了该条sql语句,由对应的用户进程(比如我们常用的sql developer)将其发送给服务器,监听程序监听到该条请求,会为其建立一个对应的服务器进程,然后服务器进程会先扫描缓冲区中有没有包含关键行(“admin”)的数据块,如果有,这就算一次缓存命中了,然后相关行会传输到PGA进行进一步处理,最终经过格式化后展示给用户;如果没有命中,那么服务器进程会首先将对应行复制到缓冲区内,然后再返回给客户端。
  DML(insert,update,delete)操作同理,加入用户发送一条update语句,服务进程依然先去扫描缓冲区,如果缓存命中,则直接更新,数据变脏;如果没有命中,由服务器进程将对应数据块先从磁盘上复制到缓冲区内,再进行更新操作。

数据缓存区就是我们将数据库文件的数据存放的缓存。它用来保存从数据文件里读取近期的数据块信息。当中的数据被全部用户享用。数据缓存区有很多大小同样的缓存块组成,这些缓存块大致能够分为3类:
一、 空暇缓存块
当我们又一次启动数据库后。系统就会为数据库分配一些空暇的缓存块。
空暇缓存块中是没有不论什么数据的,他们在等待后台进程或server进程向当中写入数据。当Oracle 数据库从数据文件里读取数据后,数据库就会寻找是否有空暇的缓存块,以便将数据写入当中。
一般来说。数据库在启动的时候,就会在内存中预先分配这些缓存块。
所以,Oracle数据库在启动的时候,会占用比較多的内存(这个内存空间是能够设置的)。可是,这能够免去在实际须要时向内存申请的时间。所以,有时候Oracle数据库尽管已启动,内存的占用率就非常高。可是。其兴许仍然能够正常执行的原因。而其它数据库尽管刚启动的时候内存占用率不是非常高,可是。但系统内存到达80%以上时,在进行数据处理就会受到明显的影响。
所以,当我们利用SELECT语句从数据库文件里读取文件的时候,数据库首先会寻找是否有空暇的缓存。

二、命中缓存块
命中缓存块保存那些正在使用的数据。
当select语句先从数据库文件里读取数据后,会把取得的数据放入到这个命中缓存块中。
直到快速缓存消耗完成等原因,这个空间才会被释放。如此下次假设再次訪问同样的数据的时候就能够从这里进行查找,节省时间(由于仅仅是被select。因此这里的数据是不会换出内存)。

三、脏缓存块
脏缓存块保存已经被改动可是还没有被写入数据库文件的数据。当訪问完数据之后。由空暇缓存块标志转化为命中缓存块标志。当我们运行update这类带侵略性的操作的时候,我们要先去命中缓存区去寻找数据,假设存在就行直接操作。而且此时命中缓存区标志被转为脏缓存块标志。这样就行实现数据的一致性。当满足一定的条件时。这些脏缓存块中的数据内容会被写入到数据库文件里去,以便永久性的保留数据库改动记录。
当写入数据库之后脏缓存块标志就会转化为空暇缓存块。

那Oracle数据库关于实现三大缓存块标志转化的原理:
实现以上机制主要靠两个列表:1.近期最少使用列表(LRU列表); 2.写入列表(DIRTY表).当中LRU列表保存着所有空暇缓存块、命中缓存块和所有还没有被移入到DIRTY列表中的脏缓存块。
当Oracle数据库用户在查询数据的时候。可能会遇到例如以下情况:
1、查询数据时。数据库首先在LRU列表中查询是否有空暇缓存块。其查询的数据是从尾部開始查找。当查找有空暇的缓存块时,数据库就会把查到的数据写入到这个空暇缓存中。
2、若数据库在查询的时候。首先查到的是脏缓存的话,则会把这个脏缓存移动到DIRTY列表中。然后再继续查询。直到查询到合适的空暇缓存块为止(查询的时候数据发生变动)。
3、若数据库在LRU列表中,从尾到头查了一遍(忽略oracle的查找算法)。没有找到空暇缓存块,或者尽管有空暇缓存块,可是其容量不符合要求时,数据库就会临时结束这一次查找。然后,系统就会触发数据库写进程,把DIRTY列表中的脏缓存块写入到数据库中去。已经被写入到数据库文件里去的脏缓存块将又被数据库标记为空暇缓存块。并插入到LRU列表中。当数据库运行完成这个动作之后。数据库又会对LRU列表进行搜索,找到合适的数据快速空暇缓存之后,就会把读取的数据写入到这个空暇缓存中。

脏缓冲区
  如果缓冲区存储的块和磁盘上的块不一致,该缓冲区就叫做“脏缓冲区”,脏缓冲区最终会由数据库写入器(DBWn)写入到磁盘中去。
  
数据库写入器(DBWn)
  数据库写入器是Oracle的一个后台进程,所谓后台进程是相对于前台进程(服务器进程)来讲的。DBWn的"n"意味着一个实例是可以有多个数据库写入器的。
  作用:简而言之,DBWn的作用就是将变脏了的缓冲区从数据库缓冲区缓存中写入到磁盘中的数据文件中去。
  
  数据库缓冲区缓存这块内存区域和数据库写入器这块是比较重要的概念,别的数据库产品像mySql也都有对应的实现,只不过叫法不一样罢了。了解这块的时候,要时刻意识到会话是不会直接更新磁盘数据的,会话的更新,插入,删除包括查询等都是先作用到缓冲区上,随后,DBWn会将其中的脏缓冲区转储到磁盘上去。 
  DBWn什么时候写入?
DBWn是个比较懒的进程,它会尽可能少的进行写入,在以下四种情况它会执行写入:

a.没有任何可用缓冲区(不得不写)

b.脏缓冲区过多

c.3秒超时(最晚3秒会执行一次写入)

d.遇到检查点,即checkPoint(检查点),检查点是个Oracle事件,遇到检查点,DBWn会执行写入。比如实例有序关闭的时候会有检查点,DBWn会将所有脏缓冲区写入到磁盘上去的,这很容易理解,要保持数据文件的一致性。
 注意:

从上述DBWn的几个写入时机,我们能意识到,DBWn的写入不是直接依赖于会话的更新操作的。不是一有脏缓冲区,它就执行写入。而且,DBWn执行写入跟commit操作也没有任何关系,不要以为commit操作的影响结果会实时流入到磁盘中去。

DBWn采用极懒算法进行写入,原因我们应该要清楚:频繁的磁盘IO对系统的压力很大,如果DBWn很积极地去写入磁盘,那对系统性能的影响就太大了,换个角度想,如果DBWn很勤快的写磁盘,那么数据库缓冲区存在的意义也就不大了。

当然,讲到这儿,我们可能会意识到一个问题,DBWn如此懒地进行数据转储,如果在某一时刻,数据库缓冲区缓存内存在着大量的脏缓冲区(生产环境中,这是常态),也就是有大量的未commit和已commit的数据还在内存中,没有持久化到磁盘中,然后突然系统断电了,这种情况下,数据是不是就丢掉了?数据当然不会丢失,这就引出了重做日志(redo log)的概念,接下来,我们就来谈谈对应重做日志的内存结构和后台进程。

SGA–日志缓冲区

当我们执行一些DML操作(insert,update,delete),数据块发生改变了,产生的变更向量则会写入到重做日志文件中去。有了这些记录,当系统由于断电等因素突然宕掉,数据库缓冲区缓存内的大量脏数据还没来得及写入到数据文件中去,在重新启动的时候,会有一个实例恢复的进程,在此过程中就应用了重做日志记录来使数据保持一致;或者数据库遭遇了物理损坏,比如磁盘损坏了,此时可以通过Oracle的备份恢复工具(如RMAN)进行数据恢复,原理就是 提取备份集–>应用重做日志文件中的变更记录。
 日志缓冲区
日志缓冲区是一块比较小的内存区域,它是用来短期存储将写入到磁盘中的重做日志文件中的变更向量的。

日志缓冲区存在的意义依然是为了减少磁盘IO,减少用户的等待时间,试想下,如果每一次用户DML操作都要进行等待重做记录被写入到磁盘中去,体验会有多差劲。

日志写入器(LGWR)
顾名思义,日志写入器(LGWR)就是把日志缓冲区内的内容写入到磁盘的重做日志文件中去,相比数据库写入器(DBWn),日志写入器就勤快多了。

以下三种情况LGWR会执行写入:
a.commit时写入
  前面提过,DBWn的写入和commit没有任何关系,如果commit时数据库没有任何记录,那数据就真的丢失了,Oracle 的重做日志就是为了保证数据安全而存在的,commit时,会话会先挂起,等待LGWR将这些记录写入到磁盘上的重做日志文件中,才会通知用户提交完成。所以,LGWR在commit时执行写入,是为了确保事务永不丢失。

b.日志缓冲区的占用率达到1/3。

c.DBWn要写入脏缓冲区前

这个写入是为了数据回滚考虑的。DBWn完全可能写入还没提交的事务(参照上面提到的写入时机),那如何保证事务回滚呢?

首先要知道,DBWn除了写入实际的数据,还会写入撤销数据,简单说,事务回滚需要撤销数据,在写入撤销数据前,会先写入针对撤销数据的日志记录(有点绕),若用户要进行事务回滚,就可以应用这些日志记录来构造撤销数据,然后进行回滚。

我们对这两块最重要的内存区域和对应的后台进程做个总结:

数据库缓冲区缓存和日志缓冲区都是为了提高性能,避免频繁IO而存在的。日志缓冲区相比数据库缓冲区缓存要小的多,并且不能进行自动管理,对于日志缓冲区的修改需要重启实例,数据库缓冲区缓存可进行自动管理。作用在数据库缓冲区缓存上的DBWn进程,为了避免频繁的磁盘IO导致系统性能下降,会尽可能少地执行写入,且DBWn的写入和commit操作没有任何关系;

而作用在日志缓冲区上的LGWR进程,则会非常积极地进行写入,一般情况下,它几乎是实时地将重做日志记录转储到磁盘中去。LGWR是Oracle体系结构中最大的瓶颈之一。DML的速度不可能超过LGWR将变更向量写入磁盘的速度。

我们在来看下其他的内存区域和后台进程
**

SGA–共享池

**
shared pool
它的主要作用是缓存SQL语句以及SQL语句的执行计划。查询一个SQL语句分为解析–执行–取数据
shared pool主要作用在解析阶段

共享池是最复杂的SGA结构,它有许多子结构,我们来看看常见的几个共享池组件:

**1.库缓存(library cache):**库缓存这块内存区域会按已分析的格式缓存最近执行的代码(执行计划),这样,同样的sql代码多次执行的时候,就不用重复地去进行代码分析,可以很大程度上提高系统性能。
  硬解析:一条语句进入库缓存中如果没有发现执行计划,那么就会发生硬解析
   硬解析流程:判断SQL语句语法有没有错误,然后在判断SQL中的表或者视图有没有权限,存不存在。还要去判断这表SQL语句怎么执行(选取最优执行方案),最后生成执行计划。一条SQL语句有多种执行方案,有的执行方案消耗资源大,执行快,有的慢,消耗的资源多,oracle要在这些执行方案里面挑选出一条最优的作为执行计划。这是硬解析里面最重要,消耗资源最大的一步。
  软解析:如果有会进行软解析
   软解析流程:判断SQL语句语法有没有错误,然后在判断SQL中的表或者视图有没有权限,存不存在。软解析没有挑选执行计划这一步。
   所以在实际环境中,我们希望软解析越多越好,不管软解析还是硬解析都需要查询对象的信息,权限的信息等等,这些信息都是存在在数据字典里面的。他们都会频繁的访问数据字典,为了提高速度,优化,oracle将数据字典里的信息也放在了共享池中,共享池的数据字典缓存(row cache)

SELECT * FROM v$sysstat WHERE NAME LIKE 'parse%';

库缓存中的内存块也是在链上,但是不是按照free空间的排列方式排的,而是按照sql语句中的字母转换成ASCII值经过运算得到了一个数字编号,根据编号挂到相应的链上。当有想用的SQL语句时,oracle只需要解析成相应的数字编号,然后锁住对应的编号链,通过遍历找到对应的块,然后进行软解析。所以说free空间取得块的操作只有硬解析才会用
  **2.数据字典缓存(row cache):**存储oracle中的对象定义(表,视图,同义词,索引等数据库对象),这样在分析sql代码的时候,就不用频繁去磁盘上读取数据字典中的数据了
  **3、pl/sql区:**缓存存储过程,函数,触发器,等数据库对象,这些对象都存储在数据字典中,通过将其缓存到内存中,可以在重复调用的时候提高性能。
  4、free 空闲空间
   free空间内存里面是一个一个的小的内存块,并且由一个一个的链将内存块连接起来,两个链之间挂的内存块大小不一样
   比如,一个链上挂的内存块是在1-10k的大小,下一个是10-20k的,这样越来越大。当一个SQL语句或者执行计划需要解析,会根据解析需要的内存大小在free空间相应的链上取下一个内存块,将SQL语句或者执行计划写入进去,然后放到库缓存中去。而如果没有相同的内存大小,free会拿出个大一些的内存块,然后分成两块,一块分成相应大小供解析使用,另一块放在相应范围的链上。只有硬解析需要在free里面获取内存块
   而且在硬解析获取内存块,产生的小的内存块碎片,如果发生了大量的硬解析,我们的free空间里就会有很多的小的内存块,这个时候可能free内存还有很多,但是由于解析的语句用的的内存在free中没有了。就会造成解析失败。oracle就会报一个错误:ora-4031错误
   链:有两个特点一是把内存串起来,二是遍历,从链的第一个然后依次找,知道找到需要的内存块
   内存里面运用了大量的链

SELECT count(*) FROM x$ksmsp  --查询内存块数量

如何解决ora-4031错误
1、alter system flush shared pool;–执行之后清空所有的库缓存和字典缓存。清空后以后在执行的语句都会发生硬解析,但是执行完后可以解决ora-4031错误 但只能治标不治本
2、设置shared pool 的大小也可以解决4031错误,我们只能设置shared pool的大小,而下面的库缓存,字典缓存由oracle自己设置,我们无法维护。而在我们设置共享池的大小时,有两个参数,非常重要
 查看总的SGA大小
 show parameter sga_target
 show parameter sga_max_target
 设置shared pool 大小 alter system set shared_pool_size = 150m scope =both;
 查看分配的各池的大小

select component,current_size from v$sga_dynamic_components;

sga_target 是动态的设置大小,设置完直接生效,而sga_max_target 是静态的,设置完需要重启数据库,sga_max_target是制约sga_target存在的,因为如果我们在设置sga_target的大小时,如果不小心设置的过高,这样会把其他的内存都用来充当SGA的空间,这样会导致系统直接挂起,很可能会导致系统死机,数据文件丢失等严重后果,而sga_max_target的存在限制了这一问题,我们可以在sga_max_target中设置一个大小,当设置sga_target的大小时,大小就会不允许超过sga_max_target设置的大小。
3、 共享可以解决占用大量空间,发生硬解析出现空间都是碎片造成4031错误的问题,共享必须执行的语句完全一样(空格也不行),所以要统一书写风格。对于格式一样,条件不一样的语句,可以使用绑定变量解决。
4、在共享池里面除了 上面的free,库缓存等之外,还有一个保留区的概念,这个空间只是用来缓存大对象,也就是说,如果我们执行的一条语句的大小超过了保留区的范围,那么服务器进程就不会去free空间里面找内存块,而是直接去保留区中,这样也能减少4031错误的产生。

**

SGA–大池:

大池是个可选的内存区域,前面我们提到专有服务器连接和共享服务器连接,如果数据库采用了共享服务器连接模式,则要使用到大池;RMAN(Oracle的高级备份恢复工具)备份数据也需要大池。

**

SGA–JAVA池

**
Oracle 的很多选项使用java写的,Java池用作实例化Java对象所需的堆空间

**

SGA–流池:

**
从重做日志中提取变更记录的进程 和 应用变更记录的进程会用到流池(如实例不正常关闭,譬如断电导致实例关闭,在重启时,Oracle会自动执行实例恢复过程,在此过程需要提取重做日志记录和应用重做日志两个动作)

以上列举了Oracle常见的内存结构,要注意的是,上面列举的内存区域,除了日志缓冲区是固定的,不能动态调整也不能进行自动管理外,其他内存区域都可以进行动态调整,也可以进行自动管理。

在说说Oracle 的几个后台进程(DBWn和LGWR较重要,前面已做了了解,在此不再赘述)

SMON(System Monitor):安装和打开数据库,实例恢复也是由此进程完成的

PMON(Process Monitor):进程监视器,主要监视服务器进程。前面提到过,专有服务器体系模式下,用户进程和服务器进程是一对一的关系,如果某个会话发生异常,PMON会销毁对应的服务器进程,回滚未提交的事务,并回收会话专有的PGA内存区域。

CKPT(Checkpoint Process):CKPT负责发起检查点信号,手动设置检查点的语法:

SQL>alter system checkpoint;

检查点可强制DBWn写入脏缓冲区,当数据库崩溃后,由于大量脏缓冲区未写入数据文件,在重新启动时,需要由SMON进行实例恢复,实例恢复需要提取和应用重做日志记录,提取的位置就是从上次检查点发起的位置开始的(检查点之前的数据已经被强制写入到数据文件中去了),这个位置称为RBA(redo byte address),CKPT会不断将这个位置更新到控制文件中去(以确定实例恢复需要从哪儿开始提取日志记录)。

MMON(Manageability Monitor)
  数据库的自我监视和自我调整的支持进程。实例在运行中,会收集大量有关实例活动和性能的统计数据,这些数据会收集到SGA中,MMON定期从SGA中捕获这些统计数据,并将其写入到数据字典中,便于后续对这些快照进行分析。(默认情况,MMON每隔一个小时收集一次快照)

ARCn(Archiver)  归档进程,这个进程是可选的,如果数据库配置为归档模式,这个进程就是必须的。所谓归档,就是将重做日志文件永久保存(生产库一般都会配置为归档模式)到归档日志文件中。归档日志文件和重做日志文件作用是一样的,只不过重做日志文件会不短被重写,而归档日志文件则保留了关于数据更改的完整的历史记录。
根据以上理解,配合内存进程交互图,深入理解

在这里插入图片描述

**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值