1、专用连接与共享连接1、大部分连接使用专用连接专用连接的工作过程1、用户在本地启动一个用户进程,例如SQLPLUS2、用户进程连接数据库,数据库服务器端启动一个服务器进程对应这个用户进程,这个用户进程输入的任何命令,服务器进程都会代理用户进程去执行命令,然后返回结果给用户进程3、用户进程终止、服务器进程随之终止共享连接的工作过程1、DBA可以定义服务器进程的个数2、启动数据库的时候,预先启动共享服务器进程3、比较少见Oracle的连接与会话三种连接类型1、本机登陆:采用内部通信机制进行连接2、C/S模式:用户通过客户端的ORACLE组件连接ORACLE数据库3、B/S模式:用户客户端没有ORAC
2、LE组件,用户通过IE与应用服务器建立连接然后在应用服务器上预先建立的连接池中挑选连接通道一个本地连接用户进程为用户进程创建的服务器进程,这个服务器进程使用的协议是beq(不是tcp),本地连接深入shared pool解析SQL语句、生成执行计划、解析SQL语句生成执行计划中间考虑的因素很多,包括访问的对象的存在、权限、等等执行SQL语句解析的过程是一个耗费资源的过程,随着用户的并发数量的增加。数据库的性能也会降低的很快。ORCLE对解析的执行1、ORACLE将SQL语句分成为两个部分静态部分+动态部分2、静态部分SQL 语句的关键词所涉及的表名称、列名称、等3、动态部分字面值(表里面的表数
3、据)例如 where name=xkj那么where name是静态部分、xkj是动态部分静态部分是有限的、动态部分是无限的在实际中,不同的SQL语句的静态部分的重复率非常的高、动态部分导致了SQL语句的千变万化实际上,动态部分对SQL语句的解析的影响可以忽略不计,主要是静态部分ORCLE将解析过的SQL语句缓存在shared pool中,碰到相同的SQL语句再次执行的时候,ORACLE直接使用已经解析过的执行计划。Shared pool中缓存的内容包括1、SQL语句2、执行计划3、PL/SQL代码4、PL/SQL机器码等通过使用绑定变量,用来提高SQL语句的缓存命中率在上面的SQL语句中,使
4、用了绑定变量n1,在解析的时候,使用的绑定变量。执行的时候,将字面值传入语句中。因此这样SQL语句的命中率将会提高。使用绑定变量是一个很好的思路。这条语句没有使用绑定变量,因此命中率会降低。我们的建议1、认识SQL的解析解析时使用绑定变量执行时将字面值传入绑定变量因此相同的绑定变量,不同的字面值,执行一次解析2、在SQL语句中,更多的使用绑定变量、特别是大型的复杂SQL查询Shared pool细分1、库缓存最近执行的SQL语句、存储过程、函数、解析树、执行计划最活跃部分2、数据字典缓存SQL执行过程中涉及的数据字典Shared Pool的内存结构Shared pool由许多的内存块组成,这些
5、内存块称为chunk1、chunk是shared pool中内存分配的最小单元(类似于extent)2、一个chunk在内存中是连续的Chunk的分类1、free:chunk中没有有效的对象,可以不受限制的分配如果用于存放和SQL相关的数据,那么chunk就属于 library cache,如果用于存放数据字典,那么这个chunk就属于dictionary cache2、recr:recreatable,chunk里面包含的对象可以被临时性的移走,如果需要,可以重建,例如共享SQL语句3、freeabl:session用过这个trunk,里面存放的对象数据是session在处理过程中产生的,没
6、有办法重建,这点不同于recr。因此这个trunk不能被临时性的移走。但是在合适的时间段可以被释放。4、perm:permanent,chunk中包含永久性的对象,但是大型的permanent类型的chunk中可能包含可用空间,需要的时候,这些空间可以被释放Shared pool中的每一个chunk在视图x$ksmsp中都有一条记录Shared pool中chunk的分配1、shared pool中的chunk的大小是不一样的,但是肯定是连续的2、因为chunk是分配的最小单元,因此session需要给对象分配空间的时候,会以chunk为单位进行申请3、可用的chunk(free)会形成一个链
7、表,便于进行分配的时候,可以通过遍历链表寻找到可用的适合的chunk,链表是chunk进行组织和管理的一种方式4、一个可用的chunk链表是一个bucket,shared pool中会有很多的bucket,不同的bucket中的chunk的大小不同,一般是随着bucket编号的增加,bucket的大小是增长的5、当需要从shared pool中寻找chunk的时候,首先会定位一个bucket,然后遍历bucket,寻找最合适的chunk如果chunk的空间比需要的空间大,那么这个chunk就拆分成两个,一个被分配、一个成为free,重新挂接到这个bucket上。6、在寻找chunk的过程中,如
8、果一个bucket中没有合适的chunk,接着寻找另外一个非空的bucket,如果所有的bucket中都没有合适的chunk,那么就从rec类型的链表中释放一部分的空间7、shared pool中所有类型的chunk都是以链表的方式进行管理的 只有rec类型的chunk能够被释放空间,即使释放了空间,这些空间可能都不是连续的,都是一些很小的chunk,这样可能形成这样一种情况,shared pool中是大量的非常小的chunk,这样在寻找chunk的时候,也很难寻找到合适的trunk 同时因为free chunk数量非常的多,因此在分配chunk的时候,就会占用大量的时间,因为对bucket进
9、行扫描、管理、分配的时候,需要获得shared pool latch,在扫描free chunk的时候,占用太多的时间,自然会发生latch争用的情况,原因就是因为大量的小的free chunk的情况 9i以前,经常出现shared pool latch的争用的情况,就上面的原因 从9i开始,对这种情况进行了改变,shared pool争用的情况就少多了注意:如果在shared pool中出现了大量的小的free chunk,就会出现share pool latch争用的情况,即使增加共享池的大小,这个问题随着时间还是会出现的。有一个错误是ORA-4013,原因是在shared pool中没有
10、找到足够尺寸的chunk。关于shared pool有两个问题1、shared pool latch的争用问题2、ORA-4013错误在shared pool中有一块保留区域,通过参数shared_pool_reserved_size设置,默认是shared pool空间的5%。对于非常大的对象,一般从这个区域中分配空间。这个区域中的chunk不会挂接到普通区域的链表中,普通区域的chunk也不会挂接到这个区域的链表中这是一块独立管理的区域这个参数反映了无法从保留区域获得足够大空间的chunk的总次数,尽量让这个参数为0.如果大于零,需要增加此区域大小Library cache用户提交的SQL
11、语句、SQL语句相关的解析树、执行计划、用户提交的PL/SQL代码块为了管理这些对象而建立的一些控制结构用户提交SQL语句或者PL/SQL以后,在library cache中会生成一个可执行的对象这个可执行对象叫做游标(不同于SQL语句中的游标)对于所有的进程来说,这些可执行对象是共享的Hash 算法Oracle在内部管理中大量的使用到了hash1、使用hash的目的就是为了快速查找和定位对数值进行hash运算,产生一个索引号,然后根据索引号将数值放置到相应的hash bucket中去根据hash运算的法则,会产生多个索引号,每一个索引号对应一个hash bucket(一个数值列)我们在寻找数
12、值的时候,将搜寻的数值进行hash,产生一个索引号,那么这个数值一定在这个索引号对应的 hash bucket中,于是直接跳转到这个hash bucket中进行遍历。这样我们定位数据的时候,就能够大大的减少遍历的数量。举一个hash的例子1、假设我们的数值列表最多有10个元素,也就是有10个hash bucket2、那么定义hash算法为n MOD 103、所有的数值都可以通过上面的算法,分配到相应的hash bucket中4、当寻找数值的时候,将数值进行hash后得到索引号5、根据索引号进入相应的hash bucket中去6、遍历这个hash bucket,将数值找到库缓存中就是使用hash
13、 bucket来管理的1、首先根据shared_pool_size指定的尺寸来自动计算hash bucket的个数2、每个hash bucket后面都串联着多个句柄句柄描述了library cache里面的对象的一些属性,包括名称、标记、指向对象所处的内存地址的指针Hash bucket句柄NameNamespace.FlagHeap 0(对象指针)Heap 0 1、sql语句设计的对象的地址2、由多个chunk组成,各个chunk地址上可以不连续一条SQL语句进入将SQL文本转化为ASCII值对ASCII等参数进行hash函数的运算得到一个数值、就是hash bucket的号码将对象句柄放进
14、相应的hash bucket中去进程要处理某个对象,例如一条SQL语句对语句进行hash,得到一个编号进入hash bucket中进行扫描1、该对象句柄存在,ok,直接使用2、该对象句柄存在,对象被交换出内存、装载对象3、句柄不存在,重新构建一个对象,挂在到hash bucket上通过视图v$db_object_cache可以显示library cache中那些对象被缓存,以及对象的尺寸。当然一些工具可能更加直观的得到这些信息。我们建议大家要熟练的掌握一些工具,通过这些工具熟练地对数据库的各个地方进行查看。字典缓存区1、存放数据字典缓存信息我们不需要对这个缓存区进行过多的关注注意没有参数具体的
15、划分library 和dictionary所占的比例,我们只能控制shared pool的大小,chunk可能被分配到其中的任何一个中去,也可能一会在这个、一会到另外一个。SQL的解析过程用户识别的是SQL语句,oracle可以执行的是代码,这个转换过程叫做解析解析分为硬解析和软解析,SQL语句第一次解析时必须进行硬解析硬解析1、客户端发出一条SQL语句,SQL语句进入共享池该SQL语句以及相关的辅助信息组成游标2、对SQL语句进行hash运算,得到一个hash值,转入相应的bucket中去3、对bucket进行遍历,查找是否存在这条SQL语句4、如果不存在这条语句1、获得shared poo
16、l latch,然后在shared pool中进行chunk链条的遍历,找到合适的chunk,之后释放shared pool latch,chunk进入library cache中2、硬解析开始硬解析过程1、对SQL语句进行语法的检查。如果有错误,那么就退出解析过程2、到数据字典中校验SQL语句所涉及的对象和列是否存在,如果不存在,退出解析过程,这个过程会加载dictionary cache3、对对象进行名称转换,同名词等要转换成实际的对象,转换失败就退出解析4、检查发出SQL语句的用户是否具有访问sql语句里面所引用的对象的权限,无权限就退出解析过程4_5 还要在shared pool 中获
17、得 free bucket 中的空的chunk,及相关latch5、通过优化器创建一个最优的执行计划,这个过程会根据数据字典里面记录的对象的统计信息,来计算最优的执行计划,这一步涉及的运算量很大,最耗CPU资源,根据对象统计信息和动态采样6、该游标所产生的执行计划、sql文本等装载进 library cache的heap中在解析的过程中,进程会一直持有library cache latch,一直到硬解析结束游标1、硬解析结束以后,产生两个游标父游标和子游标父游标里面包含的信息包括SQL文本和优化目标session打开该游标以后,就会锁定父游标所有的session都关闭该游标以后,锁定才能够释放
18、父游标在被锁定的时候,不能被交换出内存父游标交换出内存、子游标也会被交换出内存子游标被交换出内存、父游标可以不被交换出内存因为一个父游标可能会有多个子游标子游标包换所有的信息:执行计划、绑定变量等子游标随时可能被交换出内存Oracle根据父游标的信息可以构建出一个子游标,这个过程叫reload上面的语句确定reload的比率,我们希望低一些最好。一般的情况是父游标不会被交换出内存,子游标会被交换出内存。为什么会产生父游标和子游标呢?1、一个父游标可以对应多个子游标子游标的个数可以从视图v$sqlarea中的version_count字段中体现出来每个具体的子游标则全部在视图v$sql中体现产生
19、子游标的一些情况举例1、具体绑定变量的值与上次绑定变量得值有较大的差距例如上次是6位,现在是200位2、sql语句完全相同,但是所引用的表属于不同的用户等等3 变量类型不一样软解析1、硬解析是一个完整的解析过程如果解析过程中去掉一个或者多个步骤的话,这样的解析叫做软解析2、在bucket中找到了sql语句,就会进行软解析,因为如果没有找到,那么说明这个语句是第一次执行,第一次执行肯定是硬解析软解析的三种类型1、某个session发出的SQL语句与library cache里其他session发出的SQL语句相同,解析可以省略5和6,但是2、3、4还是需要执行的2、某个session发出的sql
20、语句是这个session之前发出的曾经执行过的语句,那么2、3、5、6可以省略,但是4不能省略,因为中间可能发生过grant等操作3、设置了初始化参数session_cached_cursors时,当某个session第三次执行相同的sql语句时,这个sql语句的游标信息会转移到该session的PGA中去,这样以后可以直接在session的PGA中寻找SQL,提高了效率(lib cache 中寻找时候需要获得latch),但是内存的消耗会很大很多的情况会导致SQL不被共享1、SQL文本大小写不一致2、SQL语句的绑定变量的类型不一致3、SQL涉及的对象属于不同的schema4、SQL的优化器
21、不一致添加了提示、修改了optimizer_mode参数等等等在v$sqlarea中,我们找到了父游标,并且知道父游标只有一个子游标。发现有了两个父游标两个子游标的地址不同(一定不一样)两子游标的父游标也不一样说明两次执行的SQL语句没有共享因此SQL语句不共享的因素还是很多的,对于开发人员来说,还是要引起注意。Shared pool 的大小设置1、不同的系统需要不同的值2、不要太大、不要太小,无论大还是小,对性能都有影响通用的方法是1、设置一个初始值、让系统运行一段时间初始设置shared pool的大小是SGA的10%、不要超过1G2、对shared pool的使用情况进行观察和监控9i以
22、后,我们可以使用advisor进行监控,然后查询找到合适的值3、得到一个比较合理的值4、继续观察、根据负载情况的变化,需要相应的调整参数5、shared pool不要设置1G以上要使用advisor,需要设置参数statistics_level参数,如果为typical或者all就可以监控,如果是basic,就不能监控SQL SELECT shared_pool_size_for_estimate SP,estd_lc_size EL,estd_lc_memory_objects ELM,estd_lc_time_saved ELT,estd_lc_time_saved_factor as E
23、LTS,estd_lc_memory_object_hits as ELMO FROM v$shared_pool_advice;如果shared pool这么大的话在这个shared pool值下面,指标值是这些当这个参数是1的时候,再继续加大shared pool的值的意义不是很大,因此这个值很重要当前系统没有什么负载,只要48M就够了我们的系统设置了300M保留区使用了默认值(shared pool的5%)SQL SELECT Shared Pool component,shared_pool_size_for_estimate estd_sp_size,estd_lc_time_sav
24、ed_factor parse_time_factor,CASE WHEN current_parse_time_elapsed_s+adjustment_s 0 THEN 0 ELSE current_parse_time_elapsed_s+adjustment_s END response_time FROM(SELECT shared_pool_size_for_estimate,shared_pool_size_factor,estd_lc_time_saved_factor,a.estd_lc_time_saved,e.VALUE/100 current_parse_time_el
25、apsed_s,c.estd_lc_time_saved-a.estd_lc_time_saved adjustment_s FROM v$shared_pool_advice a,(SELECT*FROM v$sysstat WHERE NAME=parse time elapsed)e,(SELECT estd_lc_time_saved FROM v$shared_pool_advice WHERE shared_pool_size_factor=1)c);不同的shared pool尺寸下,具体的响应时间因为系统负载很小,因此因子总是为1,响应速度随着空间的增加没有什么变化。注意:如果
26、是8i或者更老的版本,那就只能依靠观察系统性能了。Log buffer数据库里面的数据很重要,为了避免一些数据的丢失,例如掉电、崩溃、bug、磁盘损坏等恶劣的情况Oracle采用了log的机制,伴随着log机制,oracle提供了log buffer技术Oracle数据库的日志:里面记录的不仅包括DML、DDL语句,还包括很多的信息、例如索引、回滚等,依靠这些信息,Oracle能够轻松的实现恢复如果记录变化1、逻辑记录方式使用描述性的语句来记录整个的变化过程一个update被记录为两条,一个delete和一个insert节省日志的记录空间,对于每一个操作,只需要分解为几个操作即可恢复操作非常的
27、消耗资源,因此恢复速度很慢慢的一个很重要的原因是还需要查找数据,确认数据块的位置2、物理的记录方式将每一个数据块改变前的镜像和改变后的镜像都记录下来恢复速度很快,但是非常的占用磁盘空间因为记录的是数据块,因此恢复的时候直接根据数据块的物理地址进行定位即可,这是速度快的根本的原因 Oracle如何记录变化采用了逻辑和物理结合的方式1、Oracle针对每一个数据块,记录了插入某个值或者删除某个值的描述性语句例如update影响了100个数据块,针对每一个数据块,都记录了一对delete和insert,共有100对这样的数据每一对描述性的语句中,都记录了相关的数据库的物理地址这样节省了空间、同时在数
28、据库应用变化时,速度也足够的块Oracle开辟了log buffer空间,当需要将数据写入联机重做日志文件组的时候,Oracle会启用LGWR进程单位是字节这个缓冲区会被划分为块以后使用,块的大小和操作系统的块大小一致1、Log buffer中的数据块对应于log中的数据块,根据顺序,buffer中的日志块有序的写入到log中2、联机重做日志文件组中的成员互相之间是完全相同的3、每个数据库至少两个日志文件组、日志组之间会进行循环性的切换4、联机重做日志文件在写满以后,可以选择归档为归档日志成员强烈建议在生产环境中使用归档模式日志的重要性1、只有将被修改的数据块的日志信息写入了联机重做日志文件中
29、以后,该被修改的数据块才可以说是安全的2、LGWR负责将log buffer中的数据写入log中触发LGWR进程将日志缓冲区中的日志信息写入联机重做日志文件的条件包括1、两种情况用户发出commit或者rollbacklog buffer没有可用空间2、每隔3秒3、DBWr进程启动的时候(需要将buffer cache中的数据写入到数据文件中),如果发现脏数据块所对应的重做条目还没有写入到联机重做日志文件中,DBWr会触发LGWR进程并等待LGWR进程写完才会继续4、日志信息的数量达到整个log buffe的1/3时,触发LGWR5、日志信息的数量达到1MB时,触发LGWRLog buffer
30、的内部结构日志中到底包含哪些信息?日志的结构到底是什么?1、Oracle记录数据库变化的最小单位是改动向量(change vector)也就是Oracle使用一个个的改动向量来描述数据库的变化Oracle不可能使用更小的单位来记录数据库的变化2、改动向量的内容包括被改动的数据块的版本号事务操作代码被改动的数据块的地址注意:每一个数据块都有一个版本号数据块可以包括表或者索引、也可以属于回滚段,临时段不会生成改动向量 当多个改动向量按照先后顺序组合在一起,从而完成对数据库的一次改动时,Oracle称这组改动向量为重做记录(redo record)。重做记录用来描述对数据库的一次原子改动,当应用改动
31、中的向量的时候,要么全部成功、要么全部失败 一个事务至少产生一个重做记录,也可能产生多个重做记录 事务是恢复的最小单元,要么恢复整个事务、要么回滚整个事务改动向量重做记录事务多个改动向量组成一个重做记录多个重做记录组成一个事务一个update的流程1、回滚段事务表发生了变化,产生改动向量回滚段事务表是位于回滚段段头的一个表2、回滚段数据块发生了变化,产生改动向量3、数据表的数据块发生改变,产生改动向量上面的重做记录中包括三个改动向量4、如果有索引,那么索引数据块会发生改变,产生改动向量这是第二个重做记录Commit或者roll back以后,回滚段事务表发生改变,产生改动向量这是第三个重做记录
32、一个事务包括了三个重做记录、多个改动向量Log buffer的设置1、过小产生过多的log buffer space等待事件2、过大没有意义,因为LGWR不停的刷新理想设置log buffer 的大小注意:log buffer空间的设置不是什么大的问题,相对简单,我们主要是理解日志的工作过程日志缓冲区的大小的估计公式1.5*(平均每个事务所产生的重做记录的大小)*(每秒提交的事务数量)1、总的事务量2、系统总共的运行时间因为运行不够一天,所以trunc以后出现0的情况。手工计算的出:10834秒所有的重做记录大小可以计算出平均每个事务所产生的重做记录的大小、每秒钟所提交的事务数量然后套用公式计
33、算出即可。数据库高速缓存区database buffer cache,简称buffer cache1、通过缓存从而减少I/O2、通过构造CR(consistent read)块,从而提供读一致性3、通过提供各种lock、latch机制,从而提供多个进程并发访问同一个数据块的功能无论是lock还是latch,都是对内存的锁定,当多个进程访问内存的某一个数据块的时候,就涉及到了锁的问题,对于任何一个内存组件来说,在一个多进程的环境中,都涉及到一个同时访问的问题,也就自然的涉及到了锁的问题。内存中的数据块通常称为buffer、数据文件上的数据块通常称为block,一个概念Buffer cache的内
34、存结构两个非常重要的概念:链表和hash算法1、链表是一种数据结构、将对象串联起来链表的最突出的一个特性就是可以遍历链表进行查找链表是为了组织数据的,组织的目的就是为了查找LRU链表是Oracle中比较有名的2、hash算法同前面讲到的Hash 链表Hash bucketBuffer headerHash chain数据块读取进入buffer cache,Oracle抽取数据块的头部,在内存中构造buffer header,将buffer header串成链表的形式,buffer header里面的指针指向buffer cache中数据块本身Oracle搜索数据块的时候,只需要在链表上搜索就可
35、以,然后根据指针读取bufferHash 链表Hash bucketBuffer headerHash chain对数据块的数据类型和数据块地址进行hash函数处理以后,放置到相应的hash bucket中去Hash bucket的数量是Oracle自己决定的注意:因为hash bucket里面使用的是链表的方式对buffer header进行管理,因此访问的时候采用的是从头到尾的遍历,因此我们希望链表短一些比较好Oracle使用buffer流程1、select或者DML发出以后1、首先解析SQL、根据执行计划执行2、寻找SQL数据块、确定bucket、遍历header3、如果在buffer中
36、没有数据库的buffer header4、发生IO,到物理文件中去读取数据块5、数据块进入buffer cache,发生了一系列的动作1、寻找buffer cache中的内存数据块2、如果有空白数据块,那么就分配一个数据块、同时将buffer header放置到buffer bucket中3、如果没有空白数据块呢?首先清楚几个概念1、脏数据块(dirty buffer):buffer cache中的内存数据块的内容被修改、导致和数据文件中的数据块内容不一致2、空闲数据块(free buffer):buffer cache中的内存数据块为空3、干净数据块(clean buffer):buffer
37、中的内容和数据文件一致4、钉住的数据块(pin buffer):当前正在更新的内存数据块5、数据库写进程(DBWR):后台进程、将脏数据块写入到磁盘上的数据文件中注意:空闲和干净数据块都属于可用数据块LRU链表LRU将可用的内存数据块的buffer header链接起来、形成LRU链表按照可用数据块的使用顺序,先被使用的buffer 挂在LRU的后面,后被使用的buffer放在LRU的前面当需要分配buffer的时候,可以到LRU上进行寻找,首先是寻找空闲的数据块,如果没有空闲的数据块,那么就优先使用LRU上后面的数据块如果发现数据块正在使用(select和DML都有可能),那么顺着链表继续寻
38、找如果数据块被修改过了,成为了脏数据块,那么这个数据块就会被从LRU上摘下来。如果扫描了一定数量的buffer以后,还是没有找到空数据块,那么就认为buffer太脏了,就会触发DBWR,进行一次清理空闲数据块和干净数据块还是有区别的大家理解的重点就是:LRU将可用的数据块顺序的链接起来,这样在分配buffer的时候,会比较的合理、速度也会相对的快一些在扫描buffer寻找数据块的时候,如果扫描一定数量以后,还是没有分配到buffer,那么就会触发DBWR针对LRU链表,存在一个latch:cache buffers LRU chain latchDBWn进程1、将脏的数据块写入磁盘随着内存的不
39、断增长,可能需要多个DBWR8i开始支持多个DBWR进程DBWR触发的条件1、当进程在LRU上扫描以查找可以覆盖的buffer header时,如果已经扫描的buffer header 的数量达到一定限度,触发DBWR2、如果脏数据块的总数达到一定的限度,触发DBWR3、发生检查点、触发DBWR4、每隔3秒启动一次DBWR安全高效的写脏数据块的解决方案CKPT、LGWR、DBWR进程互相之间合作,实现上面的解决方案LGWR用户进程修改内存数据块、在日志缓冲区中都会构造一个相应的重做条目(被修改的数据块在修改之前的值和修改之后的值)LGWR负责将这些条目写入到联机重做日志文件中,一旦写入到了联机
40、重做日志文件中以后,数据就是安全的LGWR负责维护系统完整性的任务、保证数据不会丢失实例突然崩溃、怎么办?Oracle是不一定会把提交的数据块写入数据文件的实例崩溃以后,必然会有一些已经提交但是还没有写入数据文件的内存数据块丢失实例启动以后,Oracle利用日志文件中记录的重做条目来在buffer cache中重新构造这些内存块,然后完成前滚和回滚日志文件有多个、里面的条目更是很多我们需要从哪个起点来开始往后应用重做条目呢?为了预防实例崩溃,Oracle需要不断的定位这个起点为什么需要定位起点?1、这个起点不能太靠近日志文件的头部、太靠近日志文件的头部意味着要处理很多的重做条目2、不能太靠近日
41、志文件的尾部(实时的尾部),太靠近日志文件的尾部意味着有很少的脏数据块需要写入到数据文件中,说明大量的脏数据块已经写入到了数据文件中,也就说明DBWR进程在此前频繁的写数据文件,显然这样造成的后果就是IO频繁,数据库性能低下起点的意义1、实例崩溃以后的重做条目如下ABC我们可以选择在A点,也可以选择在B点,也可以选择在C点选择A、B、C作为起点,进行实例崩溃恢复都可以如果选择A作为起点,那么说明起点A以前的重做条目对应的数据块的改变已经写入到数据文件中,我们只需要使用A以后的条目重新构建buffer cache同样对于B和C来说,都可以但是A可能太远、C可能太近,B相对好一些,Oracle是如
42、何来处理的呢?Oracle为了更好的定位起点(起点以前的不进行重做、起点以后的进行重做),引入了检查点的概念(一个进程叫做CKPT)这是一个后台进程检查点发生的时候,DBWR会将所有的脏数据块写入到数据文件中,检查点周期性的执行,我们就可以使用检查点作为起点。实例恢复的时候,寻找最后一个检查点的位置,作为起点进行恢复。相关概念1、buffer cache可能非常的大,因此寻找脏数据块可能耗费时间较长因此引入了检查点队列的概念检查点队列上串起来的都是脏数据块的buffer headerOracle寻找脏数据块的时候,使用的是是检查点队列脏数据块写入到数据文件以后,就会从检查点队列上摘除下来这样在
43、非常大的buffe cache下面,CKPT能够非常快速的定位脏数据库块文件队列(每个文件上一个检查点队列)文件队列上也是挂接着脏数据块的buffer header,不过所有的脏数据块都来自这个文件增量检查点增加了检查点启动的次数如果buffer cache很大,而且检查点时间比较长,那么实例恢复的时候速度就很慢。DBWR触发的条件中不仅仅是CKPT,在两个检查点之间,DBWR可能已经触发过DBWR执行检查点按时间应该发生检查点崩溃1、从上一个检查点开始恢复2、显然上一个检查点和DBWR之间的改变已经写入到了数据文件中,再次执行恢复的意义就是重复,造成效率低下(CKPT做的事情中包括:启动DB
44、WR、将起点记录到控制文件中)Oracle启用了增量检查点检查点队列和增量检查点检查点队列上的buffer cache是按照数据块第一次被修改的时间的先后顺序来排序的。越早修改的数据块的buffer cache排在越前面,数据块如果被修改了多次,在该链表上也只出现一次,而且检查点队列上的buffer header还记录了脏数据块在第一次被修改时,所对应的重做条目在重做日志中的地址,叫做LRBA(low redo block address)检查点队列重做日志条目最早被修改的数据块第一次被修改时所对应的日志条目在重做日志中的地址最早的脏数据块被修改时所对应的日志条目因为日志条目是顺序写的,因此后
45、面的所有的脏数据块对应的日志条目一定在 后面之前的所有日志条目对应的数据块一定已经写入到数据文件中了,之后的日志条目对应的数据块一定没有写入到数据文件中,这就是一个分界这条这个地址信息就存储在控制文件中,这也就是检查点信息,检查点信息就就是崩溃恢复的起点完全检查点和增量检查点1、完全检查点标识出buffer cache中所有的脏数据块以最高优先级启动DBWR进程将这些脏数据块写入数据文件触发条件(8i以后)1、alter system checkpoint2、除了shutdown abort以外的正常关闭数据库8i以前日志切换的时候,也会触发增量检查点触发条件1、每隔3秒2、日志切换2、增量检
46、查点找出当前检查点队列上的第一个buffer header,并将该buffer header上的LRBA,记录到控制文件中去如果是日志文件切换,8i以后触发的是增量检查点对于日志切换引起的增量触发,除了上面的操作以外,还会将这个增量检查点记录到所有的数据文件中如果发生实例崩溃,Oracle会到控制文件中找到检查点位置,然后跳转到日志文件的相应位置,从这个起点开始,取出重做条目进行处理小总结1、DBWn负责写检查点队列上的脏数据块2、CKPT负责记录当前检查点队列的第一个数据块所对应的重做条目在日志文件中的地址根据规则以及一些参数,DBWr计算出哪些脏数据块需要写入到数据文件中,这些脏数据块写入
47、数据文件以后,已经写入数据文件的数据块从检查点队列上摘除。增量检查点发生的时候,读取检查点队列上的第一个buffer header的LRBA,写入到控制文件中SCN是一个具体到千毫秒的时间戳。设置buffer cacheOracle 8i的设置参数是db_block_buffer表示buffer cache中所能够包含的内存数据块的个数Oracle 9i以后使用db_cache_size来设置该参数表示buffer cache的总量,可以使用字节、KB、MB为单位来设置Oracle10g引入了ASSM(Automatic Shared Memory Management)这样一个可以进行自我调
48、整的组件,只需要设置SGA_TARGET参数即可,再设置statistics_level为typical或all,则各个参数就可以根据系统负载情况和历史信息自动的调整各个部分的大小Oracle 8.0以后,提供了三种类型的buffer cache,分别是default、keep、recycle。Default是必须的,keep和recyle是可选的8i以后,设置三个池的参数分别是db_cache_size设置default池没有特殊指定buffer cache的放在里面db_keep_cache_size设置keep池经常访问的表放在里面db_recyle_cache_size设置recyle
49、池不经常访问的表放在里面,特别是大表设置不同类型的buffer cache的优化方法不是一个很高级的办法,尽量少用显然我们的数据库采用的是ASMM根据表的特性,设计表的时候,将表放置到不同的buffer pool中Oracle 9i开始,Oracle允许不同的表空间可以设置不同的blocksize,在设置不同的表空间的时候,需要设置不同的cache我们可以设置的不同cache size包括2、4、8、16、32默认的标准cache size是8KSystem表空间使用的就是标准数据块的大小Keep池和recycle池只能使用标准块大小,我们设置非标准的cache的时候,不能设置相应的keep和
50、recycle池,我们设置的keep和recycle池只能用于标准块。我们可以设置另外的四种类型,因为标准类型不需要设置。设置不同的表空间的意义1、不同的表空间之间进行传输的时候A库的表空间的标准数据块大小是8K,B库的表空间的标准数据块的大小是32K,A库的表空间传输到B库的时候,我们可以设置B库中的8K表空间,这样就可以直接传输2、调优目的OLTP数据库中,我们通常设置数据块的大小相对较小,例如8K、4K等OLAP数据库中,我们通常设置数据块的大小相对较大,例如32K、16K等设置这些参数对数据库的调优还是很有意义的。前面讲的问题中,一共涉及了这几个参数1、不同数据块的大小2K、4K、8K