Skip to content

Oracle 架构与存储 ​

Oracle 里要先区分两个概念:实例 Instance 和 数据库 Database。

零基础最容易把 Oracle 理解成“一个数据库进程加一堆表”。这不够。Oracle 的核心模型是:

实例负责运行,数据库负责存储。实例包含内存和后台进程;数据库包含数据文件、控制文件、Redo 文件等物理文件。SQL 通过实例执行,数据最终保存在数据库文件里。

SQL 从连接到返回的总流程 ​

mermaid
flowchart TD
    A["客户端连接"] --> B["Server Process"]
    B --> C["Shared Pool 查找或解析 SQL"]
    C --> D["优化器生成执行计划"]
    D --> E["Buffer Cache 读取数据块"]
    E --> F{"是否修改"}
    F -- "查询" --> G["基于 SCN 和 Undo 一致性读"]
    F -- "更新" --> H["生成 Undo 和 Redo"]
    H --> I["commit 时 LGWR 刷 Redo"]
    G --> J["返回结果"]
    I --> J

这条链路后面会反复出现:Shared Pool、Buffer Cache、PGA、Undo、Redo、SCN、LGWR、DBWR。

实例和数据库 ​

mermaid
flowchart TD
    A["Oracle Instance"] --> B["SGA 共享内存"]
    A --> C["后台进程"]
    D["Oracle Database"] --> E["数据文件"]
    D --> F["控制文件"]
    D --> G["Redo Log 文件"]
    A --> D
概念说明
Instance内存结构 + 后台进程
Database数据文件、控制文件、redo log 文件等

实例启动后加载数据库,用户连接实例执行 SQL。

为什么要区分实例和数据库 ​

问题如果不区分会怎样
数据在哪里以为数据在进程内存里,无法理解数据文件
宕机怎么恢复无法理解实例没了但文件还在,可以通过 redo 恢复
RAC 是什么无法理解多个实例访问同一个数据库
Data Guard 是什么无法理解主备通过 redo 保持数据库文件一致

实例是运行时能力,数据库是持久化文件。实例可以关闭再启动,数据库文件仍然存在。

常见后台进程 ​

进程作用为什么重要
DBWn把脏数据块写回数据文件commit 不直接刷所有数据块
LGWR把 Redo Log Buffer 写入 redo log 文件commit 是否成功依赖 redo 持久化
CKPT触发检查点并更新控制文件/数据文件头缩短恢复时间
SMON系统监控,做实例恢复等宕机后恢复相关
PMON进程监控,清理异常会话资源会话异常退出后释放资源
ARCn归档进程,归档 redo log归档模式下支持恢复

记忆方式:DBWR 写数据块,LGWR 写日志,ARCn 管归档,SMON/PMON 做清理和恢复。

SGA 和 PGA ​

内存作用
SGA多个进程共享,包括 Database Buffer Cache、Shared Pool、Redo Log Buffer
PGA单个服务进程私有,用于排序、Hash、会话状态等
mermaid
flowchart TD
    A["SQL 执行"] --> B["Shared Pool 解析和缓存执行计划"]
    A --> C["Buffer Cache 读取数据块"]
    A --> D["PGA 排序 / Hash"]
    A --> E["Redo Log Buffer 记录变更"]

SGA 内部关键区域 ​

区域做什么相关问题
Database Buffer Cache缓存数据块和索引块逻辑读、物理读、缓存命中
Shared Pool缓存 SQL、执行计划、数据字典信息软解析、硬解析、绑定变量
Redo Log Buffer暂存 redo 记录commit、LGWR、日志写等待
Large Pool大内存操作、备份恢复、并行等大任务资源

PGA 做什么 ​

PGA 是单个服务进程私有内存,常用于:

  1. 排序。
  2. Hash Join。
  3. 会话变量和游标状态。
  4. 连接会话的私有工作区。

如果排序或 Hash 数据太大,PGA 放不下,就可能使用临时表空间,导致 SQL 明显变慢。

Shared Pool、软解析和硬解析 ​

Oracle 执行 SQL 前要解析。相同 SQL 如果能复用已有游标和执行计划,就是软解析;如果不能复用,需要语法检查、语义检查、权限检查、优化器生成计划,就是硬解析。

mermaid
flowchart TD
    A["SQL进入 Oracle"] --> B{"Shared Pool 有可复用游标吗"}
    B -- "有" --> C["软解析"]
    B -- "没有" --> D["硬解析"]
    D --> E["语法、语义、权限检查"]
    E --> F["优化器生成执行计划"]
    C --> G["执行"]
    F --> G

为什么推荐绑定变量:

sql
select * from asset where asset_no = :assetNo;

如果应用每次拼接字面量:

sql
select * from asset where asset_no = 'A001';
select * from asset where asset_no = 'A002';

SQL 文本不同,游标复用率下降,Shared Pool 压力上升,高并发下可能出现大量硬解析。

表空间、段、区、块 ​

mermaid
flowchart TD
    A["Tablespace 表空间"] --> B["Segment 段"]
    B --> C["Extent 区"]
    C --> D["Block 块"]
    D --> E["Row 行"]

Oracle 最小 IO 单位是块。理解块之后,才能理解索引扫描、全表扫描、Buffer Cache 和行迁移。

存储层级怎么理解 ​

层级类比说明
Tablespace仓库区域逻辑空间,包含一个或多个数据文件
Segment一类对象的存储表段、索引段、Undo 段
Extent一批连续块空间分配单位
Block货架格子Oracle 读写的基本数据块
Row具体货物表中的一行数据

查询一行数据,底层不是“只读一行”,而是读取它所在的数据块。一个块里可能有多行。

ROWID 是什么 ​

