1 系统全局区:SGA
1.1 SGA概念简介
SGA是一块可读写内存区域,与Oracle后台进程(background processes)一起构成了数据库实例。所有代表用户执行的服务器进程都能读取实例SGA里的信息。有一些进程能在数据库运行时写入SGA。需要注意的是,服务器和后台进程本身并不在SGA中,而是存在于独立的内存空间中。
每个数据库实例都有自己的SGA。Oracle数据库会在实例启动时自动为SGA分配内存,并在实例关闭时回收内存。正如图1,SGA由多个为了满足特定内存分配需求的内存池组成。除了重做日志缓存(redo log buffer)以外,所有其他的内存池都按连续内存单位分配和回收内存空间。这个连续内存单位称之为粒(granule),其大小与平台有关且取决于总的SGA大小。
查询 V$SGASTAT 视图可以看到SGA各部分的信息。其中包括数据库缓存、IM区、重做日志缓存、共享池、Large池、Java池、Streams池、固定SGA等。
1.2 数据库 buffer cache
数据库高速缓冲存储器(Database buffer cache),即缓冲器高速缓存,是存储了从数据文件读入的数据块副本的内存区域。缓冲器(buffer)是缓冲管理器临时缓存当前正在使用的数据块的一块主内存地址(main memory address)。所有当前连接到数据库实例的用户都能共享访问 buffer cache。
1.2.1 缓冲器高速缓存的用途
数据库buffer cache的用途包括:
- 改善物理 I/O:数据库更新高速缓存(cache)中的数据块,并存储重做日志缓冲器(redo log buffer)修改操作的元数据。在 commit 之后,数据库将重做日志缓冲器写入在线重做日志,但是并不会立即将数据块写入数据文件。数据库后台写进程 DBW (database writer) 通过 lazy write 来写入数据文件。
- 将频繁访问的数据块保留在 buffer cache 中,并将不经常访问的数据块写入磁盘。当 Database Smart Flash Cache(数据库智能闪存缓存)启用时,可以将部分 buffer cache 放到闪存缓存中。需要通过 DB_FLASH_CACHE_FILE 和 DB_FLASH_CACHE_SIZE 初始化参数来配置多个闪存设备(仅在 Solaris 和 Oracle Linux系统中支持)。
1.2.2 缓冲器状态
数据库使用内部算法来管理高速缓存中的缓冲器。一个缓冲器可以处于以下任意一种彼此互斥的状态:
- Unused:缓冲器可用,且尚未被使用过;
- Clean:缓冲器曾被使用过,其中包含的数据是干净的,所以无需刷盘(checkpoint)。可以被数据库重用;
- Dirty:缓冲器包含被修改的数据,且未被持久化到磁盘。数据库必须 checkpoint 数据块才能重用。
每个缓冲器有 pinned 和 free (unpinned) 两种访问模式。缓冲器被 pinned 在高速缓存中以后,就不会在用户访问时被从内存中置换出去(age out)。一个 pinned 缓冲器不能同时被多个会话修改。
1.2.3 缓冲器模式
当客户端请求数据时,Oracle数据库以 current模式或者 consistent模式从 buffer cache 中获取缓冲器。
- current模式
current mode get,也称为 db block get,是指获取当前出现在buffer cache中的数据块。例如,如果一个未提交的事务更新了某个数据块中的两行数据,current mode get 会获取带有未提交行的该数据块。数据库最常在更新语句中使用 db block get,且必须只更新数据块的当前版本。
- consistent模式
consistent read get 用于获取数据块的一致性读版本(read-consistent version),且有可能用到 undo数据。例如,如果一个未提交的事务更新了某个数据块中的两行数据,并且有一个不相关的会话中的查询要请求访问该数据块时,数据库会使用undo数据来创建该数据块的一个一致性读版本(称为一致性读克隆)。创建的一致性读版本不会包括未提交的更新。
1.2.4 缓冲器 IO
逻辑 IO(logical I/O),即缓冲器IO(buffer I/O),是指在缓冲器高速缓存(buffer cache)中读写缓冲器(buffers)。当请求的缓冲器不在内存中时,数据库会进行物理IO从闪存缓存或者磁盘中将缓冲器拷贝到内存中,然后通过逻辑IO读入高速缓存的缓冲器。
1.2.4.1 缓冲器写
数据库写进程(DBW)周期性地将脏的缓存器写入磁盘。DBW进程在以下条件下会写缓冲器:
- 服务器进程找不到干净的缓冲器来向数据库 buffer cache读入新的数据块。随着缓冲器变成dirty状态,空闲的缓冲器数量会逐渐下降。如果下降到某个阈值,而这时又需要干净的缓冲器,服务器进程就会发信号给 DBW 来写缓冲器。数据库使用 LRU算法(Least recently used)来决定写哪个脏的缓冲器。
- 数据库必须推进检查点(checkpoint),即redo线程里实例恢复(instance recovery)必须开始的位置。
- 表空间被修改为只读状态或者下线(offline)的时候。
1.2.4.2 缓冲器读
当未使用的缓冲器数量很少时,数据库必须从buffer cache中移除缓冲器。
如果禁用了闪存缓存(flash cache),数据库会按需重用(re-use)每个干净的缓冲器,覆写它们。如果被覆写的缓冲器之后又需要用到,数据库就必须从磁盘中读出来。相反地,如果开启了闪存缓存,DBW可以将干净的缓冲器写入闪存缓存,之后如果再需用到该缓冲器,