首页 / 资讯中心 / 文章详情

Oracle 19c体系结构详解:内存、进程与存储全解析

Oracle 19c体系结构详解:内存、进程与存储全解析 ★ FEATURED ARTICLE
很多人学 Oracle 学了很久SQL 写得很溜备份恢复也会几个命令但一谈到体系结构就犯怵——总觉得那是 DBA 的事跟开发没什么关系。等真遇到性能问题、死锁问题或者 ORA-01555 这种报错的时候才发现对体系结构没概念排查起来就跟无头苍蝇一样。这篇东西就是给你把这层窗户纸捅破的我把 Oracle 19c 的体系结构按自己学习时的理解路径重新梳理了一遍不按官方文档的那种罗列方式讲而是按它到底是怎么转起来的这个逻辑来拆。19c 是 Oracle 长期支持版本里目前最主流的之一尤其在国内生产环境存量很大。它和 11g、12c 相比底层架构没有颠覆性变化核心还是那套实例 数据库的组合但很多细节是升级过的。这篇文章会覆盖内存结构、进程结构、存储结构、UNDO 与一致性读这几个核心模块最后补充一段我自己带新人时常用的一个体系结构速览法方便你把这堆知识点串成一张图。如果你正处在会写 SQL、但搞不懂 Oracle 为什么偶尔抽风的阶段或者你刚开始接触 19c RAC、ASM 这些概念觉得很懵那么这篇笔记就是给你准备的。已经在生产环境摸爬滚打多年的老手可以直接跳过前面几节重点看后面的排查思路部分。1. 内容整体设计与思路拆解先明确一件事Oracle 体系结构这东西如果按照官方文档的章节顺序去啃——从数据库实例开始一路讲到分布式架构——你会死得很惨。因为官方文档的信息密度极高每一句话都承载大量前置知识没有一定的实操经验做支撑读起来就是每个字都认识连起来不知道在说啥。我自己的学习路径是反着来的。先搞懂一个问题一条 SQL 从客户端发出来到数据库返回结果中间到底发生了什么把这条链路走通体系结构就不再是一堆死板的概念而是一套有序协作的流程。你只需要在这条链路上记住每个环节谁在干活、干完的活存在哪、活干完了东西怎么流转整个架构就活了。从 11g 到 19c这个核心模型一直没变变的只是组件内部的细节。比如 19c 里共享池的划分更加灵活自动内存管理AMM的算法也有改进但这都不影响你先掌握那个大框架。大框架是什么就是三件事内存SGAPGA、进程后台进程前台进程、文件数据文件控制文件日志文件。这三者之间的关系可以用一个比喻来帮助记忆整个 Oracle 数据库就像一家公司。数据文件是公司的账本所有最终的数据都存在账本里一页一页的。**SGA系统全局区**是公司的大办公室大家都在这个办公室里干活。账本不可能每人抱一本所以办公室里有几个公共桌面放的是大家频繁要用到的账页——这就是缓冲区高速缓存。**PGA程序全局区**是每个员工自己的工位私人的草稿纸、计算器、临时的排序结果都在自己工位上别人看不见也不能用。后台进程是公司的各职能部门有人负责把脏账页写回账本DBWn有人负责记账流水LGWR有人负责公司整体健康检查SMON有人负责盯门禁PMON。前台进程就是拿着 SQL 来办事的客户代表替客户把需求翻译成数据库能懂的操作。这套比喻虽然不能覆盖所有细节但对入门来说非常实用。你先在脑子里建立这个画面后面每个小节都是往这个画面里添砖加瓦。2. 核心细节解析与实操要点2.1 内存结构SGA 与 PGA 的分工逻辑先看内存。这是体系结构里最重要的一块因为 Oracle 的性能大头基本都在内存命中率上。SGASystem Global Area系统全局区是一块共享内存区域Oracle 实例启动时分配多个进程都能访问。它内部又分为几个关键组件数据库缓冲区高速缓存Database Buffer Cache这是数据在内存里的家。查询走索引、走全表扫描数据都要先从磁盘数据文件里读到这个缓冲区里。之后再次访问同样数据如果缓冲区里还有且未过期就直接从内存返回不再物理读磁盘。这个区域越大物理 I/O 越少系统性能越高。19c 里这部分默认由 SGA_TARGET 统一管理也可以单独设置 DB_CACHE_SIZE。共享池Shared Pool主要管三样东西。第一是库缓存Library Cache存放 SQL 和 PL/SQL 的解析结果包括执行计划第二是数据字典缓存Dictionary Cache存放表和列的元数据第三是各种内部结构。你想一条 SQL 执行前要做语法解析、语义检查、生成执行计划这个过程中涉及的中间产物全放在共享池里。如果共享池过小频繁发生硬解析CPU 直接飙高这是最常见的性能故障来源之一。日志缓冲区Redo Log Buffer所有对数据的修改在落盘之前会先记录一条重做日志到这个缓冲区。它是循环使用的空间不大默认值通常够用。LGWR 进程负责在特定时机把它刷到联机重做日志文件里。PGAProgram Global Area程序全局区是每个会话私有的内存区里面最重要的是排序区Sort Area和哈希区Hash Area。举个实际场景一条 SQL 里用了 ORDER BY排序动作如果能在 PGA 内存里完成就是内存排序很快如果排序数据量超过 PGA 限制就得把中间结果写到磁盘临时表空间里这时临时表空间就会增长SQL 响应时间也可能明显变慢。19c 里内存参数默认开启了自动管理AMM 或 ASMM除非你很明确自己在做什么否则不建议手工设死 SGA_TARGET 和 PGA_AGGREGATE_TARGET 的固定值容易造成配置僵化。我见到过不少生产事故是系统管理员为了调优把 SGA_MAX_SIZE 调得很大结果共享池分配不均反而频繁 ORA-04031。记住一句话自动管理是你的朋友手工精调永远是在你完全理解了内存模型之后才做的事。2.2 进程结构看不见的幕后员工Oracle 分为前台进程和后台进程。前台进程就是你执行的每个会话对应的服务进程负责处理 SQL。后台进程是实例启动时自动拉起的一组常驻进程各司其职。入门阶段你重点认识下面这几个就够用了SMONSystem Monitor系统监控进程。数据库崩溃后下次启动时由它负责实例恢复——把崩溃时没来得及完成的事务回滚掉把已提交但没写盘的数据恢复回来。平时如果产生了临时段残留也是它负责清理。PMONProcess Monitor进程监控进程。负责清理异常中断的会话、释放锁资源、回滚未提交事务并且会定期监听动态注册到监听器。DBWnDatabase Writer数据库写进程默认有多个DBW0~DBW9。它负责把缓冲区里被修改过的脏块写回数据文件。要注意它不是每次事务提交都写盘而是按照检查点机制和 LRU 算法批量写。这就是为什么系统突然断电时内存里可能还留着一些未落盘的修改需要靠联机重做日志来重演恢复。LGWRLog Writer日志写进程。事务提交时把日志缓冲区里的重做记录写到联机重做日志文件。它的写入时机是关键提交时立即写所以事务一旦返回 COMMIT 成功日志就一定落盘了数据块可能还没落盘。这是 Oracle 保证 ACID 的一项核心机制——先写日志后写数据简称 WALWrite-Ahead Logging。CKPTCheckpoint检查点进程。负责更新控制文件和数据文件头的检查点信息。它本身不写数据块但会触发 DBWn 写脏块。检查点出现时意味着该时间点之前的所有已提交数据都保证已经落盘。ARCnArchiver归档进程。数据库运行在归档模式时LGWR 写满一组联机日志后ARCn 会把这组日志复制到归档日志目录。生产库必须开归档模式否则你只能在零丢失和可恢复之间选一个。这里插一句热词相关的提醒如果你在搜 19c RAC 安装步骤应该已经注意到 RAC 环境里每个节点都有自己的 SGA、PGA 和后台进程实例之间通过高速私网通信同步缓存融合Cache Fusion的信息。但单实例和 RAC 的进程模型没有本质差异先把单实例的后台进程搞明白了再看 RAC 会省力很多。2.3 存储结构从逻辑到物理的两层映射存储结构是很多人最晕的部分因为 Oracle 有两套概念同时存在——逻辑存储表空间、段、区、块和物理存储数据文件、控制文件、日志文件。入门只需要记住一句话逻辑结构面向使用物理结构面向存盘。物理文件层面数据文件真实存放数据的地方后缀通常是 .dbf。一个表空间可以对应多个数据文件。控制文件数据库的大脑中枢记录数据库名、数据文件位置、日志文件位置、检查点信息、SCN 等关键元数据。它损坏了数据库就起不来。所以 19c 默认有多个多路复用副本和重做日志一样尽量放在不同的物理磁盘上。联机重做日志文件至少两组每组至少一个成员循环写入。如果一组日志坏了数据库会报错甚至停机生产环境务必多路复用。归档日志文件联机日志切换后保留的备份副本是进行时间点恢复PITR的基础。逻辑存储层面表空间Tablespace逻辑容器Oracle 里最顶层的逻辑单位。系统表空间 SYSTEM、SYSAUX、UNDO 表空间、TEMP 表空间都是系统自带的业务数据通常另外建 USERS、业务表空间。段Segment表、索引、分区中的每个分区都对应一个段。段是逻辑对象的存储载体。区Extent段由若干个区组成区是空间分配的最小单位。表每增长一定量就分配一个新的区。块BlockOracle I/O 的最小单位默认 8KB建库时可以调。块内有块头、空闲空间、行数据等部分行链接、行迁移、PCTFREE 这些概念都围绕块来理解。这两个层面的映射关系是你建了一张表 → Oracle 在指定表空间里创建一个段 → 段最开始分配一个或多个区 → 区由连续的块组成 → 块最终落在表空间对应的某个物理数据文件上。你在 SQL 里写 SELECT 时只关心表DBA 优化时才会关心到区和块。这个两层映射有什么实际意义至少两点。第一你理解了表空间对应数据文件就明白为什么一条 ALTER TABLESPACE ADD DATAFILE 命令能解决空间不足第二你理解了段由区组成就明白为什么一张频繁删除插入的表会产生空间碎片可能需要 SHRINK SPACE 或重建来回收空间。2.4 UNDO 与一致性读解决读不阻塞写、写不阻塞读UNDO 表空间存放的是事务修改前的旧值镜像。它的三个核心作用分别是回滚未提交事务、提供一致性读Consistent Read、支持闪回查询。你可能见过 ORA-01555: snapshot too old 这个经典报错它就是因为 UNDO 空间不足或保留期太短导致查询需要读取的旧版本数据已经被覆盖了。19c 里 UNDO 表空间默认使用自动扩展和自动调优保留期但也不是万能药。一张大表在做长查询的同时另一个会话持续大量 UPDATE 这条表就可能触发 ORA-01555。遇到这种场景要么扩大 UNDO 表空间要么用逻辑备份 分批提交的方式减小 UNDO 压力要么调整 UNDO_RETENTION。一致性读是 Oracle 多版本并发控制MVCC的核心机制当一个会话读取数据时它只会看到查询开始时间点之前已经提交的数据版本。实现方式是如果缓冲区里的数据块被另一个会话修改了查询进程会通过 UNDO 里的旧镜像构建出查询开始时刻的数据版本这个过程就是 CRConsistent Read。读操作不加锁写操作不加读锁这是 Oracle 并发能力的根基也是面试里高频考点。对于 19c 里的实际操作我建议你至少熟练这几个查询-- 查看 UNDO 表空间使用情况 SELECT tablespace_name, status, SUM(bytes)/1024/1024 AS undo_mb FROM dba_undo_extents GROUP BY tablespace_name, status; -- 查看当前 UNDO 保留期配置 SHOW PARAMETER UNDO_RETENTION; -- 查询某个时间点的历史数据闪回查询 SELECT * FROM your_table AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL 60 MINUTE);开发人员如果在代码里做长事务、大查询要留意 UNDO 压力。一条 UPDATE 影响一百万行UNDO 里就得存一百万行的旧值空间消耗非常大。生产环境常见的排查是UNDO 表空间一直涨、一直自动扩展最后把磁盘撑爆。根因往往不是系统参数而是业务侧一次性 UPDATE 全表或循环单条提交但没及时 COMMIT。3. 实操过程与核心环节实现3.1 快速摸清你的实例结构纸上得来终觉浅。体系结构这种知识最终要通过实际操作在脑子里固化下来。我建议你照着下面这套流程走一遍十几分钟就能把自己手上的 19c 实例结构摸得明明白白。第一步搞清楚实例和数据库的基本信息-- 查看实例名、数据库名、版本 SELECT instance_name, host_name, version, status FROM v$instance; -- 查看数据库创建时间、归档模式 SELECT name, created, log_mode, open_mode FROM v$database;第二步查看内存分配情况-- 查看 SGA 各组件大小 SELECT * FROM v$sga; -- 查看 SGA_TARGET 与 PGA_TARGET 的设置 SHOW PARAMETER sga_target; SHOW PARAMETER pga_aggregate_target; -- 查看共享池、缓冲区命中率 SELECT name, value FROM v$sysstat WHERE name IN (physical reads, session logical reads, physical writes);第三步查看后台进程SELECT paddr, program, background FROM v$process WHERE background IS NOT NULL;你会在输出里看到 PMON、SMON、DBW0、LGWR、CKPT、ARC0 等进程名。结合前面说过的职责你这一刻就能建立起实例 共享内存 一堆进程的直观印象。第四步查看文件层面的结构-- 控制文件位置 SELECT name FROM v$controlfile; -- 数据文件 SELECT file#, name, bytes/1024/1024 AS mb FROM v$datafile; -- 联机重做日志 SELECT group#, member FROM v$logfile; -- 表空间与数据文件的映射 SELECT t.name AS tablespace_name, d.name AS file_name, d.bytes/1024/1024 AS mb FROM v$tablespace t, v$datafile d WHERE t.ts# d.ts#;这套流程我在每次接手新环境时都会跑一遍相当于是给数据库做了一次体检式的信息摸底。你在学习阶段如果只记概念记不住就靠这套 SQL 把概念和实际数据对起来记忆会牢固很多。3.2 深入学习 SQL 执行链路体系结构不是死知识最终要落到一条 SQL 是怎么跑起来的。我强烈建议你自己做一次实验直观观察 SQL 在内存和文件之间的流转。-- 做一个简单的全表扫描查询 SET AUTOTRACE TRACEONLY STATISTICS; SELECT COUNT(*) FROM dba_objects;这条 STMT 看起来简单但在后台干了很多事Oracle 收到 SQL先去共享池的库缓存中查找有没有相同的 SQL 文本哈希匹配。没有的话做硬解析——语法检查、权限检查、生成执行计划并把执行计划存入库缓存。然后根据执行计划去访问数据如果要查的数据块不在缓冲区高速缓存里就从数据文件做物理读如果在就做逻辑读。读取过程中每一行数据都要按照一致性读规则确认版本最后把统计信息返回给你。你在 AUTOTRACE 的输出里能看到类似这样的信息Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 234 consistent gets 12 physical reads 244 redo size这一行行的统计信息其实就是体系结构的现场证据。consistent gets代表一致性读的次数physical reads代表真实从磁盘读的块数。如果 physical reads 长期远高于 consistent gets说明缓冲区命中率低I/O 压力大。这不是玄学是内存结构设计在起作用。我还碰到过不少初学者问为什么我每次执行同一条 SQL都要重新打开一遍执行计划答案就是共享池的硬化/软化解析差异。你可以在 V$SQL 里查看 SQL_ID、解析次数、执行计划SELECT sql_id, sql_text, executions, parse_calls, buffer_gets, disk_reads FROM v$sql WHERE sql_text LIKE SELECT COUNT(*) FROM dba_objects%;如果 parse_calls 远大于 executions说明这条 SQL 一直在做硬解析那就得检查是不是没有用绑定变量。绑定变量是共享池利用率的分水岭这几乎是我在所有性能调优实践里最先检查的项。3.3 用图表串联一张图记住全部结构很多人学体系结构的难点在于记忆分散。我建议你自己动手画一张Oracle 体系结构全景图不需要精美关键是流程完整。图的中心是SGA上方连接用户进程 → 服务进程 → PGA左侧连DBWn → 数据文件右侧连LGWR → 联机日志 → 归档日志下方连CKPT → 控制文件中间再加入共享池 → 库缓存/字典缓存缓冲区高速缓存与日志缓冲区并列。数据库打开时实例先在 SGA 中初始化各内存区然后由后台进程执行启动恢复SMON最后控制文件被读取数据文件和日志文件被打开。你如果已经在搜Oracle for ASM 命令这类内容说明你可能在往 RAC 方向进阶了。再补充一点ASM自动存储管理是 Oracle 自己的卷管理器和文件系统数据文件本质上是存放在 ASM 磁盘组里的。ASM 实例有一个独立的小 SGA有自己的一套进程如 RBAL、ABRn它不直接承载业务数据但负责磁盘组空间和 IO 分配是 RAC 环境的标配。不过你别被 ASM 吓到它和单实例体系结构不冲突只是在存储层多了一个管理代理。4. 常见问题与排查技巧实录4.1 共享池相关的典型问题ORA-04031: unable to allocate N bytes of shared memory是共享池问题里最著名的报错。它发生在共享池内存碎片化严重或者实际容量不足的时候。早期版本里有人试图通过增大 SHARED_POOL_SIZE 解决但效果往往不好。因为在 19c 的自动管理模式下共享池是 SGA 内部动态调优的改固定参数很容易引发其他组件被压缩产生新问题。正确排查路径是先看v$sgastat中共享池的 free memory 还有多少再看库缓存和字典缓存的命中率最后检查是不是存在大量非绑定变量的 SQL 频繁硬解析的情况。硬解析多了共享池被撑满free memory 几乎见底就会报 04031。解决手段通常是改写代码加绑定变量、清空共享池生产环境慎用、调整共享池预留空间参数SHARED_POOL_RESERVED_SIZE。4.2 监听和连接类问题Oracle 监听服务无法启动几乎是入门第一坑。我从自己排障和带人经验里总结出一套排查顺序第一步看监听日志位置在$ORACLE_HOME/network/log/listener.log。日志尾部通常是报错的直接原因。第二步确认listener.ora里配置的端口没有被占用。netstat -ano | grep 1521如果有进程占用了端口监听就起不来。Windows 上常见的是某个残留的 Java 服务抢走了端口。第三步检查防火墙和主机名解析。监听配置里如果写了主机名DNS 解析失败也会导致启动失败改成 IP 或者修正 /etc/hosts 就能解决。平时经常有人问连接数据库报 ORA-12541: TNS:no listener多半是监听没起来或者数据库和监听不在同一台服务器/端口。这时候先lsnrctl status看监听状态再tnsping看网络连通性基本能定位。4.3 UNDO 空间增长与事务控制UNDO 相关的误操作里最典型的就是开发在循环里一条条 UPDATE 不提交。每次修改都占用 UNDO 空间不提交就不释放UNDO 表空间就会被撑到自动扩展上限最后数据库 hang 住。遇到过几次这种事故之后我们团队形成了两条规矩大事务分批提交比如要更新一百万条数据按主键范围分 100 批每批一万条后 COMMIT这样 UNDO 里旧版本不会堆积过多。监控 UNDO 增长定时跑 SQL 查看 UNDO 使用量和当前活动事务发现异常增长时及时定位到对应会话。-- 查看当前活动事务关联会话信息 SELECT s.sid, s.serial#, s.username, s.sql_id, t.used_ublk, t.used_ublk * TO_NUMBER(p.value)/1024/1024 AS undo_mb FROM v$transaction t JOIN v$session s ON t.addr s.taddr JOIN v$parameter p ON p.name db_block_size WHERE s.username IS NOT NULL;这条 SQL 对排查固定会话导致 UNDO 一直不释放特别有用基本绕过所有概念直接找到现场。4.4 数据文件满的处理表空间不足应该算生产环境最高频的告警之一。标准流程是先确认哪个表空间满再看对应的数据文件在哪个磁盘上最后决定是加数据文件还是扩展现有文件大小。-- 查看表空间使用率 SELECT df.tablespace_name, ROUND(SUM(df.bytes)/1024/1024, 2) AS total_mb, ROUND(SUM(CASE WHEN f.bytes IS NOT NULL THEN df.bytes - f.bytes ELSE 0 END)/1024/1024, 2) AS used_mb, ROUND(SUM(f.bytes)/1024/1024, 2) AS free_mb FROM dba_data_files df LEFT JOIN dba_free_space f ON df.file_id f.file_id GROUP BY df.tablespace_name;然后按需执行-- 方式一给表空间加新数据文件 ALTER TABLESPACE users ADD DATAFILE /oradata/orcl/users02.dbf SIZE 10G AUTOEXTEND ON NEXT 512M MAXSIZE 32G; -- 方式二扩展现有数据文件 ALTER DATABASE DATAFILE /oradata/orcl/users01.dbf RESIZE 20G;这里有个很容易被忽略的细节数据文件是否开启了 AUTOEXTEND。如果没开即使磁盘还有空间表空间也会报unable to extend。所以新库创建表空间时我建议统一开启自动扩展并设置合理的 MAXSIZE 上限防止涨到无限大把磁盘打满。5. 实操心得把体系结构变成你的记忆地图如果让我用一句话总结 Oracle 19c 体系结构的学习重点那就是一切围绕着数据如何从磁盘到内存、再从内存回到磁盘这条主链展开。任何概念你都可以放到这条链上去验证自己是否理解——内存组件负责什么、哪个进程负责搬动数据、两个文件之间靠什么保持同步——链条通了体系结构就不再是死记硬背。我带新人时常用一个笨办法让他在纸上画出前面说的全景图不要求审查式标准但必须标注清楚每个组件和它相邻组件之间的数据流向。画完后再拿一条 UPDATE 语句走一次链路客户端 → 服务进程 → PGA → 日志缓冲区 → LGWR 写日志 → DBWn 写数据块 → CKPT 做检查点 → 归档进程归档。这个过程只要能流畅讲出来体系结构这个坎就算跨过去了。最后再分享一个小技巧遇到任何奇怪的报错第一时间不是去百度复制粘贴而是打开v$diag_info查告警日志的位置然后去$ORACLE_BASE/diag/rdbms/dbname/instname/trace/alert_instname.log看末段内容。告警日志里会记录 ORA 错误、ORA-600 内部错误、Block Corruption 等关键信息是排障的第一现场。把体系结构知识和这份日志对照着看才是提高经验的正确姿势。
阅读完成 · 觉得有帮助?
咨询建站