ROWID 可以理解为 Oracle 定位一行物理位置的地址信息。普通 B-tree 索引叶子块保存 key 和 ROWID。查询通过索引找到 ROWID 后,再根据 ROWID 回表读取数据块。

mermaid
flowchart TD
    A["索引 key: asset_no"] --> B["找到 ROWID"]
    B --> C["根据 ROWID 定位数据块和行"]
    C --> D["读取表数据"]

这解释了为什么返回行数少时索引快,返回行数非常多时,索引 + 大量 ROWID 回表可能不如全表扫描。

Redo 和 Undo ​

机制作用
Redo记录数据块变化,用于崩溃恢复
Undo保存旧值,用于回滚和一致性读
mermaid
flowchart TD
    A["update 一行"] --> B["生成 Undo 旧值"]
    A --> C["生成 Redo 变更记录"]
    B --> D["支持回滚 / 一致性读"]
    C --> E["支持崩溃恢复"]

Undo 怎么支持一致性读 ​

Oracle 查询开始时会确定一个一致性读 SCN。若查询过程中遇到的数据块版本比这个 SCN 更新,就需要通过 Undo 找旧值,构造出查询开始时能看到的数据版本。

mermaid
flowchart TD
    A["查询开始,获得 SCN=100"] --> B["读取数据块"]
    B --> C{"数据块版本是否晚于100"}
    C -- "否" --> D["直接读取"]
    C -- "是" --> E["沿 Undo 找旧值"]
    E --> F["构造 SCN=100 时的版本"]

这就是为什么 Oracle 普通查询通常不会被正在更新的事务阻塞,因为查询可以读一致性旧版本。

Redo 怎么支持崩溃恢复 ​

更新时数据块可能只在 Buffer Cache 中修改,还没写回数据文件。只要 commit 时 Redo 已经落盘,宕机后 Oracle 就可以根据 Redo 把已提交修改重做出来。

如果没有 Redo,数据块没来得及写盘就宕机,已提交事务就可能丢失。

SCN ​

SCN 是 System Change Number,可以理解为 Oracle 内部的一致性时间点。Oracle 用 SCN 判断数据版本、恢复位置和一致性读。

SCN 出现在很多地方:

  1. 查询一致性读。
  2. 事务提交。
  3. 数据文件头。
  4. 控制文件。
  5. 归档日志和恢复。
  6. Data Guard 主备同步。

可以把 SCN 理解成数据库内部的“逻辑时间戳”。它不是用户时间,但用来判断数据版本先后。

Commit 到底做了什么 ​

mermaid
flowchart TD
    A["业务执行 update"] --> B["生成 Undo 旧值"]
    B --> C["修改 Buffer Cache 数据块"]
    C --> D["生成 Redo 到 Redo Log Buffer"]
    D --> E["commit"]
    E --> F["LGWR 刷 Redo 到 redo log 文件"]
    F --> G["生成提交 SCN"]
    G --> H["返回提交成功"]
    H --> I["DBWR 后台写数据块"]

重点:

  1. commit 必须保证 Redo 持久化。
  2. commit 不要求数据块马上写到数据文件。
  3. 数据块晚点刷盘没关系,因为 Redo 可以恢复。
  4. 如果 LGWR 慢,commit 会慢。

Checkpoint 是什么 ​

Checkpoint 会推动脏块写盘,并记录数据库恢复到哪里。它的作用不是“提交事务”,而是控制恢复成本。

mermaid
flowchart TD
    A["Buffer Cache 中有脏块"] --> B["Checkpoint 触发"]
    B --> C["DBWR 写部分脏块"]
    C --> D["更新数据文件头和控制文件信息"]
    D --> E["缩短实例恢复需要重做的日志范围"]

Checkpoint 越频繁,恢复时可能更快,但运行时写盘压力可能更高;过少则恢复时间可能变长。

商业场景:为什么查询不阻塞更新 ​

场景:资产采集任务正在更新设备状态,报表用户同时查询当天资产列表。

在很多数据库里,读写阻塞是高频问题。Oracle 的一致性读让普通查询可以基于查询开始时的 SCN 读取一致版本;如果某行已被更新但未提交,查询可以通过 Undo 看到旧版本。

这带来两个结果:

  1. 报表查询通常不会等更新事务提交。
  2. 长查询需要 Undo 保留足够久,否则可能出现 ORA-01555 snapshot too old。

所以长报表、大事务、Undo 保留时间是 Oracle 生产排查重点。

常见坑 ​

坑后果正确理解
分不清实例和数据库无法理解 RAC、恢复、文件结构实例运行,数据库存储
以为 commit 刷数据块无法解释 Redo 和 DBWRcommit 主要刷 Redo
不用绑定变量硬解析多,Shared Pool 压力大高并发用绑定变量
忽略 Undo长查询报快照过旧Undo 支持回滚和一致性读
只看 SQL 不看等待排查方向错误结合执行计划和等待事件

面试标准回答 ​

text
Oracle 架构要区分实例和数据库。实例由 SGA 共享内存和后台进程组成,数据库由数据文件、控制文件和 redo log 文件等组成。SGA 中有 Database Buffer Cache、Shared Pool、Redo Log Buffer,PGA 是进程私有内存,常用于排序、Hash 和会话工作区。Oracle 存储结构是表空间、段、区、块、行,块是重要的 IO 单位。查询通过 Shared Pool 解析和复用执行计划,通过 Buffer Cache 读取数据块;更新会产生 Undo 和 Redo。Undo 用于回滚和一致性读,Redo 用于崩溃恢复,SCN 用于标识数据库一致性时间点。commit 时 LGWR 刷 Redo 并生成提交 SCN,数据块可以由 DBWR 后台稍后写回数据文件。