ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Oracle体系架构详解:从内存进程到存储优化

Oracle体系架构详解:从内存进程到存储优化 Oracle的体系架构是很多DBA和开发者的分水岭。刚接触时你可能觉得它只是一堆术语SGA、PGA、DBWn、LGWR、表空间、数据文件、控制文件、重做日志……背下来不难难的是真正出现问题时能不能顺着架构找原因。比如连接数打满是监听、进程还是会话出了问题SQL突然变慢是共享池、缓冲区还是执行计划的问题临时表空间爆掉是PGA太小还是排序量太大。这些问题如果不理解体系架构很容易乱调参数最后越调越怪。下面把Oracle体系架构拆成内存、进程、存储三层再结合日常SQL、常见故障和优化思路串一遍。适合刚学Oracle的人也适合用Oracle写业务但没系统看过架构的开发。目标是让你不仅记住名词还能在遇到问题时知道先看哪里。1. 先搞清楚 Oracle 体系架构到底在讲什么1.1 很多人记不住架构是因为先背了图没对应到真实场景网上流传的Oracle体系架构图通常画了很多方块和箭头SGA、PGA、DBWn、LGWR、CKPT、SMON、PMON、数据文件、控制文件、日志文件……看起来像一个工业系统。如果只是照着图背很快就会忘因为架构图是“静态的”而数据库运行是“动态的”。我更建议把架构理解成一条数据流客户端发一条SQL通过网络传到监听器监听器转发给服务进程服务进程在共享池里做解析在缓冲区里找数据块需要写日志时交给LGWR需要把脏块写盘时交给DBWn最后把结果返回给客户端。这一条链路上每一步都有对应的内存结构和后台进程。当你按这个链路去看架构图SGA和PGA就不再是孤立的方块而是整条链路上的“临时工作区”DBWn和LGWR也不再是名词而是“什么时机把内存数据落到磁盘”这个问题的两个答案。这才是体系架构真正有用的地方。1.2 实例、数据库文件、会话之间的边界Oracle体系架构里有一组特别容易混淆的概念实例Instance和数据库Database。简单说实例是内存结构和后台进程的集合数据库是磁盘上数据文件、控制文件、在线重做日志等文件的集合。一个实例可以加载一个数据库在RAC环境里多个实例同时加载同一个数据库。入门阶段先按“一个实例对应一个数据库”来理解不会跑偏。这里有个很实用的判断方法。数据库启动时会依次经历几个阶段nomount只启动实例读取参数文件分配SGA启动后台进程。mount读取控制文件让实例与数据库建立关联。open打开数据文件和在线重做日志允许用户访问。所以启动脚本里的startup实际是这几个阶段依次完成的。如果启动卡在nomount大概率是参数文件有问题如果卡在mount大概率是控制文件有问题如果卡在open大概率是数据文件、临时文件或日志文件有问题。这个对应关系背下来排错会快很多。1.3 用户进程、服务进程、后台进程各管什么还有一个容易混的点用户进程、服务进程和后台进程。用户进程是客户端程序比如SQLplus、Navicat、JDBC连接池。服务进程是在数据库服务器上专门为某一个会话处理SQL的进程。后台进程是全局性的不专属于某个会话比如DBWn、LGWR、SMON、PMON。连接出现问题的时候要先判断是哪一层。如果客户端连不上先看网络和监听器如果连接建立后SQL卡住再看服务进程、等待事件和锁如果整个数据库响应慢再看后台进程和内存、磁盘资源。很多人一遇到ORA-12541、ORA-12514就以为数据库坏了其实很多只是监听配置或服务名的问题。理解这个边界后至少不会把所有问题都归到“数据库挂了”这一个结论上。2. 内存结构SGA 和 PGA 决定你的数据库能扛多少并发2.1 SGA 里最该关注的组件SGA系统全局区是实例启动时分配的一块共享内存所有会话都能访问。里面最常被提到的几个组件是Shared Pool共享池用来缓存SQL、PL/SQL代码和数据字典信息。Buffer Cache缓冲区缓存用来缓存从数据文件读出来的数据块。Redo Log Buffer重做日志缓冲用来缓存事务产生的重做记录。Large Pool大池给并行操作、RMAN备份等场景使用。Java PoolJava池运行Java存储过程时使用。入门阶段优先理解Shared Pool和Buffer Cache。Shared Pool决定SQL解析快不快Buffer Cache决定数据访问快不快。你写一条SQL如果之前有人执行过相同文本的SQL解析结果可能直接命中Library Cache省掉硬解析你要查的数据如果已经缓存在Buffer Cache里就不用每次到磁盘读。2.2 PGA 为什么经常被漏看PGA程序全局区是每个服务进程私有的内存不共享。排序、哈希连接、位图操作、PL/SQL变量、游标运行时信息都可能占用PGA。很多人调内存只知道调SGA比如把SGA_TARGET调大却忘看PGA。结果遇到大量排序、哈希连接PGA不够用就把排序数据写到临时表空间导致临时表空间暴涨、SQL变慢。所以看到临时表空间增长不要急着只加tempfile先看PGA是否偏小或者SQL里是否存在不必要的排序。在自动内存管理下SGA和PGA可以动态调配。但要注意自动管理不等于“不用看”生产环境仍要观察实际使用量确认是否发生了交换、是否频繁出现disk sort。2.3 内存参数怎么调先看现象再动参数查看内存相关参数常用命令是SHOW PARAMETER sga_target; SHOW PARAMETER pga_aggregate_target;查看SGA各组件当前大小SELECT name, bytes/1024/1024 AS size_mb FROM v$sgainfo;查看PGA使用情况SELECT * FROM v$pgastat;这里要强调不要一上来就调大参数。你先要确认现象是什么。如果Shared Pool不足常见表现是大量硬解析、library cache竞争、CPU高如果Buffer Cache不足常见表现是物理读高、buffer busy wait多如果PGA不足常见表现是disk sort多、临时表空间增长快。调整方向可以简单归类现象可能原因优先处理思路CPU高硬解析多Shared Pool压力大绑定变量、优化SQL、增加Shared Pool物理读高缓存命中低Buffer Cache偏小或SQL扫描量太大检查SQL是否走索引再评估增大Buffer Cache排序多临时表空间增长快PGA不足或SQL排序量过大优化SQL减少排序评估增大PGAcommit慢日志写等待Redo Log Buffer、磁盘IO或归档慢观察LGWR等待检查日志文件所在磁盘调参时一次只调一个变量观察一段时间别同时改SGA和PGA又改并行度否则出问题很难定位。2.4 共享池与SQL解析为什么绑定变量重要在Oracle体系架构里SQL执行前要经过解析。第一次执行一条SQL需要做语法检查、语义检查、生成执行计划这个过程叫硬解析。如果同样文本的SQL已经执行过解析结果可能被缓存后面的执行直接使用叫软解析。硬解析非常消耗CPU和Shared Pool空间。如果业务系统大量拼接SQL比如把用户ID直接拼进字符串每条SQL文本都不一样硬解析数量就会非常高Shared Pool容易碎片化严重时整个数据库CPU都会被解析消耗掉。解决办法是使用绑定变量。比如JDBC里用PreparedStatementPL/SQL里用变量让SQL文本保持稳定。这不算什么高级优化但很多生产事故确实是从“大量硬解析”开始的。3. 进程结构从客户端连到数据库中间发生了什么3.1 建立一条数据库连接经过了哪些进程一条连接建立通常不是直接从客户端到数据库实例。客户端先访问监听器监听器负责接收连接请求。默认端口一般是1521。监听器确认服务名后会为这个会话创建一个服务进程服务进程再去访问SGA、读写数据文件。所以排查连接问题顺序很重要客户端能不能ping通数据库服务器。监听器是否启动lsnrctl status能看到什么。服务名、端口、防火墙是否配置正确。sqlplus / as sysdba在服务器本地能不能连接。连接数是否达到上限比如processes或sessions参数不够。很多“连不上数据库”的问题最后查出来不是数据库停了而是监听器没启动、服务名错误、连接数耗尽或防火墙拦截。理解了进程链路就不会一直围着数据库本身打转。3.2 关键后台进程DBWn、LGWR、CKPT、SMON、PMON后台进程里最需要理解的是这几个DBWn数据库写进程把Buffer Cache里的脏块写回数据文件。它不会每次提交都写数据文件而是在检查点、缓冲区不足或需要腾出空间时批量写入。LGWR日志写进程把Redo Log Buffer里的重做记录写到在线重做日志。事务提交时Oracle必须确保redo日志已经写成功所以LGWR的性能直接影响提交速度。CKPT检查点进程更新控制文件和数据文件头部的检查点信息并触发DBWn写脏块。SMON系统监控进程负责实例恢复、清理临时段、合并空闲空间。PMON进程监控进程监控其他进程会话异常断开时负责回收资源。DBWn和LGWR的差异很容易记混。记住一点事务提交时redo日志必须写盘但数据文件不一定马上写。因为redo是顺序写速度相对快数据文件是随机写批量写更高效。所以Oracle通过redo保证不丢数据再通过DBWn慢慢把数据块最终落盘。这就是“先记日志再写数据”的基本思想。3.3 用体系架构排查连接和锁等待连接卡住或者SQL等待时不要光看“卡住了”。要分层看连接建立前看监听状态、端口、网络。连接建立后看V$SESSION里会话的状态和等待事件。如果等待事件是锁相关比如enq: TX - row lock contention说明有会话持锁未提交阻塞了其他会话。如果等待事件是IO相关比如db file sequential read、db file scattered read要考虑索引和全表扫描以及磁盘性能。查看当前会话的常用SQLSELECT sid, serial#, username, status, event, sql_id FROM v$session WHERE username IS NOT NULL;如果确认某个会话占用资源异常或者阻塞了其他会话可以结合业务确认后终止会话ALTER SYSTEM KILL SESSION sid,serial#;这个命令要谨慎使用生产环境最好先和业务确认避免误杀正在执行的事务。3.4 后台进程异常怎么看后台进程状态可以通过V$BGPROCESS查看SELECT name, description, error FROM v$bgprocess WHERE paddr IS NOT NULL;正常运行的进程会有对应地址如果某个关键后台进程异常error列可能会有信息。更完整的诊断要看告警日志也就是常说的alert log通常存在diag_dest对应的目录里。数据库报错、进程异常、内部错误都会记录在那里。遇到奇怪问题第一步先打开alert log而不是反复重启。4. 存储结构表空间、数据文件、段、区、块4.1 从表空间到数据块一张表到底存在哪Oracle的存储结构可以按两层看。逻辑层是数据库包含多个表空间表空间包含段段包含区区包含数据块。物理层就是数据文件。一张表、一个索引、一个undo段、一个临时段在逻辑上都是“段”在物理上都落在数据文件里。数据块是数据库最小的存储单位常见大小是8KB。一个区是连续的一组数据块一张表初始分配一个或多个区随着数据增长再扩展。理解这个结构就能解释很多现象为什么一张经常删除和插入的表会碎片化因为段内的区可能变得不连续为什么某些表即使删除大量数据文件大小却没有减少因为段的高水位线不会自动降下来为什么TRUNCATE比DELETE快很多因为TRUNCATE是重置段DELETE是一条条删除并生成undo和redo。4.2 表空间和数据文件的常用操作创建表空间时一般会指定数据文件、初始大小、自动扩展策略和段空间管理方式。示例CREATE TABLESPACE app_data DATAFILE /u01/app/oracle/oradata/ORCL/app01.dbf SIZE 1G AUTOEXTEND ON NEXT 128M MAXSIZE 32G SEGMENT SPACE MANAGEMENT AUTO;参数含义SIZE 1G初始分配1GB。AUTOEXTEND ON NEXT 128M空间不足时自动扩展128MB。MAXSIZE 32G最大扩展到32GB。SEGMENT SPACE MANAGEMENT AUTO使用自动段空间管理减少手动设置存储参数。查询表空间和数据文件大小SELECT tablespace_name, file_name, bytes/1024/1024 AS size_mb FROM dba_data_files;查询表空间使用率可以用SELECT tablespace_name, used_percent FROM dba_tablespace_usage_metrics;这个视图在常见版本里都有比手工joindba_free_space更简单不容易算错。使用率持续高位时要先看业务增长再决定扩展还是清理历史数据。4.3 undo 和 redo 在体系架构中到底负责什么undo和redo是Oracle体系架构里最容易混淆的一对。可以这样记redo记录的是“做了什么修改”用来在数据库崩溃后重做保证事务不丢。undo记录的是“修改之前的样子”用来回滚事务、保证读一致性、支持闪回查询。一条UPDATE语句执行时既要生成undo记录保存修改前的值也要生成redo记录保存修改动作。undo本身也需要写redo来保护。是不是有点绕但这就是Oracle事务机制的一部分。日常遇到的现象大多能对应上ORA-01555 snapshot too old通常和undo保留时间不足、查询时间太长有关。undo表空间增长很快说明有大事务或大量更新操作。在线重做日志损坏可能导致实例无法正常切换日志甚至需要恢复。4.4 临时表空间和排序溢出临时表空间主要用于排序、哈希连接、临时表等操作。当PGA里的排序区不够用时Oracle会把排序中间结果写到临时表空间这个过程叫disk sort。大量disk sort会让SQL变慢还会让临时表空间快速增长。所以遇到临时表空间不足不要只加tempfile先看是否有SQL在做无谓的大排序。比如分页查询没有过滤条件把全表拿来做ORDER BY比如两个大表做哈希连接PGA不足比如DISTINCT、UNION使用过多。优化SQL往往比加临时文件更有效。如果确定需要增加临时表空间ALTER TABLESPACE temp ADD TEMPFILE /u01/app/oracle/oradata/ORCL/temp02.dbf SIZE 2G AUTOEXTEND ON NEXT 256M MAXSIZE 8G;5. 用体系架构解释日常 SQL 和优化问题5.1 树形查询 connect by start with 为什么和索引、连接方式有关Oracle的树形查询常用写法是START WITH指定根节点CONNECT BY PRIOR指定父子关系。比如机构表、物料BOM表都可能用到SELECT empno, mgr, level FROM emp START WITH mgr IS NULL CONNECT BY PRIOR empno mgr;这个查询在体系架构里会不断访问表数据每一层都要根据前一层的值去找下一层。如果根节点很多、层级很深扫描量会很大。通常优化思路是在关联字段上建立合适索引控制根节点范围避免在连接条件上使用函数必要时利用LEVEL过滤无谓分支。不要以为“它能查出树形结构”就够了。数据量上来后能不能高效执行取决于访问路径和执行计划。5.2 trunc(sysdate) 为什么让索引失效固定执行计划能解决什么很多人写过这种条件WHERE create_date TRUNC(SYSDATE);如果create_date列本身没有函数索引在列上使用函数后普通索引可能用不上。Oracle需要把每一行的create_date都做一次TRUNC再和右边的值比较。这种情况下优化器可能选择全表扫描。解决思路不是把条件改成BETWEEN就是建函数索引或者使用正确的范围写法WHERE create_date TRUNC(SYSDATE) AND create_date TRUNC(SYSDATE) 1;“固定执行计划”在Oracle里可以通过SQL Plan Baseline等方式实现。它的作用是当统计信息变化、数据分布变化导致执行计划变差时尽量保留一个已经验证过的稳定计划。但注意不要轻易固定一个有问题的计划。先把SQL改写、索引、统计信息这些基础工作做扎实再考虑固定计划。5.3 not exists、distinct、分页查询背后的资源消耗NOT EXISTS和NOT IN很多优化资料都会提醒NOT IN遇到子查询结果里有NULL时结果可能不符合预期。NOT EXISTS通常更安全。从架构角度看优化器可能会把NOT EXISTS转换成anti join执行时涉及外层表访问和子查询访问能不能走哈希、能不能走索引都影响性能。DISTINCT需要去重一般会触发排序或哈希。如果对大表做DISTINCTPGA不够就会用到临时表空间。Oracle分页常见写法是ROWNUM嵌套SELECT * FROM ( SELECT t.*, ROWNUM rn FROM ( SELECT * FROM emp ORDER BY empno ) t WHERE ROWNUM 20 ) WHERE rn 10;在12c及之后也可以直接写OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY。但要注意深分页意味着数据库需要生成、排序并丢弃前面的大量行越往后翻越慢。分页优化不能只看语法要看排序源和过滤条件。5.4 存储过程为什么能减少网络往返又为什么会有解析问题存储过程在数据库端预编译业务逻辑放在数据库里客户端只需要调用一次过程名不需要反复发送多条SQL。这样可以减少网络往返也方便复用执行计划。但在存储过程里如果大量使用动态SQL而且每次拼接的条件都不一样那就和业务系统里拼SQL一样会引发硬解析。PL/SQL里可以用批量绑定FORALL或BULK COLLECT减少上下文切换。大批量DML时逐行处理一条条执行和批量绑定一次性传递数组性能差别会非常明显。这不算复杂技巧但前提是理解Oracle执行SQL时的上下文切换开销。5.5 dual 表是什么最多能存多大dual是Oracle自带的一个特殊表通常用来执行不依赖具体表的表达式比如SELECT SYSDATE FROM dual; SELECT 11 FROM dual;它一般只有一个数据块不需要也不适合往里面插入业务数据。你可以把它理解成一个“空壳计算表”主要用来测试连接和计算表达式。体系架构上访问dual同样要走解析和数据访问流程但因为数据量极小通常都是缓存命中。6. 常见故障和排查顺序照着做能省很多时间6.1 数据库启动失败、监听连不上怎么查把问题分成两层实例问题和监听问题。实例问题先在服务器本地用sqlplus / as sysdba登录执行startup。如果启动到某个阶段失败看报错。常见原因包括参数文件路径错误或参数写错。控制文件丢失、损坏或被移动。数据文件、临时文件、redo log文件不可访问或权限不对。磁盘空间不足。监听问题用lsnrctl status看监听状态。如果监听没起用lsnrctl start启动。如果状态正常但客户端连不上检查使用的服务名是否注册。客户端tnsnames.ora中的端口、主机名、服务名是否正确。防火墙是否放通1521端口。数据库是否已经open。这个排查顺序是按链路来的比直接重装数据库靠谱得多。6.2 表空间满了、临时表空间不足怎么处理报ORA-01653、ORA-01650、ORA-01652时先确认是哪个表空间满了。查询表空间使用率SELECT tablespace_name, used_percent FROM dba_tablespace_usage_metrics ORDER BY used_percent DESC;如果是普通业务表空间满可以增加数据文件或允许自动扩展。但要注意自动扩展不能无限开磁盘本身容量是上限。最好配合监控设置合理阈值避免空间被打满后数据库直接不可用。如果是临时表空间不足先看有没有大排序SQL。可以通过V$SORT_USAGE找到正在使用临时空间的会话SELECT username, session_addr, sql_id, tablespace, contents, segtype FROM v$sort_usage;然后针对SQL做优化或者临时增加tempfile。只加tempfile不优化SQL问题可能很快重现。6.3 慢 SQL 和大批量任务怎么定位SQL变慢先看等待事件。在Oracle里V$SESSION的EVENT字段直接告诉你当前会话在等什么。是等CPU、等IO、等锁还是等日志写。确认等待类型才能决定优化方向。定位SQL的几个方向用V$SQL或V$SQLAREA按CPU_TIME、ELAPSED_TIME排序找消耗最高的SQL。对单条SQL生成执行计划看访问路径是索引扫描还是全表扫描。检查统计信息是否过期优化器可能因为统计信息不准走了差计划。检查是否存在绑定变量和硬解析问题。大批量任务比如数据迁移、批量导入导出需要注意资源占用。使用expdp/impdp时要评估导出文件磁盘空间、目标端表空间大小、并行度、日志记录。并行度不是越大越好开太多并行会把数据库IO打满影响生产业务。冷迁移这类操作通常需要停库把数据文件、控制文件、redo log、参数文件等整体拷贝到新环境。冷迁移对版本、补丁、操作系统字节序要求比较高。低版本迁到高版本相对常见高版本直接拿文件去低版本一般不支持。做之前先确认两边版本、补丁和文件路径配置避免拷过去打不开。6.4 归档、备份恢复和安全配置需要哪部分架构知识归档模式不开启时在线重做日志覆盖后历史redo会丢失数据库只能恢复到上次备份点。开启归档后日志文件切换时会生成归档日志为备份恢复和DG同步提供基础。做备份恢复时要理解数据库文件之间的关系控制文件里记录了数据文件、日志文件的位置和SCN信息数据文件里记录了文件自身的SCN恢复时通过比对SCN和归档日志把数据库恢复到一致状态。安全配置方面常见的检查会涉及补丁版本、账号权限、密码策略、审计配置、参数安全设置、数据文件权限等。比如查询数据库版本SELECT * FROM v$version;查看密码过期策略、审计是否开启都属于体系架构里“参数、进程和文件”的综合应用。不同组织的合规要求不同具体检查项要以实际要求为准。6.5 架构知识最后会沉淀成什么学到最后架构知识会变成一套排错顺序。看到磁盘IO高先想DBWn、LGWR和对应磁盘看到CPU高先想SQL解析、排序和慢SQL看到连接问题先想监听、进程和会话看到数据文件增长先想表空间、段和自动扩展。Oracle体系架构不是一张需要背下来的图而是数据库运行时的地图。你只需要知道当某个方向出问题时该往哪张图、哪个视图、哪类日志里去找答案。我自己踩过几次坑之后最大的感受是很多问题不是Oracle能力不够而是前置理解没到位。比如不知道LGWR和DBWn的区别就会把commit慢误判成数据文件慢不知道PGA和临时表空间的关系就会在加tempfile和不加之间反复纠结不知道实例和数据库的边界启动失败时连该先查参数文件还是控制文件都分不清。把这些基础框架搭好后面的排查才会变成顺藤摸瓜而不是东敲西试。
返回列表