Oracle Instance
曾经也学习过oracle 逻辑结构的知识。但用的不多好多都是有点概念,近期做到一个跨instance工作流。全部抽点时间温习了一下相关知识。把网上看到的感觉讲的还比較明了。全面的文章汇总一下
instance = 内存结构(SGA,system global area) +后台进程
内存结构 = 共享池+数据快速缓存+重做日志缓冲区+其它
后台进程 = DBWn(database writer n个)+LGWR(log writers)+SMON(system monniter)+PMON(progress moniter)+CKPT(checkpoint)+……
PGA(Program Global Area)= server进程+后台进程
以下分别介绍各部分:
共享池
1、共享池用于存放近期运行的SQL语句和数据字典信息,其尺寸由初始化參数SHARED_POOL_SIZE定义。
共享池主要由库快速缓存和数据字典快速缓存两部分组成。
库快速缓存用于存放近期运行的SQL语句信息。包含SQL语句文本,解析代码值及其运行计划。运行计划是SQL语句的内部操作步骤。
比如:当运行select name from students where grade=90时,假设grade列上不存在索引,运行计划将採用全表扫描;假设有索引。运行计划将使用索引和ROWID定位数据。
如上图所看到的。库快速缓存包括很多上下文区,每一个上下文区都有对应的SQL语句运行计划,这些上下文区又被称为共享游标。当client运行SQL语句时,server进程首先检查共享游标是否存在,若存在则依照运行计划直接运行就可以;若不存在则生成SQL语句运行计划,并将运行计划存放到对应的上下文区中。然后运行SQL语句。共享游标减少了SQL语句解析的次数。提高了运行性能。
另外,语句1和语句2因为文本不同,所以占用不同的上下文区,而对于文本全然同样的语句1来说能够共享上下文区。
所谓的文本全然同样指的是:语句文本同样;大写和小写和长度同样;赋值变量同样。
数据字典快速缓存用于存放数据字典的信息,包含表、列的定义以及权限信息。
最后,库快速缓存和数据字典快速缓存的尺寸是能够变化的。动态改变共享池的尺寸:alter system set shared_pool_size = 60M;
数据快速缓存
数据快速缓存用于存放近期訪问的数据块信息,它由很多小缓冲区组成。
数据快速缓存採用LRU(least recently used)算法管理数据快速缓存。
数据快速缓存的结构:分为三部分。各自是脏缓冲区、空暇缓冲区、忙缓冲区。脏缓冲区是指内容与对应数据块不一致的缓冲区。空暇缓冲区是指内容与对应数据块一致或者不包括数据的缓冲区;忙缓冲区是指服务进程正在存取的缓冲区。
重做日志缓冲区
重做日志缓冲区用于记载instance的变化。
后台进程
后台进程是指oracle server隐含运行的进程。
启动instance时不仅会分配SGA。还会启动后台进程;关闭intance时不仅释放SGA所占的内存空间。并且会释放后台进程所占用的CPU和内存资源。
以下介绍一下经常使用的后台进程:
SMON(System Monitor):用于运行intance恢复、合并空间碎片并释放暂时段。
PMON(Process Monitor)用于监视server进程的运行。而且在server进程失败时清除该server进程。
--================================================================================
Oracle内存结构
Oracle内存结构主要能够分共享内存区与非共享内存区,共享内存区主要由SGA(System Global Area)组成。非共享内存区主要由PGA(Program Global Area)组成(见图1-1)。
从图1-1中能够看到,Oracle共享内存区主要包含数据缓冲区(Data buffer)、共享池(Shared pool)及一些其它的结构。而PGA则主要包含会话的一些信息及排序区,Hash join区域等。以下分别介绍这些内容。
SGA
系统全局区(SGA,System Global Area)事实上是一块巨大的共享内存区域,包括了Oracle的数据缓冲及众多的控制结构。这里的数据能够被Oracle的各个进程共用。假设有相互排斥的操作。如锁定一个内存对象,则须要通过Latch与Enqueue来控制。
每一个Oracle实例(instance)仅仅能启动一个SGA,除非通过RAC等一些特殊的全局管理方式。否则不同的实例仅仅能訪问自己的SGA区域。通过例如以下的方式就能够查看SGA大小:
10gR2 Piner>show sga Total System Global Area 8877225568 bytes Fixed Size 755296 bytes Variable Size 486539264 bytes Database Buffers 8388608000 bytes Redo Buffers 1323008 bytes
以上结果是一个典型的OLTP环境中的SGA的分配情况,我们能够看到四个大的部分。
Fixed Size,包含了一些数据库与实例的控制信息、状态信息、字典信息等,启动的时候就固定在SGA中。并且不会改变。
Variable Size,包括了shared pool、large pool、java pool、streams pool、游标区和其它结构等,合计450MB左右。
Database buffers,有时候也叫Data buffer,它是数据库中数据块缓冲的地方,数据块在内存中就缓存在这里。所以。在OLTP环境中,Data buffer是SGA中最大的缓冲区,是数据库性能高低的关键所在。
Redo buffers,它是为了加快日志写进程的速度而设立的缓冲区,在一般OLTP环境中。由于提交非常频繁。所以一般不会非常大。
SGA的大小信息也能够从v$sga中获得。与show sga的结果一样。
另外,v$sgastat记录了SGA的一些统计信息。v$sga_dynamic_components则保存了SGA中能够动态调整的区域的一些动态或者手工调整记录。
以下将介绍SGA中最重要的两个对象,共享池(Shared pool)与数据缓冲区(Database buffer)。其它的池。如Streams pool,在介绍Streams的章节时再另外介绍。
共享池(Shared pool)
共享池是SGA中很关键的内存片段。特别是在性能和可伸缩性上。由初始化參数shared_pool_size决定其大小,在Oracle 10g以后。Oracle能够自己主动管理大小。
在典型的OLTP高可用环境中,一个太小的共享池会扼杀性能,导致出现Ora-04031错误,使系统停止执行。可是太大的共享池也将消耗大量的CPU来管理。在数据仓库环境中。由于并发进程的须要。可能会分配比較大的共享池。
提醒:在实际的高可用环境中。有非常大的一部分故障就是由于共享池的原因而导致系统停顿甚至宕机的,如Latch争用、Ora-0431错误、Library cache争用与等待。
不对地使用共享池仅仅会带来灾难性的后果。所以,必须先要了解共享池的作用。
共享池又能够分为SQL语句缓冲区(Library Cache)、数据字典缓冲区(Data Dictionary Cache)及一些控制结构。而数据字典缓冲区与控制结构是用户无法直接控制的,所以,真正与用户有关的事实上就是SQL语句缓冲区。
当一个用户第一次提交一个SQL语句。Oracle会将这句SQL进行硬分析(Hard parse)。这个过程类似于程序编译,会耗费相对较多的时间,由于它要分析语句的语法与语义,获得最佳的运行计划(Sql plan),并在内存中分配一定的空间来保存该语句与相应的运行计划等信息。
由于Oracle总是保存语句的运行信息。当数据库第二次或者多次运行该SQL时。Oracle自己主动跳过这个硬分析过程。变为软分析(Soft parse)或高速软分析(Fast soft parse)。从而降低了系统分析的时间,降低CPU与Latch的消耗。
注意:Oracle中仅仅有全然同样的语句,包含大写和小写、空格、换行都要求一样,才干反复使用曾经的分析结果与运行计划。
图1-2是一个完整的SQL语句的分析过程:
所以,假设大量的,频繁訪问的SQL语句都不採用绑定(Bind)变量。Oracle为了做SQL的硬分析,Shared pool latch将变得严重争用与等待,相同也会耗费大量的CPU,直到机器的资源耗尽。
另外,由于Oracle会从共享池中分配空间来保存刚做完硬分析的SQL语句,也将耗费大量的内存空间。并且,这些被浪费的空间无法被重用。
对于编程者来说,要尽量提高语句的重用率。降低语句的分析时间。一个设计非常差的应用程序能够毁掉整个数据库。为了避免出现这种问题,Oracle从9i開始。还引进了一个新的參数cursor_sharing,只是,由于该參数总是带来非常多其它问题,如bug,所以,在现有的数据库版本号上,还是不建议在高可用的生产环境中使用。
共享池採用LRU算法来决定共享池中的对象是否继续保存,由于其空间毕竟有限,不可能无限保存全部的信息。
所以,假设一个语句已经被运行过了。假设长时间没有被使用。又一次运行的时候,也可能面临又一次分析,假设真的运行次数如此之少,就不是高可用环境须要关心的了。
对于间歇性訪问的比較大的对象。如自己定义的过程与包,假设不想在执行过程中被系统自己主动交换出去,能够调用DBMS_SHARED_POOL.KEEP存储过程将该过程或包pin在共享池中,以降低又一次加载的巨大代价。
我们能够通过例如以下命令手工清除共享池的内容。除了有指导的特殊情况下外,该命令不建议在高可用的生产环境上执行。
SQL> alter system flush shared_pool;
与共享池相关的视图非常多。这里介绍几个可能在高可用环境中常常须要用到的视图。
v$sqlarea,每条记录都显示了一个SQL语句的具体统计信息,包含历史以来的运行次数、物理读、逻辑读、耗费时间等许多的重要信息。
v$sqltext_with_newlines。由于v$sqlarea仅仅是记录了一个语句或者是一个游标的前1000个字符。假设是比較大的SQL语句,则不能在v$sqlarea中全然显示。
假设通过这个视图,能够获得一个SQL语句的具体信息。在这个视图中。一个SQL语句分为多行保存,通过hash_value来标示语句,通过piece来排序。
v$sql_plan视图保存了被运行的SQL语句的运行计划。能够通过特定的脚本获得曾经运行过的语句的运行计划。在本书的后面章节有这种讨论。
只是。该视图在9i的早些版本号,如9206曾经,存在一些bug,查询该视图。可能会出现600错误,甚至导致数据库崩溃。
v$shared_pool_advice,这个视图会对Oracle的共享池做一些预測。范围可能在当前值的50%~200%之间,优化者能够依据视图显示的信息做优化推断。如又一次调整共享池大小。
当中的字段SHARED_POOL_SIZE_FACTOR说明了预測的共享池大小与如今大小的比例。
对于并发非常多。并且訪问频繁的高可用环境。须要避免例如以下的一些情况。在本书的后面将有具体的案例分析来说明其原因与避免方法:
共享池不够或bug导致的0431错误,该错误可能导致系统无法訪问。
分析数据改变导致运行计划改变,错误的运行计划可能导致系统无法运行。
添加了新的对象,如索引。引起执行计划改变而导致系统无法执行。
改动表导致依赖的存储过程或者是包失效。而无法自己主动编译成功。导致系统崩溃。
错误的操作方法导致严重的Latch争用与等待。
数据缓冲区(Data buffer)
数据缓冲区(Data buffer)
数据缓冲区(Data buffer)是Oracle中用于数据块缓冲的区域。数据库常规情况下读写(非直接读写)数据块,Undo块等。都会经过这个缓冲区,并适当地保存在缓冲区。假设下一次请求操作相同的块,则不须要从磁盘获得,大大提高了系统的响应速度。
数据缓冲区尽管不像共享池那样easy导致系统故障。可是,它却是影响OLTP系统性能的关键,由于它的Cache技术能够非常大程度地避免磁盘寻道,直接从Data buffer中获得。所以,Oracle把从Data buffer获得数据块叫Cache hit,把从磁盘获得数据块叫Cache miss,它们的比率就是我们常说的Data buffer命中率。
在一个典型的OLTP的环境中。或者对事务型以及小查询型的数据库来说。更高的命中率意味着更快的响应速度,所以命中率一般要求在95%以上。大的Data buffer对提高系统的性能有巨大的优点,由于Data buffer比較大。缓冲的数据块也就比較多,命中率也就更高。
可是在典型的OLAP环境中,大的Data buffer则不一定是必要的,由于OLAP的查询基本是要求从磁盘返回,并且以直接读写居多,直接读写是不经过数据缓冲区的。使得命中率失去意义。所以在OLAP环境中,须要考虑用很多其它的磁盘驱动器,OLAP的速度取决于硬盘的多少与系统的带宽。
数据缓冲区中的块基本上在两个不同的列表中管理。一个是块的"脏"表(Dirty List)。表示被用户改动过的数据块,採用检查点队列(checkpoint queue)来管理这些脏的数据块,必要的时候通过数据库写进程(DBWR)来写入这些脏块;另外一个队列是不脏的块的列表(LRU List),比方通过Select从磁盘获得的数据块。
一般的情况下,Oracle使用近期最少使用(Least Recently Used,LRU)算法来管理这些队列。可是。从8i開始,另外还添加了Touch的概念,不不过纯粹的LRU算法。
块缓冲区快速缓存又能够细分为下面三个部分Default pool、Keep pool、Recycle pool。在9i曾经。它们相应的是db_block_buffers、buffer_pool_keep、buffer_pool_recycle三个參数,分别表示每一个缓冲区块的个数。从9i開始,又又一次引入了三个新的參数:db_cache_size、db_keep_cache_ size、db_recycle_cache_size。分别表示该缓冲区的字节大小。
从9i開始,Oracle支持创建不同块尺寸的表空间,这个新的特性同一时候也攻克了在不同块大小的数据库之间传输表空间的问题,而且能够为不同块尺寸的数据块指定不同大小的数据缓冲区。
不同块尺寸的数据缓冲区的大小就由对应參数db_nk_cache_szie来指定,当中n能够是2。4,8,16或32。如创建了一个大小为2K的非标准尺寸的表空间,就能够指定db_2k_cache_size为这个表空间指定缓存区的大小。
注意:db_block_buffers与db_cache_size这两种不同类型的參数。不能同一时候设置。另外, db_nk_cache_size不能设置默认标准块大小的缓冲区,如默认块大小为8K,则不能设置參数db_8k_cache_size。
正确使用Default pool、Keep pool、Recycle pool也能够提高系统的性能,如把一个訪问非常频繁的表或索引放置在适当大小的Keep pool中,能够降低物理读。提升IO性能。
是否决定使用这个功能。要看系统的详细情况,如參考Statspack中的Segment统计信息,关注当中的物理读部分,分析Top物理读的对象。假设有些对象的确不大,可是物理读又非常大。就能够考虑缓冲分离。
视图v$db_cache_advice与共享池的v$shared_pool_advice一样,由Oracle自己主动依据一些数学模型算法,收集信息后产生的一系列建议值,能够作为调整Data buffer大小的參考。
v$bh与x$bh
v$bh在研究与查询Data buffer使用上,是一个很不错的视图。很具体地记录了数据块在数据缓冲区内的使用情况。一条记录相应一个Block的具体信息。
假设通过例如以下语句来查询v$bh的来源,能够看到这个视图来源于基表x$bh与x$le,可是,主要数据与字段都是来源于x$bh的。
SQL>select * from v$fixed_view_definition t where t.view_name='GV$BH'不同的是。x$bh包括了很多其它的信息,如touch count信息,在Oracle 8i以上作为LRU算法的一个重要的參考信息,表示了一个块的热点程度。touch count信息相应到x$bh的tch字段,而段的data_object_id信息相应到x$bh的obj,或者是v$bh的objd。有了这些基本信息,事实上就非常好确认热点块在哪里了。
不同的是,x$bh包括了很多其它的信息,如touch count信息。在Oracle 8i以上作为LRU算法的一个重要的參考信息,表示了一个块的热点程度。touch count信息相应到x$bh的tch字段,而段的data_object_id信息相应到x$bh的obj,或者是v$bh的objd。有了这些基本信息,事实上就非常好确认热点块在哪里了。