Oracle
面试宝典
-
内存结构篇
一:Oracle
内存结构由哪几部分组成?
1
User global area (UGA)
2
Program global area (PGA)
3
System global area (SGA)
4
软件代码区Software code areas
二:请分别介绍下UGA
、
PGA
、
SGA
、软件代码区?
1 UGA
UGA
是用户全局区,主要存放用户会话的相关信息,比如登录信息。
在会话的生命周期内,UGA
必须对数据库会话可用。
所以,在连接模式是专用服务器连接模式时,也就是一个会话对应一个连接,UGA
存储在
PGA
中。
但是在连接模式是共享服务器时,也就是多个会话对应一个连接,UGA
存储在
SGA
中的
large pool
,如果
large pool
空间不够,
UGA
会存储在
shared pool
。大多情况下都使用专用服务器连接模式。
2 PGA
PGA(Process Global Area)
程序全局区,
PGA
是一个非共享内存区域,它包含
Oracle
进程专用的数据和控制信息。在
Oracle
进程启动时创建
PGA
。由每个服务进程和后台进程专有,所有单个
PGA
的集合就是总实例
PGA
大小。
PGA
内容:
PGA
主要有两个区域,
私有SQL
区域、
SQL
工作区域。
私有SQL
区域存储
SQL
的绑定变量值、查询执行状态信息,客户端进程负责管理私有
SQL
区域。分配的私有
SQL
区域的数量受初始化参数
OPEN_CURSORS
的限制。
SQL
工作区主要用于排序操作、
Hash
连接、位图合并连接时使用的内存。
比如 order by
、
group by
等操作。
PGA
管理:
在Oracle8i
中,
PGA
调整非常复杂,要调整
SORT_AREA_SIZE
、
HASH_AREA_SIZE
、
BITMAP_MERGE_AREA_SIZE
、
CREATE_BITMAP_AREA_SIZE
等参数。在
ORACLE9I
以后,只需要调整
PGA_AGGREGATE_TARGET
,这个值是个软限制,比如设置大小
2G
,只是一个目标值,实际上
PGA
大小可以超过
2G
。在
12C
开始引入
PGA_AGGREGATE_LIMIT
参数限制
Oracle
实例
PGA
使用内存的上限,如果超过限制就采取终止会话的方式来降低
PGA
内存的使用量。
3 SGA
系统全局区域(SGA)
,是一组共享内存结构,所有服务器和后台进程共享
SGA
。
与Oracle
后台进程一起构成数据库实例。
可以在V$SGASTAT
视图中查询关于
SGA
组件的信息。最重要的
SGA
组件如下
:
•
Database Buffer Cache
•
Shared Pool
•
Redo Log Buffer
•
In-Memory Area
•
Large Pool
•
Java Pool
•
Fixed SGA
•可选的与性能相关的
SGA
子区域
(1)Database Buffer Cache
数据库缓冲区缓存,也称为缓冲区缓存,是数据文件上的数据块在内存中的副本。主要是为了在内存中进行高速的数据查找和更新,
尽量减少磁盘的
IO
操作。也是
SGA
中占比比较大的一块内存区域。用户访问
DB Cache
的数据比访问磁盘上的数据速度更快数
(
内存的读取效率是磁盘读取效率约
14000
倍
)
,因此应用系统应该尽可能多地从
DB Cache
中访问数据。在大多数情况下,
DB Cache
的命中率越高,访问性能就越好。
缓冲池包括:default
默认池、
keep
保留池、
recycle
回收池
Buffer Cache
管理:
通过三条链表进行管理:HASH
链表、检查点队列链表、
LRU
链表
HASH
链表
HASH
链表的作用是通过
HASH
算法
(
消耗
CPU
资源
)
,提高
DB Cache
中数据块的定位速度。也就是逻辑读。
比如,根据需要访问块的块号、文件号计算HASH
值,在通过
HASH
值找到对应的
HASH Bucket,
搜索
Buckect
后的链表,找到目标
BH(Buffer Header),
通过
BH
找到
BA(Buffer Address)
,按照
BA
访问具体的
Buffer,
这个就是逻辑读的过程。
检查点队列链表(CKPT-Q)
主要用于记录脏块。
Buffer Cache
其实就是磁盘数据文件的缓存,以修改块的操作为例,如
update
,只是修改
Buffer Cache
中的
Buffer,
修改完成后
,update
操作就算完工了。这样
Buffer
中的数据和磁盘中的
block
就不一致了,这样的
Buffer
就是脏
Buffer
,脏块由
DBWR
进程统一写磁盘,但是
Buffer Cache
通常很大,有几万或几十万
Bufeer
,怎么在
Buffer Cache
中找到哪些是脏
Buffer
呢,这就需要一个链表,将所有脏
Buffer
都串起来,
DBWR
写脏块时,就是按照这个串起来的链表的顺序来写,这样的脏链表有两个,一个是
LRUW
,另一个是
CKPT-Q。
在
buffer cache
中,修改完数据后,会将对应的数据块加入到检查点队列
(CKPT-Q)
。
LRU
链表
(
最近最少使用链表
)
物理读时,服务器进程将数据块从数据文件读进Buffer Cache
中,假如
Buffer Cache
有
10000
个
Buffer
,那么进程应该覆盖哪个
Buffer
呢?
简单说,就是进程将数据块读进Buffer Cache
的什么地方。
答案是,覆盖最不常用的Buffer
,
LRU
主要就是解决如何快速找到最不常用的
Buffer
。
在Oracle 8i
之前,
LRU
算法
是
,DB Cache
在
LRU
上是会移动的,常用的缓冲会被换到
LRU
的热端,不常用的缓冲会被挤到
LRU
的冷端,一般来说会话分配
Cache
时,会从
LRU
的冷端开始查找。这种
LRU
算法会产生性能瓶颈
。
从 Oracle 8i
开始,
LRU
的算法有所改进,
LRU
链上的缓冲不再需要移动了,而是通过
tch
计数器大小值来判断某个数据块是否为热块。
(2)Redo Log Buffer
重做日志缓冲区是SGA
中的一个循环缓冲区,它存储描述数据库更改的重做条目。
重做记录是一种数据结构,它包含重做DML
或
DDL
操作对数据库所做更改所需的信息。数据库恢复将重做项应用于数据文件以重构丢失的更改。
LGWR
按顺序将数据块写入磁盘,而
DBW
将数据块分散写入磁盘。分散写比顺序写要慢得多。因为
LGWR
允许用户避免等待
DBW
完成缓慢的写操作,所以数据库提供了更好的性能。
LOG_BUFFER
初始化参数指定
Oracle
数据库在缓冲重做条目时使用的内存量。与其他
SGA
组件不同,重做日志缓冲区和固定
SGA
缓冲区不会将内存分成颗粒。
(3)Shared Pool
相比于Buffer Cache
,共享池中的内容可谓是杂乱无章。
Oracle
基本上将不能放进
Buffer Cache
中的数据都扔进了共享池,使得共享池的分配和释放极为频繁。
共享池中最基本的内存分配单元成为Chunk,
相当于
Buffer Cache
中的
Buffer
或块的概念。
Chunk
的大小极不统一,最新的
Chunk
可以只有十来个字节,最大的
Chunk
有几十兆甚至几百兆。基本内存单元大小的不统一,再加上频繁进行分配、释放操作,使共享池中极易产生内存碎片。总的来说,共享池是
Oracle
中最复杂的内存池。
包括以下内容:
•Library Cache
•Data Dictionary Cache
•Server Result Cache
•Reserved Pool
1
Library Cache
库缓存
主要
存储
用户提交的
SQL
语句、SQL
语句相关解析数、
SQL
执行计划、
PL/SQL
程序块等
。
2
Data Dictionary Cache
dictionary cache
里存放了数据字典的内存结构,包括
表的定义、Storage
信息、用户权限信息、约束定义、表的统计信息等。
SQL
语句解析期间频繁地访问数据字典。构造
dictionary cache
的目的是为了加快
SQL解析过程中语义解析
的速度。
数据字典缓存也被称为行缓存(Row Cache
),因为它是以记录行为单元存储数据的,而不像
Buffer Cache
是以数据块为单元存储数据。
3
Server Result Cache
服务器结果缓存是共享池中的内存池。与缓冲池不同,服务器结果缓存保存结果集,而不是数据块。
执行查询时,数据库将确定查询结果是否存在于查询结果缓存中,
如果结果存在,那么数据库将从缓存中检索它,而不是执行查询。缓存使数据库能够避免重新读取数据块和重新计算结果的昂贵操作。
4
Reserved Pool
保留池是共享池中的一个内存区域,Oracle
数据库可以使用它来分配大的连续内存块。
如果Oracle
解析一个
PL/SQL
程序单元,也需要从共享池中分配内存给这些程序单元对象。由于这些对象本一般比较大(如包),所以分配的内存空间也相对较大。系统经过长时间运行后,共享池可能存在大量内存碎片,导致无法满足对于大块内存段的分配。为了使有足够空间缓存大程序块,
Oracle
专门从共享池内置出一块区域来来分配内存保持这些大块。
数据库以块的形式从共享池分配内存。分块允许将大对象(
超过
5 KB)
加载到缓存中,而不需要单个连续区域。通过这种方式,数据库减少了内存碎片的产生。
(4)Large Pool
大池是一个可选的内存区域,用于比共享池更大的内存分配。
大池可以为以下情况提供大内存分配:
•
用于共享服务器和
Oracle XA
接口
(
用于事务与多个数据库交互
)
•
并行执行中使用的消息缓冲区
•
用于恢复管理器
(RMAN) I/O
从属的缓冲区
(5)Java Pool
Java
池是存储
Java
虚拟机
(JVM)
中所有特定于会话的
Java
代码和数据的内存区域。此内存包括在调用结束时迁移到
Java
会话空间的
Java
对象。
对于专用服务器连接,Java
池包括每个
Java
类的共享部分,包括方法和只读内存
(
如代码向量
)
,但不包括每个会话的
Java
状态。
(6)
可选的与性能相关的SGA
子区域
一些SGA
子区域只针对特定的性能特性启用。本节包含以下主题
:
•
In-Memory Area
•
Memoptimize Pool
In-Memory
是12C
开始,在
SGA
中新增加的内存区域,可以实现表数据按列存储;
In-Memory
并没有取代传统的
Buffer Cache
,二者并存在
SGA
中。列式存储在访问多行、少列情况下性能更优。
memoptimize pool
大小通过MEMOPTIMIZE_POOL_SIZE
设置,其中存储着启用了
fast lookup
表的散列索引。
从18c
开始支持
Memoptimized Rowstore
,可用于提高查询性能。针对频繁基于主键查询的
SQL
语句的性能提高十分明显。可以通过
CREATE TABLE
或
ALTER TABLE
…
MEMOPTIMIZE FOR READ
语句来启用表的
fast lookup
。
(7)软件代码区概述
软件代码区是存储正在运行或可以运行的代码的内存的一部分。Oracle
数据库代码存储在一个软件区域中,这个软件区域通常比用户程序的位置更具排他性和受保护性。
软件区域的大小通常是静态的,只有在软件更新或重新安装时才会改变。这些区域所需的大小因操作系统而异。
软件区域是只读的,可以安装共享的,也可以安装非共享的。有些数据库工具和实用程序(
如
Oracle Forms
和
SQL*Plus)
可以安装为共享的,但有些则不能。在可能的情况下,数据库代码是共享的,这样所有用户都可以访问它,而不需要在内存中有多个副本,从而减少了主内存,并在总体上提高了性能。如果在同一台计算机上运行,数据库的多个实例可以将相同的数据库代码区域用于不同的数据库。
欢迎关注我的微信公众号"IT小Chen",共同学习,共同成长!!!