试谈ORACLE的工作机制doc 82页正式版.docx
《试谈ORACLE的工作机制doc 82页正式版.docx》由会员分享,可在线阅读,更多相关《试谈ORACLE的工作机制doc 82页正式版.docx(128页珍藏版)》请在冰豆网上搜索。
试谈ORACLE的工作机制doc82页正式版
ORACLE的工作机制
体系结构
实例
Oracle运行的时候,在内存中会要开辟一个区间,这个区间主要是用于从磁盘(数据文件)中读出数据后的一个在内存的缓存和处理。
而处理这些数据的操作,需要有一些系统的后台进程,这些进行在Oracle数据库启动的时候,就开始运行,一直在响应前台的操作。
实际上,这一个区间(SGA)和这些后台进程合在一起,就称为实例。
实例是包括SGA区和后台进程两个部分的。
数据库启动执行若干动作,经历三个阶段,分别是未加载、加载和打开。
1、未加载(nomount)可以把数据库启动的这一阶段看作是Oracle实例的启动。
这种方式启动下可执行:
重建控制文件、重建数据库。
这一启动命令:
•读取数据库参数文件。
•启动所需的后台进程并按参数文件中的定义分配内存。
•将进展情况写入告警日志文件中。
2、加载(mount)在实例启动加载阶段,数据库参数文件中指定的控制文件被读取。
记住控制文件将数据库各部分联系在一起。
实例从控制文件中找到下列信息,然后将进展写入告警日志文件。
这种方式启动下可执行:
数据库日志归档、数据库恢复、重新命名一些数据库文件:
•所有数据文件和重做日志文件的名称和位置。
•数据库名。
•最新系统更改号(SCN)。
3、打开(open)包含在数据库中的每个联机数据文件在数据库打开前必须被同步。
在数据库打开阶段:
•所有联机数据文件的头与控制文件信息相比较。
•所有文件同步后,数据库打开。
当数据库关闭时,取决于它的关闭方式执行不同的任务:
•正常(normal)在所有的用户离线后发生的正常关闭。
•事务(transactional)事务关闭就是当所有的用户执行完当前的事务后,将用户从数据库上清除。
•立即(immediate)立即关闭就是从数据库清除所有当前用户之后,回退所有未完成的操作。
•异常(abort)异常关闭没有给数据库任何整理的机会。
这种方式关闭后需要实行崩溃恢复。
实例是数据管理的核心—它做所有的工作,而数据库存储所有的数据。
其他启动方式:
•startuprestrict
约束方式启动
这种方式能够启动数据库,但只允许具有一定特权的用户访问
非特权用户访问时,会出现以下提示:
ERROR:
ORA-01035:
ORACLE只允许具有RESTRICTEDSESSION权限的用户使用
•startupforce
强制启动方式
当不能关闭数据库时,可以用startupforce来完成数据库的关闭
先关闭数据库,再执行正常启动数据库命令
•startuppfile=参数文件名
带初始化参数文件的启动方式
先读取参数文件,再按参数文件中的设置启动数据库
•startupEXCLUSIVE
***************
一个Delete操作的流程:
1、检查语法、语义(V$ROWCACHE:
datadictionarycache),计算HASHVALUE,在session的UGA中进行匹配(session_cached_cursors),如果UGA中没有,在librarychache中匹配(librarychachelocklatch保护librarychachelock对地址堆的访问,而后librarychachepinlatch保护librarycachepin对librarycache中sql相关信息的访问)
2、根据执行计划读取数据:
cachebufferchainlatch保护能定位到bufferheader并pin住该块(如果没有bufferheader,就pin住某个空块(没有空块就产生freebufferwaits),并到数据文件中读取)。
如果此时有某个进程想访问该块,将产生bufferbusywaits。
3、在redologbuffer中记录delete操作的细节。
(包括回滚段前后镜像、数据块前后镜像)。
4、在相应回滚段段头的事务表中创建一个undo条目,把将要删除的记录创建前镜像,存放到UndoBlock中。
5、在BufferCache中的相应数据块上删除记录,并且标记相应的数据块为Dirty。
提交(COMMIT)
1.Oracle产生一个SCN
2.在回滚段事务表中标记该事务状态为commited
3.LGWRFlushLogBuffer到日志文件
3.如果此时数据块仍然在BufferCache中,那么SCN将被记录到BlockHeader上,这被称为快速提交(fastcommit)
4.如果dirtyblock已经被写回到磁盘,那么下一个访问这个block的进程将会自回滚段中获取该事务的状态,确认该事务被提交。
然后这个进程获得提交SCN并写回到BlockHeader上。
这被称为延迟块清除(delayedblockcleanout)。
内存
SGA(系统全局区、共享全局区)、PGA(进程全局区、私有全局区)
内存分配原则:
10%冗余内存,OSSYS进程(约1.6G),OSBUFFER(约0.8G),数据库连接消耗内存(每个连接约5~8M),PGA(每个连接约2M,V$PGA_TARGET_ADVICE),SGA
SGA
v$sgastat
注意showparametersga_max_size
Oracle的内存:
●软件代码区
●系统全局区
●进程全局区:
包含单个进程的数据和控制信息
●排序区
SGA中的Thefixedarea包含了数千个原子变量,以及如指向SGA中其它区域的pointers(指针)等小的数据结构.通过对fixedtable内表X$KSMFSV查询(如下)可以获得这些变量的名字,变量类型,大小和在内存中的地址.
thevariablearea是由largepool和sharedpool组成
Sharedpool中永久性的内存包含各种数据结构如:
thebufferheaders,processes,sessions,transactionarrays,theenqueueresources,locks,theonlinerollbacksegmentarrays,variousarraysforrecordingstatistics.其中大部分的SIZE是依靠初始参数的设置来确定的.这些初始参数只能在实例被关闭的状态下才能够进行修改.所以这里说的永久性是针对实例打开状态下的生存期而言.
Thevariablearea的在SGA中的SIZES就等于LARGE_POOL_SIZE,SHARED_POOL_SIZE和永久性的内存arrays的SIZE三者相加.
永久性内存arrays的SIZE=thevariablearea-(LARGE_POOL_SIZE+SHARED_POOL_SIZE).
数据缓冲区命中率
v$sysstat
这里命中率的计算应该是
令x=physicalreadsdirect+physicalreadsdirect(lob)
命中率=100-(physicalreads-x)/(consistentgets+dbblockgets-x)*100
通常如果发现命中率低于90%,则应该调整应用可可以考虑是否增大数据缓冲区
共享池的命中率
SQL>selectsum(pinhits-reloads)/sum(pins)*100"hitradio"fromv$librarycache;
hitradio
----------
99.809291
假如共享池的命中率低于95%,就要考虑调整应用(通常是没使用bindvar)或者增加内存
关于排序部分
SQL>selectname,valuefromv$sysstatwherenamelike'%sort%';
NAMEVALUE
--------------------------------------------------------------------------
sorts(memory)67935
sorts(disk)1
sorts(rows)7070
假如我们发现sorts(disk)/(sorts(memory)+sorts(disk))的比例过高,则通常意味着sort_area_size部分内存较小,可考虑调整相应的参数。
关于log_buffer
SQL>selectname,valuefromv$sysstat
2wherenamein('redoentries','redobufferallocationretries');
NAMEVALUE
--------------------------------------------------------------------------
redoentries2325719
redobufferallocationretries10
假如redobufferallocationretries/redoentries的比例超过1%我们就可以考虑增大log_buffer
如何在Linux上扩展SGA超过1.7G
共享池(SHARED_POOL_SIZE)
v$shared_pool_advice
ALTERSYSTEMFLUSHSHARED_POOL
HowtoKeepObjects--重点
使用DBMS_SHARED_POOL.KEEP过程来keepobjects,UNKEEP过程从sharedpool中移走pinnedobjects
executedbms_shared_pool.keep('address,hash_value');--keep该匿名块
共享池包括库高速缓存(librarycache)、数据字典高速缓存和服务器控制结构(例如数据库字符集)。
Oracle服务器用库高速缓存来提高执行SQL语句的性能;库高速缓存包括共享和专用SQL区。
共享SQL区包括SQL语句语法分析树和执行路径,而专用SQL区存储特定的会话信息,例如捆绑变量、环境和会话参数、运行堆栈和缓冲区等。
Softparse使用的资源包括CPU和librarycachelatchgets
Hardparse是指要解析的SQL没有在librarycache中,或者执行的时候发现解析过的SQL已经agedout,就是离开了librarycache,称为Librarycachemisses.使用的资源包括额外的CPU,librarycachelatchgets,以及sharedpoollatchgets.
专用SQL区在每个事务初始化时创建,在与专用SQL区相关的游标关闭时被释放。
一个用户会话能够一次打开的专用SQL区的数量由init.ora参数OPEN_CURSORS决定。
使用这两个结构,Oracle服务器能够重用一条SQL语句的所有执行的共同信息。
与此同时,可以从专用SQL区中查询执行的特定会话信息。
注意游标使用过程中并不关闭游标的应用会继续为应用分配越来越多的内存,部分原因是为每个打开的游标分配了专用SQL区。
库高速缓存中的专用SQL区可更进一步分为永久区和运行区。
共享池的大小取决于init.ora文件参数SHARED_POOL_SIZE,它是以字节为单位的。
你必须将这个值设得足够大,以确保有足够的可用空间来装载和存储PL/SQL块和SQL语句。
共享区经过长期装卸和卸载数据对象会产生许多碎片,如果在共享池中没有足够的连续空间用来装载目标数据,会产生错误。
解决这个问题的捷径是运行SQL命令ALTERSYSTEMFLUSHSHARED_POOL。
但是如果在数据库操作时,经常遇到共享池错误,你必须增大共享池
Librarycache 包含sharedSQLandPL/SQLareas(PL/SQL包括Procedures,Functions,Packages,Trigger,匿名PL/SQL块)
SizingtheLibraryCache
定义storedobject(packages,views等等)的内存需求;定义经常使用的sqlstatement的所需内存
1.初始时将SHARED_POOL_SIZE设得很大,运行应用程序
2.计算storedobject所占的内存
SELECTSUM(sharable_mem)FROMv$db_object_cache WHEREtype='PACKAGE'ortype='PACKAGEBODY'ortype='FUNCTION'ortype='PROCEDURE';
3.应用程序运行一段时间后,估计常用sql语句所占的内存(不包括动态SQL)
SELECTSUM(sharable_mem) FROMv$sqlarea WHEREexecutions>5;
4.对每个user每个打开的cursor,需要250bytes,可在运行高峰期间使用查询:
SELECTSUM(250*users_opening)FROMv$sqlarea;
5.在测试环境中,可让一个用户打开一定数量的cursor,运行下列语句测试共享内存,然后乘上user数
SELECT250*valuebytes_per_user FROMv$sesstats,v$statnamen WHEREs.statistic#=n.statistic# ANDn.name='openedcursorscurrent' ANDs.sid=15;
以上内存的和,再加上一点内存(留给动态SQL使用),作为你的应用的理想内存设置;预留一部分空间作为大的内存需要,避免miss和碎片;一些大的内存需要:
PL/SQL块的编译,trigger的编译;小的object不会使预留空间碎片化,反而保证reservedlist有大的连续块,一旦从reservedlist中分配的内存释放它就返回reservedlist。
影响的参数:
SHARED_POOL_RESERVED_SIZE 初始值=SHARED_POOL_SIZE*10%,超过50%,oracleserver报错
OPEN_CURSORS缺省=50
定义了涉及分配给用户进程的私有SQL区域的cursors数量,一个privateSQLarea一直存在直至cursor关闭;为了利用更多的内存给共享SQL区域,需要提高session每个session允许多cursor数量,开发人员应关闭不需要的cursor节省内存
CURSOR_SPACE_FOR_TIME缺省=FALSE布尔值
设置TRUE,表示以空间换取时间,共享SQL区不会被agedout直至相关的cursor被关闭,因此确信有足够的内存,没有cachemiss;除非RELOADSinV$LIBRARYCACHE一直为0,否则不要改变此参数值
若应用为FORM或使用动态SQL,设此值为FALSE--因为动态sql总是不一致,将占用过多内存
SESSION_CACHED_CURSORS缺省=0表示没有cache
当一个session打算关闭一个cursor时,如果这个cursor的parsecount超过3次,那么这个cursor将会被加到sessioncursorcachelist的MRU端.当一个session打算parse一个sql时,它会先去session的pga内搜索sessioncursorcachelist,如果找到那么会把这个cursor脱离list,然后当关闭的时候再把这个cursor加到MRU端.session_cached_cursor提供了快速软分析的功能,提供了比softparse更高的性能.
检查系统是否需要此参数的方法:
对某个典型用户session
selecta.sid,b.name,a.valuefromv$sesstata,v$statnamebwherea.statistic#=b.statistic#and(b.name='sessioncursorcachehits'orb.namelike'parsecount%');
Iffewparsesresultinhits,则可提高此参数,注意它将increaseoveralldemandsonmemory.--?
?
?
?
DataDictionaryCache
Selecttype,parameter,gets,getmisses,round(getmisses/decode(gets,0,null,gets)*100,2)"ratio(%)"fromv$rowcache;
GoalforaGoodRatio
SUM(GETMISSES)/SUM(GETS)<15%,否则应增大SHARED_POOL_SIZE
不可能希望getmisses趋近于0,因为数据库启动后需要读取objects定义
OEM-->PerformanceManager—>Memory—>DataDictionaryCacheHit%
检索需要在共享池中要求大于100K连续空间的对象:
select*fromv$db_object_cachewheresharable_mem>100000andtypein('PACKAGE','PACKAGEBODY','PROCEDURE','FUNCTION');
考察返回的结果,确认是否需要pin到共享池中,返回结果中的KEPT字段如果是YES,那么表示该对象已经固定在了共享池中,为NO,则表示还没有固定。
如果需要固定,使用下面的语句:
execdbms_shared_pool.keep('SYS.STANDARD');
数据库默认安装的时候没有创建dbms_shared_pool包,所以需要先创建该包。
cd$ORACLE_HOME/rdbms/admin
sqlplus“/assysdba”
@dbmspool.sql
DATABUFFER---数据库缓冲区高速缓存
v$db_cache_advice
==一堆数据块(DB_BLOCK_SIZE*DB_BLOCK_BUFFERS)
数据库的任何修改都在该缓冲里完成(LRU-->LRUW)。
所有的块,被读到内存中后,它的块头(datablockheader)放在一个Cachebufferchain中,Cachebufferchain由多个双向hash链表组成,hash链表数量由_db_block_hash_buckets决定.每个数据块头由DBA(datablockaddress)作为key,经hash函数后放在链表上,它和blockbuffer中的block一一对应,数据块头不包括实际的数据,仅是一个简单的描述.后台进程扫描hash链表前,必须获得cachebufferchainlatch,如果在CacheBufferchain中找不某块,就由磁盘读入.若需要查找某个block,则根据block的信息能计算hashvalue然后迅速定位到hashtable,然后根据hashtable信息去查看是否存在所想要的buffer,若有则命中,若没有则不命中。
显然不可能根据list去逐个搜索,这样效率太低.
LRU就是一种尽可能将常用的数据保留在内存的算法.当数据库需要一个数据缓冲区,他会从数据库缓冲区的LRU队列的尾部找一个空闲的缓冲,将一个数据块读入,然后数据库会把这个缓冲区放到LRU队列的中部,如果该缓冲被其他程序用到的话,那么他会往队列的头上移动,如果这个缓冲没有被其他程序用到,并且没有被修改过,那么他会慢慢的移动到LRU队列的尾部,最终被认为是空缓冲区被其他数据块所覆盖.一旦这个缓冲区被修改过DBWR把他从LRU队列中移出,放到LRUW队列(也叫赃缓冲区)中,等待DBWR把他们批量写入数据文件,然后再把他们的缓冲区连接到LRU队列的尾部.周而复始的工作.
如果查找在一个阀值内没有结果或者造成dirty缓冲区已经溢出,在进一步查找freebuffer前系统将发出一个消息给DBWR让他可以将LRUW队列的缓冲区写入磁盘.这个阀值被叫做这个阀值被叫做DBWRscandepthdirty缓冲区大小可以用_DB_LARGE_DIRTY_QUEUE和2*_DB_BLOCK_WRITE_BATCH来确定.前台进程继续搜索freebuffer.直到_DB_BLOCK_MAX_SCAN_CNT还没有发现系统就会挂起该进程.记录dirtybuffersinspected的静态变量并把该进程标志为freebufferwait.
cache和buffer_pool_keep是不一样的,cache是如果对该表全表扫描的话,会把块放在mru端,buffer_pool_keep是放在keep池中
selecttable_name,cache,buffer_poolfromdba_tableswheretable_name='TEST';
将表和索引Cache到SGA中
从ORACLE805之后,支持ALTERTABLEtable_nameSTORAGE(BUFFER_POOLKEEP)命令了。
但是在805与8i中,需要设置buffer_pool_keep参数来设置KEEP池大小。
这块内存来自数据缓存区,也就是从db_block_buffers中分配。
在ORACLE8和8i中,还必须设置db_block_lru_latches参数。
该参数应该比2*3*CPU数量少,但是要大于1,否则无法设置buffer_pool_keep。
在ORACLE9i中则需要设置DB_KEEP_CACHE_SIZE来设置KEEP池内存的大小。
这样将表KEEP才有用。
而且KEEP池要能够容纳得下才行的
将函数Cache到SGA中
@$ORACLE_HOME\rdbms\admin\dbmspool.sql;
execdbms_shared_pool.keep('procedure_name','P');
重做日志缓冲区(LOG_BUFFER)
logbuffer分成内部的bufferblocks,而这些block各有8个字节的头部信息存在于variablearea中.
当重做日志缓冲区填满时,将它的内容写入联机重做日志文件。
是循环使用。
是数据库最活跃的情形,可以用V$SYSSTAT视图进行监控。
查询V$SYSSTAT视图value域,它表明用户进程等待重做日志缓冲区所花费的时间(此处