简述
由一个Oracle数据库以及Oracle实例即构成一台Oracle服务器。
Oracle数据库
而Oracle数据库是一个数据的集合,该集合被视为一个逻辑单元。
Oracle实例
而Oracle实例是由一个Oracle后台进程以及Oracle对应内存结构所构成,具体内容我们会在后文展开描述。
Oracle11g组件简介
而关于Oracle的体系结构,我们可以参考Oracle官网给出的图片
如上图所示,可以看到Oracle实例是由一个庞大的内存结构以及后台进程所构成。所以Oracle数据库启动实例的过程就是**分配内存(初始化内存结构)和启动后台进程(初始化后台进程)**的过程。
而且从图中我们也不难看出Oracle实例的内存包括SGA
以及PGA
而后台进程中又包含了SMON、 PMON、 DBWR、 LGWR、 ARC\ CKPT等众多子进程构成。关于这些组成部分我们会在后文中展开描述。
讲到Oracle11g的内存结构,我们首先就需要直到两个组成部分,分别是SGA和PGA,他们分别是系统全局区和程序全局区,所占内存比分别是Oracle内存占比的80%、20%。
SGA
是Oracle内存结构中最重要的系统全局区,Oracle会在实例启动时为其分配内存空间。对此我们可以通过重启来查看是否真的如此。如下图所示,我们首先以sys用户登录sqlplus然后键入以下命令关闭Oracle数据库
shutdown immediate
完成数据库关闭之后,我们在使用如下命令启动数据库
startup
可以看到在系统启动时完成了Oracle的SGA内存分配。
在上文概览中我们也看到了,SGA
是一块庞大的内存区域,其组成部分也有:共享池、数据缓冲区、日志缓冲区、large池、Java池、stream池等。首先我们来聊聊SGA的共享池,众所周知,一条SQL语句的执行是需要经过权限校验、语法解析、生成执行计划等众多过程,假如我们每一句SQL都需要进行这样一个步骤,那么Oracle执行效率将会变得十分低下。所以Oracle数据库就借鉴了操作系统缓冲区的思想。会将之前执行过的语句直接存到共享池中供后续的用户服用,这样就避免了,每次执行相同SQL都要执行语法分析、编译生成执行计划这样繁琐的步骤了。
需要注意的是共享池中判定一条SQL是否相等是根据SQL语句的字符串,若我们执行的SQL句子相同,但是大小写不同,例如select * from scott.emp
和select * from scott.Emp
就是两句不同的SQL,为了合理的利用共享池,我们就必须规划团队编写SQL的习惯。
再聊聊数据缓冲区,我们都知道数据从硬盘中读取的速度,远远慢于从内存中读取。Oracle为了保证查询效率,会将之前查询过的结果缓存到数据缓冲区中,这样后续的查询都会从内存中读取,效率自然会高。
但是考虑到数据一致性问题,当用户对这些数据执行更新操作的时候,缓冲区的这些数据就会变成脏数据,Oracle设计者也参考了操作系统的MESI
协议,当缓存中的这些数据被修改后,这些被修改的数据就会通过DBW进程将数据写回硬盘中,内存中关于这些数据的缓存就会被置为无效,下次需要查询这些数据时,同样会从硬盘中读取,缓存到数据缓冲区,再返回给用户。
接下来便是日志缓冲区,日志缓冲区的作用相较于上述几个缓冲区来说不是特别重要,它会将用户日常的修改操作存到日志缓冲区中,当日志缓冲区的数据达到一定数量时,这些缓冲数据就会被存到日志文件中,相对来说日志缓冲区的作用仅仅时归档,对于性能方面的影响不是特别大。
large池则是为了进行较大后台进程操作时而分配的内存空间,主要指备份恢复、大型IO操作、并行查询等场景而设置的内存空间。Stream池和java池都是为各自要用而分别的内存空间这里也不多做赘述。
再来聊聊PGA,它是Oracle内存结构的程序全局区,与SGA不同的是,SGA是系统全局区,是所有用户共享的,所以查询过的数据或者查询出的结果集都会放在共有的缓存中。而SGA则是有些不同,它属于服务器进程,只有在用户进程进行连接的时候,Oracle才会创建为服务器进程分配一个PGA。所以对于每个用户进程来说,大部分情况下PGA是私有的,这里之所以强调大部分,是因为PGA会根据连接模式的不同,分配方式也会有所不同。
连接模式分为两种,一种是共享连接模式,这种情况下多个用户进程可能会对应一个服务器进程,所以在这种情况下某些PGA对某些用户来说是共享的。还有一种连接模式的专用模式,这种情况是Oracle连接模式中最常用的,他会为每个建立连接的用户进程分配一个转悠的服务器进程,所以这个服务器进程的PGA是私有的。
需要补充的是一旦用户进程和服务器进程建立连接之后,服务器进程就会成为用户进程代理,为其处理一切sql操作,并且当用户进程与服务器进程断开连接之后,该服务器进程也会终止。
PGA保存了服务器进程所需要的数据以及控制信息,比如每个session传入的sql变量、以及对session进行控制的控制信息。如果该session进行了排序或者hash操作,同样会被存入PGA中。
Oracle的实例进程有三种,分别是用户进程,实例进程和后台进程,用户进程在上文中已经提到,当用户运行一个应用程序准备和Oracle数据库发起请求连接时,就会创建一个用户进程。而当用户与数据库实例建立会话时,数据库服务器也会创建一个服务器进程。
这里提到了一个会话的概念,只要一个用户和服务器建立连接,并各自创建进程就会生成一个session,当用户与数据库断开连接时,这个session也会随之消失。
我们可以以system用户登录sqlplus,键入以下sql,此时我们发现session中并没有这个用户
select * from v$session where username='SCOTT'
/
当我们使用sqlplus
登录一个scott用户时,用同样的sql语句就会发现此时数据库中出现了关于scott的会话
需要重点描述的就是后台进程了,后台进程是由多个进程构成,分别是PMON、SMON、 DBWR、 LGWR、CKPT 等。
其中PMON进程就是用户清理出现故障的进程,释放所有当前挂起的锁定,释放故障进程使用的资源等。
而SMON则是监控进程,在实例故障崩溃之后,该进程会自动打开并且恢复实例。并且这个进程还会整理数据文件的自由空间,将相邻的区域结合起来。释放不再使用的临时段。
DBW则时管理数据库缓冲区,将最近使用过的块保留在内存中,并且为了保证硬盘和缓冲区的数据一致性,对于修改后的缓冲区数据,他也狐疑实时将新数据写回硬盘中。但是在多用户情况下,如果涉及大量的数据修改这时候,单一一个DBWR进程是不够的,所以我们也需要学会修改DBR的数量。
首先我们需要通过下面这条sql查看,发现只有一个DBW进程
select COUNT(1) from v$process where program like '%DBW%'
/
然后键入下面这条sql修改
ALTER system SET db_writer_processes=3 SCOPE =spfile;
重启数据库
shutdown immediate
完成数据库关闭之后,我们在使用如下命令启动数据库
startup
再次使用刚刚的SQL就会发现,数据变为了3
LGWR则时将日志缓冲区中的日志写回日志文件,系统中可以有多个日志文件,该进程以循环的方式将数据写入日志文件中。
CKPT进程我们只需了解以下即可,该进程是为了防止实例崩溃,为了尽快进行实例恢复的进程,而检查点包括两种,分别是完全检查点和增量检查点。
了解这么多后台进程后,我们又该如何查看当前数据库中的进程呢?只需我们键入以下SQL即可
select * from v$process
/
例如我们想查看smon的信息就用下面这条sql
select * from v$process where program like '%SMON%'
/
自Oracle 9i之后Oracle就引入PGA自动PGA大小分配管理,这一优化使得Oracle滋生会估计session大概消耗的PGA总的大小,调整PGA大小。这一策略的前提是workarea_size_policy
为auto,这个参数的查看我们可以登录sys账户通过下面这条sql查询
show parameter workarea_size_policy;
这就是著名的AMM即自动内存管理,他的作用的就是直接为Oracle整体设置一个总的内存大小,不必像10g那样具体分配SGA和PGA。在11g中MMAN就是用于自动内存管理的。
我们可以用如下命令设置内存和最大内存。
show PARAMETER memory;
show parameter sga_target;
show parameter pga_aggregate_target;
而修改内存的方式也很简单,只需下面这条命令即可,例如我想将内存改为600m,只需
alter system set memory_target=600m;
修改最大内存即
alter system set memory_max_target=900m scope=spfile;
注意以下文件都在我们Oracledata目录下你所创建的数据库名的文件夹中,例如笔者的数据名为orcl那么这些文件都在C:\app\zhangshiyu\oradata\orcl
数据文件:用于存储数据库数据,如表、索引数据等
控制文件:记录数据库物理结构的二进制文件
日志文件:记录对数据库的修改信息,用于故障恢复
依次由大到小为数据库->表空间-> 段 ->区-> 数据块
,表空间是最大的逻辑单位,一个数据库至少有一个表空间,默认就有一个名为system的表空间。
表空间详情我们完全可以通过以下这条SQL查看
SELECT * FROM "V$TABLESPACE" ;
而每个表空间都是由一个或者多个数据库文件组成。表空间大小等于构成表空间的所有数据文件大小。同样的,我们也可以当前数据库创建属于自己的表空间,例如笔者当前所用的数据库名字为orcl,我们则可以通过以下SQL完成表空间创建
-- 在orcl数据库中创建一个名为testtbs 的表空间,并且会自动增长
CREATE tablespace testtbs datafile 'C:\app\zhangshiyu\oradata\orcl\testtbs01.dbf' SIZE 10m autoextend ON;
若sqlplus窗口显示以下内容则说明创建成功
同样的,我们也可以到文件夹中查看,也能确认刚刚的表空间是否创建成功了。
关于表空间,我们还需要知道一点,默认情况下创建的用户使用的表空间都是使用user,如下所示首先我们创建一个名为zhangsan的用户并授权所需权限
create user zhangsan identified by zhangsan;
grant connect,resource to zhangsan
完成之后,我们可以通过如下sql查看对应用户所使用的默认表空间,注意,查询时用户名需要大写
SELECT * FROM DBA_USERS WHERE USERNAME ='ZHANGSAN'
SELECT * FROM DBA_TABLES WHERE table_name ='A';
同样可以看到该用户所创建的表被放到了user表空间中
我们也可以指定自定义表空间,上文中我们已经创建过一个名为testtbs的表空间,所以我们完全可以用改空间作为默认表空间,只需使用如下SQL即可
alter database default tablespace testtbs
这时候我们再去dba_user表中查看即可发现,新创建用户的表空间都变为testtbs了
SELECT * FROM DBA_USERS WHERE USERNAME ='LISI';
段是构成表空间的存储结构,是由一组区构成的,按照存储数据的特征,我们可以将段分为数据段、索引段、回退段、临时段等。
而区是段的组成部分,它是由一堆数据块组成。当段中所有空间已完全被使用时,系统自动为该段分配一个新区。区不能跨数据文件存在,只能在存到一个数据文件中。
数据块是Oracle服务器所能分配、读取、和写入的最小存储单元,Oracle无论对数据或者文件进行的任何操作都是以块为单位进行数据的存储及管理。我们可以使用下面这条SQL来看看Oracle数据库为我们分配的块的大小(注意单位为byte,所以下图块大概是8k左右):
show parameter db_block_size;
那么问题来了,我们都知道块是Oracle操作数据的基本单位,那么下面这段SQL查出来的结果所使用实质内存是多少呢?
select ENAME from scott.emp WHERE EMPNO =7934;
可以看到查询结果为一个6字节的字符串,但是上文提到了,块是数据查询的最基本单位,所以这u但SQL实际上所查询出来的数据实际上也是将数据从硬盘读到一个块中在缓存到数据缓冲区中,最后再交给用户。所以实际上所用到的内存也是8k左右。