由于内存结构和进程结构关系较紧密, 进程会作用到对应的内存区域, 比如数据库写入器作用到数据库缓冲区缓存中, 日志写入器会作用到日志缓冲区, 所以在这里我把内存结构和进程结构会相互配合地进行描述~
Oracle 实例内存结构的组成结构:
实例内存结构
oracle 实例内存结构由两部分组成 SGA(系统全局区)和 PGA(用户全局区)组成, SGA 是一块共享的内存区域, 也是最大的一块内存区域; PGA 则是用户会话专有的内存区域, 每个会话在服务器端都有一块专有的内存区域就是 PGA.
SGA 组成
篇幅有限, 下面对数据库缓冲区, 日志缓冲区, 共享池做主要介绍
数据库缓冲区缓存
通过指定 DB_CACHE_SIZE 参数的值, 可以配置缓冲区高速缓存. 缓冲区高速缓存可存放数据文件中块大小为 DB_BLOCK_SIZE 的数据块的副本. 缓冲区高速缓存是 SGA 的一部分; 因此所有用户都可以共享这些块. 缓冲区缓存 是 Oracle 用来执行 sql 的工作区域, 在更新数据时, 用户会话不会直接去更新磁盘上的数据, 想想, 如果允许这么做, 那么频繁的磁盘 IO 对于系统性能的影响是毁灭性的. 所以, 实际的处理流程是这样的:
select ename,salary from emp where name='阿里巴巴';
首先, 当用户提交了该条 sql 语句, 由对应的用户进程 (比如我们常用的 sql developer) 将其发送给服务器, 监听程序监听到该条请求, 会为其建立一个对应的服务器进程, 然后服务器进程会先扫描缓冲区中有没有包含关键行 ("阿里巴巴") 的数据块, 如果有, 这就算一次缓存命中了, 然后相关行会传输到 PGA 进行进一步处理, 最终经过格式化后展示给用户; 如果没有命中, 那么服务器进程会首先将对应行复制到缓冲区内, 然后再返回给客户端.
DML(insert,update,delete)操作同理, 加入用户发送一条 update 语句, 服务进程依然先去扫描缓冲区, 如果缓存命中, 则直接更新, 数据变脏; 如果没有命中, 由服务器进程将对应数据块先从磁盘上复制到缓冲区内, 再进行更新操作.
脏缓冲区
如果缓冲区存储的块和磁盘上的块不一致, 该缓冲区就叫做 "脏缓冲区", 脏缓冲区最终会由数据库写入器 (DBWn) 写入到磁盘中去.
数据库写入器(DBWn)
数据库写入器是 Oracle 的一个后台进程, 所谓后台进程是相对于前台进程 (服务器进程) 来讲的. DBWn 的 "n" 意味着一个实例是可以有多个数据库写入器的.
作用: 简而言之, DBWn 的作用就是将变脏了的缓冲区从数据库缓冲区缓存中写入到磁盘中的数据文件中去.
数据库缓冲区缓存这块内存区域和数据库写入器这块是比较重要的概念, 别的数据库产品像 MySQL 也都有对应的实现, 只不过叫法不一样罢了. 了解这块的时候, 要时刻意识到会话是不会直接更新磁盘数据的, 会话的更新, 插入, 删除包括查询等都是先作用到缓冲区上, 随后, DBWn 会将其中的脏缓冲区转储到磁盘上去.
DBWn 什么时候写入?
DBWn 是个比较懒的进程, 它会尽可能少的进行写入, 在以下四种情况它会执行写入:
a. 没有任何可用缓冲区(不得不写啊)
b. 脏缓冲区过多
c.3 秒超时(最晚 3 秒会执行一次写入)
d. 遇到检查点, 即 checkPoint(检查点), 检查点是个 Oracle 事件, 遇到检查点, DBWn 会执行写入. 比如实例有序关闭的时候会有检查点, DBWn 会将所有脏缓冲区写入到磁盘上去的, 这很容易理解, 要保持数据文件的一致性.
日志缓冲区
重做日志缓冲区是一个循环缓冲区; 服务器进程可以用新条目覆盖重做日志缓冲区中已写入磁盘的条目. LGWR 进程的写速度通常都很快, 足以确保缓冲区中始终有存储新条目的空间. LGWR 进程将重做日志缓冲区写入磁盘上的活动联机重做日志文件 (或活动组成员) 中. LGWR 进程将 LGWR 上次写入磁盘以来进入缓冲区的所有重做条目复制到磁盘.
当我们执行一些 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 要写入脏缓冲区前
共享池
共享池是最复杂的 SGA 结构, 大小通过 SHARED_POOL_SIZE 指定.
常见的几个共享池组件:
1. 库缓存: 库缓存这块内存区域会按已分析的格式缓存最近执行的代码, 这样, 同样的 sql 代码多次执行的时候, 就不用重复地去进行代码分析, 可以很大程度上提高系统性能.
2. 数据字典缓存: 存储 oracle 中的对象定义(表, 视图, 同义词, 索引等数据库对象), 这样在分析 sql 代码的时候, 就不用频繁去磁盘上读取数据字典中的数据了
3.PL/SQL 区: 缓存存储过程, 函数, 触发器等数据库对象, 这些对象都存储在数据字典中, 通过将其缓存到内存中, 可以在重复调用的时候提高性能.
作为 DBA, 以上内容是必须掌握的, 如果大家有兴趣的话可以多了解下这方面内容~
来源: http://stor.51cto.com/art/201810/584860.htm