Oracle 体系结构深度解析:从内存、进程到日志与事务一致性的全链路技术详解


一、体系结构总览:一句话理解 Oracle 实例

Oracle 体系结构可以浓缩为一句话:"6 大共享池、5 大后台进程、3 大文件"。

  • 内存结构(SGA + PGA):SGA(System Global Area)由 Shared Pool、Database Buffer Cache、Redo Log Buffer、Large Pool、Java Pool、Streams Pool 等组成;PGA(Program Global Area)为每个服务器进程私有。
  • 后台进程:DBWn、LGWR、CKPT、PMON、SMON 等。
  • 三大核心文件 :
    • 控制文件(Control File):记录各文件的存放位置以及数据库当前的运行状态;
    • 数据文件(Data File):存放实际数据;
    • 重做日志文件(Redo Log File):记录对数据文件的所有修改。

实例与数据库的关系:生产环境常见多个实例(一般为 2、4、8 个)对应一个数据库,即 RAC 技术------日常实现负载均衡(LB),单实例故障时仍能继续运行(HA)。

运维关注重点 :对生产库而言,服务器进程(前台进程)数量远大于后台进程,因为一个用户进程对应一个服务器进程;后台进程一般不易出问题,因此学习与优化的重点是服务器进程与 PGA 的关系(也最容易出问题)。


二、SQL 语句执行过程剖析

1. 读取数据:解析 → 执行 → 获取

text 复制代码
解析(Parse) → 执行(Execute) → 获取数据(Fetch)

解析分为硬解析 与软解析(实际还有软软解析):

  • 硬解析 :判断 SQL 语法、表是否存在、是否有权限、并挑选最优执行计划------这是最耗时、最耗费 CPU 与 I/O 的环节;
  • 软解析:在 Shared Pool 的 Library Cache 中找到已缓存的 SQL 与执行计划,不再重新选择执行计划,节约大部分时间。

2. 逻辑读与物理读

  • L I/O(逻辑读,内存读):消耗 CPU 资源;
  • P I/O(物理读,硬盘读):消耗 I/O 资源。

Database Buffer Cache 用于缓存数据文件的数据块。若用户查询的块不在 Buffer Cache 中,则从数据文件读取并放入 Buffer Cache,再返回给用户。

命中率:命中率低一定有问题,命中率高不一定没问题------还要关注此时系统每秒的物理读是多少。

bash 复制代码
# 系统级观测
vmstat 1 10
iostat 1 10
mpstat 1 10
top
free

3. 修改数据:只改内存

SQL 修改数据时只修改 Buffer Cache 中的数据 ,效率高。注意:Server Process 不负责写盘,写盘由后台进程(DBWn、LGWR)完成。这是 Oracle 的一个设计技巧------把用户不关心的事交给后台进程,把用户关心的交给 Server Process,因此后期优化也主要针对 Server Process 进行。


三、Shared Pool、SQL 共享与绑定变量

1. Shared Pool 的组成

Shared Pool 由三块区域组成:

区域 作用
free 空闲内存部分
library cache 缓存 SQL 语句及其执行计划
row cache 数据字典缓存

只可整体设置 Shared Pool 大小,不能对其内部区域分别设置。Shared Pool 中容易出问题的是 free 与 library cache。

观测命令:

sql 复制代码
SELECT * FROM v$sgastat a WHERE a.name = 'library cache';
SELECT * FROM v$sgastat a WHERE a.pool = 'shared pool' AND a.name = 'free memory';
SELECT * FROM v$sgastat a WHERE a.name = 'row cache';

-- 查看 Shared Pool 中的 chunk 数量
SELECT count(*) FROM x$ksmsp;

2. 硬解析与 ORA-4031

硬解析时需从 free 中寻找合适大小的 chunk。若硬解析失败,会报经典错误 ORA-4031。

ORA-4031 的两大成因:

  1. 系统产生大量硬解析;
  2. 大量硬解析产生大量碎片,此时又来一个需要大块空间的 SQL,而 free 空间不足(可能本身空间有剩余,但都是碎片,没有符合需求大小的连续块),导致报错。

3. 减少硬解析的手段

  • 共享 SQL:统一书写风格,让 SQL 完全相同;
  • 使用绑定变量。
sql 复制代码
-- 使用绑定变量使 SQL 共享
DECLARE
  v_sql varchar2(50);
BEGIN
  FOR i IN 1..10000 LOOP
    v_sql := 'insert /*jingyu*/ into test values(:1)';
    EXECUTE IMMEDIATE v_sql USING i;
  END LOOP;
  COMMIT;
END;
/

-- cursor_sharing 参数(可解决字面值未用绑定变量的问题,尽量先让开发改)
show parameter cursor
alter system set cursor_sharing='force';

查找未共享的 SQL:

sql 复制代码
spool 1.txt
SELECT sql_fulltext FROM v$sql WHERE executions=1 ORDER BY sql_text;
spool off

注意:结果不一定都是未共享的 SQL,也可能是该 SQL 本就只执行了一次。

查看硬解析更直观的方法:

sql 复制代码
SELECT name, value FROM v$sysstat WHERE name LIKE 'parse%';

查看 library cache 命中率(易出问题,正常应很接近 100%):

sql 复制代码
SELECT sum(pinhits)/sum(pins)*100 FROM v$librarycache;

查看 row cache 命中率(一般没问题):

sql 复制代码
SELECT sum(gets), sum(getmisses), 100*sum(gets-getmisses)/sum(gets) FROM v$rowcache;

查看某条 SQL 的执行计划:

sql 复制代码
-- 先在 v$sql 中确认 sql_id,再:
SELECT * FROM table(dbms_xplan.display_cursor('g4pkmrqrgxg3b'));

4. ORA-4031 的处理与规避

  1. ALTER SYSTEM FLUSH SHARED_POOL;(慎用------之后会产生大量硬解析,能解决 4031 但治标不治本);
  2. 共享 SQL(统一风格 + 绑定变量);
  3. dbms_shared_pool.keep('大的对象名'); 将大对象常驻;
  4. 保留区:在 Shared Pool 中单独划出一块空间只放大对象,设置足够大可减少很多 4031。
sql 复制代码
-- 查询保留区请求未命中数,结果应为 0;若大于 0,需调整 shared_pool_reserved_size
SELECT request_misses FROM v$shared_pool_reserved;
  1. 增加 Shared Pool 空间:
sql 复制代码
SELECT component, current_size FROM v$sga_dynamic_components;
show parameter sga_target
show parameter sga_max_size
alter system set shared_pool_size=150M scope=both;

版本差异(重要) :10g 之后引入统一的动态参数 sga_target,sga_max_size 为静态参数用于约束 sga_target。若设置了 sga_target,Shared Pool 大小由系统自动分配;手工配置若小于自动分配值,Oracle 会直接忽略,此时 show parameter sga 显示就不准确了。

5. Shared Pool 到底该设多大?

  • 若 SQL 未共享、硬解析非常多,Shared Pool 的作用是反向的------设得越大反而越不好;
  • 10g 以前不超过 1GB;10g 以后可以超过 1GB、2GB、5GB,但也不建议设太大;
  • 可借助 EM 的"指导中心 → 内存指导 → 建议"查看建议值。

四、Database Buffer Cache

1. 段、区、块的概念

sql 复制代码
create table t2 (id int, name varchar2(30));

建表的同时会建立一个段 ;建段时会给段分配一个区(物理上连续的几个块)。

  • 区(Extent):Oracle 给段分配的最小单位;
  • 块(Block):Oracle I/O 的最小单位。

一般情况下一个块中有多个行(行链接、行迁移除外)。

2. Buffer Cache 的意义

  1. 减少 I/O(物理 I/O、逻辑 I/O);
  2. 构造 CR 块------Oracle 在修改数据之前会先将数据写入 undo。

undo 的两个作用:回滚未提交事务、构造 CR 块。

3. 内存组织结构

结构 作用
CBC(cache buffers chains) 按块地址将 buffer 链起来
LRU / LRUW LRU 按最近最少使用顺序链起可用块;LRUW 为脏块链,DBWn 以此为标准优先写最近最少使用的脏块
CHECKPOINT QUEUE 关于脏块,按块第一次变脏的时间点链起来

Oracle 中一般采用双向链。

4. DBWn 进程数

sql 复制代码
show parameter writer
alter system set db_writer_processes = 2 scope=spfile;
-- DBWn 数量一般设定为 服务器核心数/8

5. 重要参数配置

sql 复制代码
alter system set db_cache_size=200m scope=both;

设置顺序 :sga_max_size → sga_target → db_cache_size

  • OLTP 系统中,Buffer Cache 一般设为 sga_max_size 的 2/3;
  • 经验区间:DB_CACHE_SIZE = SGA_MAX_SIZE/2 ~ SGA_MAX_SIZE*2/3;
  • 可用 advice 视图确认合适大小。

6. Block 状态与热块诊断

sql 复制代码
SQL> desc x$bh   -- buffer header

state 取值 0~8:0=free,1=XCUR,2=SCUR,3=CR,4=READ,5=MREC,6=IREC,7=write,8=pi。

非 RAC 环境下 current 永远等于 xcur;RAC 下存在 scur。

current 块与 CR 块区别 :CR 块被构造读出后马上失效、可被覆盖;而要修改一个块,只能修改 current 块。

查看一个对象占用了多少不同状态的 buffer:

sql 复制代码
SELECT o.object_name,
       decode(state,0,'free',1,'xcur',2,'scur',3,'cr',4,'read',5,'mrec',6,'irec',7,'write',8,'pi') state,
       count(*) blocks
FROM x$bh b, dba_objects o
WHERE b.obj = o.data_object_id AND o.object_name = 'T2'
GROUP BY o.object_name, state
ORDER BY blocks DESC;

-- 实验前可先执行
alter system flush buffer_cache;

寻找热块(逻辑读次数多即热块,看 TCH 列):

sql 复制代码
SELECT obj object, dbarfil file#, dbablk block#, tch touches
FROM x$bh WHERE tch > 10 ORDER BY tch ASC;

查询当前空闲空间比例(最好控制在 10% 以内):

sql 复制代码
SELECT decode(state,0,'FREE',1,decode(lrba_seq,0,'AVAILABLE','BEING USED'),3,'BEING USED',state) "BLOCK STATUS",
       count(*)
FROM x$bh
GROUP BY decode(state,0,'FREE',1,decode(lrba_seq,0,'AVAILABLE','BEING USED'),3,'BEING USED',state);

最浪费内存的前 10 个语句占比(建议控制在 5% 以内):

sql 复制代码
SELECT sum(pct_bufgets) "Percent"
FROM (SELECT rank() OVER (ORDER BY buffer_gets DESC) AS rank_bufgets,
             to_char(100 * ratio_to_report(buffer_gets) OVER(),'999.99') pct_bufgets
      FROM v$sqlarea)
WHERE rank_bufgets < 11;

找出消耗物理 I/O 最大的 SQL:

sql 复制代码
SELECT disk_reads, substr(sql_text,1,4000) FROM v$sqlarea ORDER BY disk_reads ASC;

风险提示 :flush buffer_cache / flush shared_pool 均属高危操作,会引发大量物理读/硬解析,仅在测试环境或确有需要时使用。


五、日志与检查点原理

学习 Oracle 数据库归结为两个目标:保证数据一致性 、提高性能。日志的功能只是保证数据一致性。

1. 归档模式配置

sql 复制代码
alter database archivelog;
ARCHIVE LOG LIST
SELECT log_mode FROM v$database;
alter database noarchivelog;

ALTER SYSTEM ARCHIVE LOG CURRENT;
ALTER SYSTEM ARCHIVE LOG ALL;
ALTER SYSTEM SET LOG_ARCHIVE_MAX_PROCESSES=3;

alter system set log_archive_dest = '/u01/app/oracle/archivelog1' scope = spfile;
alter system set log_archive_duplex_dest = '/u01/app/oracle/archivelog2' scope = spfile;
alter system set log_archive_dest_1 = 'LOCATION=/u01/app/oracle/archivelog3';
alter system set log_archive_dest_2 = 'SERVICE=standby1';
alter system set log_archive_format = 'arch_%t_%s_%r.arc';

相关视图:

sql 复制代码
SELECT dest_name,status,archiver,destination,log_sequence,reopen_secs,transmit_mode,process FROM v$archive_dest;
SELECT name,sequence#,registrar,standby_dest,archived,status FROM v$archived_log;
SELECT NAME,STATUS FROM v$archived_log;
SELECT * FROM v$logfile;
视图 含义
v$archived_log 从控制文件中获得归档相关信息
v$archive_dest 归档路径及状态
v$log_history 控制文件中日志的历史信息
v$database 查看数据库是否处于归档状态
v$archive_processes 归档相关的后台进程信息

2. Write-Ahead-Log 与 LGWR

日志写入优先(Write-Ahead-Log) :LGWR 绕过 OS 缓存直接写入磁盘,但绕不过存储的写缓存。

LGWR 触发条件:

  1. 用户提交;
  2. 有 1/3 重做日志缓冲区未被写入磁盘;
  3. 有大于 1MB 的重做日志缓冲区未被写入磁盘;
  4. 每隔 3 秒钟;
  5. DBWn 需要写入的数据的 SCN 大于 LGWR 记录的 SCN,DBWR 触发 LGWR 写入。

Log Buffer 大小:

sql 复制代码
SELECT * FROM v$sgainfo WHERE name IN ('Fixed SGA Size','Redo Buffers','Granule Size');
  • 9i 以前一般 3M;10g 中 Oracle 自动调整,原则是 'Fixed SGA Size' + 'Redo Buffers' 为 granule size 的整数倍;
  • 10.2.0.3 默认 14M,10.2.0.4 默认 15M。

3. 日志优化建议

  • OLTP 系统中 REDO LOG 写操作以小而频繁为主,一般写大小几 KB,每秒写 IO 次数可达几十、数百甚至上千次。因此 REDO LOG 文件适合存放在 IOPS 高的高速磁盘上,仅数百 IOPS 的 SATA 盘不适合存放;
  • REDO LOG 写入是串行的,因此底层条带化对 REDO LOG 写性能提升十分有限;
  • REDO LOG 切换时间应尽可能不低于 10--20 分钟:
sql 复制代码
SELECT to_char(FIRST_TIME,'yyyy-mm-dd hh24:mi:ss') f_time, SEQUENCE# FROM v$log_history;

日志维护操作:

sql 复制代码
alter database add logfile group 5 '/opt/oracle/oradata/dbtest/redo05_1.log' SIZE 10M;
alter database add logfile member '/opt/oracle/oradata/dbtest/redo04_3.log' to group 4;
alter database drop logfile group 5;
alter database drop logfile ('/opt/oracle/oradata/dbtest/redo05_1.log','/opt/oracle/oradata/dbtest/redo05_2.log');

4. 检查点队列(Checkpoint Queue)

关键地址概念:

  • RBA:日志块地址(Redo Block Address);
  • LRBA:第一次被脏的地址;
  • HRBA:最近一次被脏的地址;
  • On disk RBA:current redo log 中最后一条日志的地址。

核心机制:

  • 检查点队列就是按数据块的 LRBA 地址链起来的;
  • CKPT 进程:每隔 3 秒触发一次,记录检查点信息并触发 DBWR;
  • 完全检查点:将所有脏块写入磁盘,只有正常关闭时才会发生,正常运行期间基本不会发生;
  • 增量检查点:CKPT 将检查点队列中最早脏块对应的 LRBA 地址记录到控制文件,每 3 秒发生一次。

增量检查点不会更新数据文件头以及控制文件中数据库 SCN、数据文件条目 SCN 信息,只是每 3 秒由 CKPT 更新控制文件中的 low cache rba(检查点位置)。

查看检查点位置:

sql 复制代码
SELECT CPDRT,
       CPLRBA_SEQ||'.'||CPLRBA_BNO||'.'||CPLRBA_BOF "LowRBA",
       CPODR_SEQ||'.'||CPODR_BNO||'.'||CPODR_BOF "On disk RBA",
       CPODS, CPODT, CPHBT
FROM x$kcccp;
列 含义
CPDRT 检查点队列中的脏块数目
CPODS on disk rba 的 SCN
CPODT on disk rba 的时间戳
CPHBT 心跳

实例崩溃恢复原理:崩溃后重启,Oracle 到控制文件读取 low cache rba(检查点位置),从此处开始应用重做日志,应用到 on disk rba 位置,即完成前滚。

sql 复制代码
SELECT checkpoint_change# FROM v$database;
ALTER SYSTEM CHECKPOINT;
ALTER SYSTEM SWITCH LOGFILE;
SELECT name,checkpoint_change# FROM v$datafile;
SELECT name,checkpoint_change# FROM v$datafile_header;
SELECT * FROM v$log;

检查点队列的意义:找到跑日志的起点,加快实例崩溃后 Oracle 的启动速度。Oracle 8 之前没有检查点队列,确定不了日志起点,要跑很多日志,启动很慢。


六、SCN(System Change Number)

1. SCN 的意义

SCN 代表"时间/先后/新旧",是保证数据一致性的核心。

sql 复制代码
SELECT dbms_flashback.get_system_change_number,
       SCN_TO_TIMESTAMP(dbms_flashback.get_system_change_number) FROM dual;

2. 常见 SCN 位置

控制文件的三个 SCN:

sql 复制代码
-- 系统 SCN
SELECT checkpoint_change# FROM v$database;
-- 文件 SCN
SELECT name,checkpoint_change# FROM v$datafile;
-- 结束 SCN
SELECT name,last_change# FROM v$datafile;

数据文件头部(开始 SCN):

sql 复制代码
SELECT name,checkpoint_change# FROM v$datafile_header;

日志文件头部(first / next SCN):

sql 复制代码
SELECT recid,sequence#,first_change#,next_change# FROM v$log_history WHERE rownum<6;

3. 一致性判断

正常情况下,控制文件的系统 SCN、文件 SCN 与数据文件头部的 SCN 应一致。

  • 正常关闭:更新系统 SCN、文件 SCN、终止 SCN、数据文件头部 SCN;
  • 非正常关闭 :终止 SCN 为空,其余相同,需进行实例恢复------只需 redo log,不需要归档 log。

实例恢复判断依据 :启动数据库时,检测到控制文件的终止 SCN 为空就需要做实例恢复。

4. 恢复相关名词

  • 跑日志:跑多了没关系,不会重复应用两次,只会空跑;
  • 提升 SCN:若某数据文件是旧的,需应用归档日志、重做日志使其 SCN 提升至与系统 SCN 一致。

5. fast_start_mttr_target

sql 复制代码
-- 默认 0,表示 Oracle 自动调节;单位是秒

若设为 20 秒,实例恢复前滚日志时 Oracle 会尽量控制在 20 秒内,并加大 DBWn 写的频率。若时间过短,DBWn 写频率过大,I/O 会很繁忙,可能出问题。


七、PGA 与内存管理

1. PGA 的作用与构成

PGA 构成:

  1. private SQL area;
  2. Session Memory(保存会话变量、登录信息等);
  3. SQL Work Areas。

2. Dedicated Server 与 Shared Server

目前大多使用 Dedicated Server(专用服务器) ;若是大型电商网站,访问很多、单负载很小,则用 Shared Server。

3. 重要参数

PGA_AGGREGATE_TARGET:

  • OLTP:PGA_AGGREGATE_TARGET = (total_mem * 80%) * 20%(典型 PGA 为总内存的较小部分);
  • DSS:PGA_AGGREGATE_TARGET = (total_mem * 80%) * 50%(DSS 会运行大查询,PGA 最多可分配 70% 内存)。
sql 复制代码
alter system set workarea_size_policy=auto scope=both;
alter system set pga_aggregate_target=512m scope=both;

WORKAREA_SIZE_POLICY 相关(手工管理时): sort_area_size、sort_area_retained_size、hash_area_size、hash_join_enable、bitmap_merge_area_size、create_bitmap_area_size、open_cursors、_pga_max_size。

4. 重要视图

sql 复制代码
SELECT * FROM V$PGASTAT;

SELECT pga_target_for_estimate/1024/1024 ||'M' "Estimate PGA Target",
       estd_pga_cache_hit_percentage "Cache Hit(%)",
       estd_extra_bytes_rw/1024/1024 ||'M' "Extra Read/Write",
       estd_overalloc_count "Over alloc count"
FROM v$pga_target_advice;

SELECT * FROM V$SYSSTAT WHERE name LIKE '%sort%';

SELECT name,value FROM v$statname a, v$mystat b
WHERE a.statistic#=b.statistic# AND a.name LIKE '%pga%';

VSQLWORKAREA/VSQL_WORKAREA / VSQLWORKAREA/VSQL_WORKAREA_ACTIVE 用于查看 SQL 工作区。

V$PROCESS:查看各进程 PGA 使用。

sql 复制代码
SELECT spid,program,pga_max_mem,pga_alloc_mem,pga_used_mem,pga_freeable_mem
FROM v$process WHERE PROGRAM LIKE '%jiagulun%';

八、事务、Undo 与读一致性

1. 事务基本概念与 ACID

一组 DML 语句构成事务:

sql 复制代码
COMMIT;
ROLLBACK;
SAVEPOINT <savepoint_name>;
ROLLBACK TO [SAVEPOINT] <savepoint_name>;

四大特性:

  • 原子性(Atomicity):事务中所有操作要么都做、要么都不做;
  • 一致性(Consistency):事务前后数据都必须满足业务规则约束;
  • 隔离性(Isolation):防止多个并发事务交叉执行导致数据不一致;
  • 持久性(Durability):事务提交后修改永久保存,系统故障也不丢失。

隐式提交与回滚 :DDL、退出(正常退出会隐含提交)。任何 DML 都应显式提交或回滚,不要让 Oracle 隐式提交或回滚。

隔离级别:

sql 复制代码
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET TRANSACTION ISOLATION LEVEL READ COMMITED;
SET TRANSACTION READ ONLY;
SET TRANSACTION READ WRITE;

2. Undo 表空间与管理

undo 表空间中 undo 段是自动生成的。作为高级 DBA,需要了解 Oracle 如何使用 undo 段,才能解决性能问题。

sql 复制代码
show parameter undo_tablespace
show parameter undo
SELECT * FROM v$rollname;
SELECT owner, segment_name, tablespace_name FROM dba_rollback_segs;
SELECT name FROM v$parameter WHERE name LIKE '%undo%';

undo 的三个作用:

  1. 事务回滚(rollback);
  2. 读一致性,构造 CR 块;
  3. 实例恢复,回滚未提交事务。

Undo 段中区的四种状态:free、expired、inactive、active。

sql 复制代码
SELECT extent_id, bytes, status FROM dba_undo_extents WHERE segment_name='_SYSSMU1$';

undo_retention:undo 段中区状态为 inactive 的保留时间。

sql 复制代码
alter tablespace undotbs1 retention guarantee;    -- 强制保留
alter tablespace undotbs1 retention noguarantee;

3. 事务操作流程小结

  • ITL 中 UBA 指向 data block 的最后一个 undo block 地址,undo block 之间相互指向,用于回滚;
  • Data block header 与 Undo block 的直接指向,用于更快速构造 CR 块;
  • ITL 中 XID 指向 undo segment header,是为了多种提交方式。

一个事务开始后,至少要在两个位置写入事务信息:①回滚段段头块的事务表 ;②要修改的数据块头部的事务槽(找一个事务槽写入事务信息)。

4. IMU 机制

传统 undo 中,Oracle 将 undo 表空间和普通表空间同等对待。引入 IMU 后,事务需要回滚块时不再需要从磁盘调取,直接在 Shared Pool 的 IMU buffer 中读取 ,大幅提高了构造 CR 块的速度。RAC 和 Stream 环境中 IMU 被禁止。

sql 复制代码
SELECT * FROM v$sysstat WHERE name LIKE '%IMU%';
-- 关注 IMU commits 和 IMU Flushes,若一直增加,说明开启了 IMU

5. 读一致性

示例:9:00 开始查询一张返回 1 万条记录的表;9:01 其他用户删除第 1 万条并提交;9:02 查询结束------返回结果应为 1 万条还是 9999 条?

答案:Oracle 返回 1 万条。因为查询时会先对当前状态做快照,记录一个当前 SCN;查询过程中若发现某块的 SCN 大于当前 SCN,就说明该块在查询过程中被修改了,需要从 undo 构造 CR 块。

6. ORA-01555 "Snapshot too old"

成因:

  1. SQL 执行时间太长;
  2. undo 表空间压力太大;
  3. undo 表空间大小设定不足------取决于最长执行 SQL 的时间及需闪回的时段。

处理思路:通过 EM 的 undo 表空间建议图,根据时间找到合适的 undo 表空间大小参考值。生产上应关注长查询与高并发更新叠加、延迟块清除、跨提交 fetch、回滚段损坏等场景,可通过分离读写负载、扩大 undo 空间缓解。


九、锁机制:Latch 与 Lock

1. 锁类型

  • Latch 锁:chain(链),轻量级、短时;
  • Lock 锁:排他锁(X)、共享锁(S)。

2. 行级锁:DML(事务锁 TX)

  • 只有排他锁;
  • 不影响读(读走 CR 块)。

3. 表级锁:TM

锁模式 简称 编码 说明
Row Exclusive RX 3 DML 时自动加,允许其他事务修改同表其他行,不允许其他事务加 X 锁
Row Shared RS 2 select ... for update
Share S 4 lock table ... in share mode
Share Row Exclusive SRX 5 lock table ... in share row exclusive mode
Exclusive X 6 lock table ... in exclusive mode
sql 复制代码
lock table <表名> in [row share][row exclusive][share][share row exclusive][exclusive] mode;

4. 锁相关视图

  • v$transaction :XIDUSN(回滚段编号)、XIDSLOT(事务表记录/槽号)、XIDSQN(序列号)、STATUS;
  • v$lock :SID、TYPE(关注 TX/TM)、LMODE(已获得锁模式)、REQUEST(请求锁模式)、BLOCK(>0 表示阻塞了他人);
  • v$enqueue_lock:只显示申请但无法获得锁的 session,按申请时间先后排列;
  • v$locked_object:当前已被锁定的对象信息;
  • v$session :SID 与 SERIAL# 共同唯一标识一个 session。

常用锁诊断 SQL:

sql 复制代码
select sid,type,id1,id2,
  decode(lmode,0,'None',1,'Null',2,'Row share',3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive') lock_mode,
  decode(request,0,'None',1,'Null',2,'Row share',3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive') request_mode,
  block
from v$lock where sid=&sid;

-- 定位阻塞源
select a.sid blocker_sid, a.serial#, a.username as blocker_username, b.type,
  decode(b.lmode,0,'None',1,'Null',2,'Row share',3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive') lock_mode,
  b.ctime as time_held, c.sid as waiter_sid,
  decode(c.request,0,'None',1,'Null',2,'Row share',3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive') request_mode,
  c.ctime time_waited
from v$lock b, v$enqueue_lock c, v$session a
where a.sid = b.sid and b.id1 = c.id1(+) and b.id2 = c.id2(+) and c.type(+) = 'TX' and b.type = 'TX' and b.block = 1
order by time_held, time_waited;

-- 杀会话
alter system kill session '&sid,&serial';

说明 :对于 TM 锁,ID1 表示被锁定对象的对象 ID,ID2 始终为 0;对于 TX 锁,ID1 表示事务使用的回滚段编号及事务表记录编号,ID2 表示该记录编号被重用的次数(wrap)。

锁资源上限参数:

sql 复制代码
select name, value from v$parameter where name in ('transactions','dml_locks');
select resource_name, current_utilization, max_utilization, initial_allocation
from v$resource_limit where resource_name in ('transactions','dml_locks');

5. 死锁

两个 session 互相持有对方正在申请的锁定时,即发生死锁。死锁是典型的"双输" ,Oracle 会自动撤销造成死锁的那个 DML 语句 (其他 DML 不撤销)。死锁总是由应用程序设计不合理引起------应通过统一加锁顺序等方式从应用侧根治。


十、网络原理与配置

Oracle 网络没有负载,相对简单,不容易出问题。

1. 动态注册

PMON 注册监听,或强制注册:

sql 复制代码
alter system register;

2. 静态注册

由于动态注册不稳定,可采用静态注册------在原 listener.ora 上复制几行,改 global_dbname 与 sid_name 即可:

text 复制代码
SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (GLOBAL_DBNAME = jyzhao)
      (ORACLE_HOME = /opt/app/oracle/product/11.2.0/dbhome_1)
      (SID_NAME = jyzhao)
    )
  )

global_dbname 与 service_names 一致;sid_name 与 instance_name 一致。

3. 双网卡双监听

服务器一般为双网卡或多网卡,每个网卡上配置监听可缓解网络压力,实现网络上的负载均衡,但有一定局限性。

4. 客户端 tnsnames.ora 配置

text 复制代码
JYDB =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.159)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = jyzhao)
    )
  )

5. 数据库的各种名字

db_name、db_unique_name、instance_name、service_names、global_names 等需区分清楚,配置监听与连接串时不要混淆。


十一、参数文件与数据库启动/关闭

1. 参数文件

类型 说明
spfile<SID>.ora 动态参数文件(二进制),9i 以后引入并建议使用
init<SID>.ora 静态参数文件(文本)
sql 复制代码
-- nomount 之前即可互相创建
create pfile from spfile;
create spfile from pfile;

2. 启动三阶段

阶段 动作
nomount 根据参数文件配置参数启动实例
mount 根据参数文件中记录的控制文件位置打开控制文件
open 根据控制文件信息打开数据文件、redo 日志文件
sql 复制代码
-- 启动顺序(依次):监听 → 数据库 → isqlplus/EM
$ lsnrctl start
SQL> startup
$ lsnrctl status
$ isqlplusctl start
$ emctl start dbconsole

3. 关闭四种方式

方式 说明
abort 模拟自然断电,再次启动需实例恢复,万不得已才用
immediate 所有未提交事务全部回滚,强制断开用户连接,最常用
transactional 等待事务自动提交或回滚,强制断开用户连接,很少用
normal shutdown 默认参数,很少用
sql 复制代码
-- 关闭顺序(依次):isqlplus/EM → 监听 → 数据库
$ isqlplusctl stop
$ emctl stop dbconsole
$ lsnrctl stop
SQL> shutdown immediate;

4. 管理工具与平台

Oracle Universal Installer、DBCA(Database Configuration Assistant)、DBUA(Database Upgrade Assistant)、Oracle Net Manager、EM(Enterprise Manager)、SQL*Plus / iSQL*Plus、RMAN、Oracle Secure Backup、数据泵 EXPDP/IMPDP、SQL*Loader 等。

EM 一旦建立,Linux 服务器主机名就不要修改;EM 默认端口 1158,出问题可删除重建;查看端口号可查 $ORACLE_HOME/install/portlist.ini。


十二、生产环境部署与运维实践

1. 典型生产库环境(HA + LB)

标准生产库环境处处体现冗余,有效防止单点故障------即 HA(高可用) ;冗余在条件下还可去除,平时同时运行提供服务,一台坏掉另一台继续提供完整服务------即 LB(负载均衡) 。此外还涉及 MPIO 多路径技术(两根线视为一根传输)。

关键经验:

  • 一般生产库常见方案:服务器与光纤交换机选 IBM,存储选 EMC;
  • 服务器硬盘过去多用 SCSI,如今 SAS、FC 较多;EMC 存储通常用 FC 盘;
  • 服务器通过 HA 卡和光纤连接光纤存储交换机,交换机再通过光纤连接存储;
  • 生产环境服务器 CPU 需支持 64 位,Linux 系统与 Oracle 软件都选 64 位;
  • 安装 Oracle 软件遵循 OFA(Optimal Flexible Architecture,灵活体系结构)。

2. 存储与 RAID 选型

存储的特点 :集合所有硬盘、加快读写速度、支持 RAID 技术。存储控制器最为重要也最值钱,通常配备 2 个控制器和 2 个电源。

存储缓存与电池:存储电池的唯一作用是断电时暂时不丢数据;若缓存电池坏了,会自动关闭缓存写;如今存储还提供 flash,长时间不能加电时可把缓存内容写入 flash。

RAID 对比:

级别 冗余 读写性能 说明
RAID0 无 读写速度高 需 2 块以上,建议不超过 6 块
RAID1 有 写无提升、读有提升 镜像
RAID5 有(1/n) 写性能差、读性能高 可坏 1 块,坏后读速度受严重影响
RAID6 有 写性能很差 可坏 2 块,坏 2 块读速度同样受严重影响
RAID10 / RAID01 有 性能较好 推荐使用

RAID0、RAID1、RAID5 现在很少单独使用;RAID6、RAID10、RAID01 中后两者用得最多。

3. Linux 上安装 Oracle 的要点

前期规划:

  • 物理内存小于 4GB 时,swap 分区一般规划为物理内存的 2 倍;
  • 生产库建议给 /tmp 独立文件系统,大小 10G;
  • / 使用剩余全部空间;
  • 软件版本建议选用企业版(标准版连基本的 RAC 和分区表都没有);
  • Oracle 10g 建议装在 RedHat 4 系统;
  • 存储选择:练习环境用文件系统,生产库多用 ASM 和裸设备。

正式安装步骤:

  1. 确保所需开发工具、系统工具已安装(建议配置 yum 补齐 rpm 包);
  2. 配置网络环境(IP 与 hosts,主机名与 IP 对应写入 hosts);
  3. 建立相关用户组、用户;
  4. 修改 Linux 内核参数、设置环境变量($ORACLE_BASE、$ORACLE_HOME、$ORACLE_SID、$LD_LIBRARY_PATH、$NLS_LANG、$NLS_DATE_FORMAT 等);
  5. 用 Xmanager 执行 ./runInstaller 安装;
  6. 仅安装 Oracle 软件,最后按提示执行两个脚本;
  7. dbca 创建数据库;
  8. netca 配置监听。

建库注意:

  • 示例方案(Sample Schema)在生产库中不能选,练习环境可选;
  • 字符集选择要谨慎;
  • 控制文件、数据文件、重做日志文件位置可自定义。

监听识别不了数据库时,强制注册:

sql 复制代码
SQL> alter system register;

4. 字符集设置

字符集是"字符"与"编码"的对照表,安装时需确认两个字符集:

  1. 数据库字符集 :需存储多国语言选 AL32UTF8,只有中英文选 ZHS16GBK;
  2. 国家字符集 :一般选 AL16UTF16。

Unicode 字符集中,UTF8 很老不推荐;AL32UTF8 最新,建议使用。

sql*plus 客户端设置原则:与所在操作系统字符集一致。

  • Windows 一般为 GBK(chcp 结果为 936):set NLS_LANG=american_america.zhs16gbk;
  • Linux 一般为 UTF-8:export NLS_LANG=american_america.utf8。
sql 复制代码
-- 查看服务器字符集
SELECT userenv('language') FROM dual;
SELECT * FROM v$nls_parameters;

风险提示 :字符集设置错误会导致库中存储的就是错误编码,几乎不可逆,务必在安装阶段慎重设置。 Oracle 不建议后期更改数据库字符集;如确需更改,需了解"超集/严格超集"概念再评估。

5. 存储结构布局经验

  • 控制文件、数据文件、日志文件放在存储上;
  • 参数文件在启动时读取、启动后丢失也无妨,一般放服务器上($ORACLE_HOME/dbs);
  • 备份原则:控制文件、参数文件定期备份;数据文件、归档日志文件每次都要备份;
  • 原则上备份文件不能放在存储上,一般放带库(虚拟带库/真实带库,建议真实带库);
  • Oracle 的特点之一是多表空间结构------一个库里有多个表空间,通过划分表空间方便管理。

十三、核心风险事项汇总

领域 风险 规避建议
内存 Shared Pool 过大 + SQL 未共享 → 反而更差 先解决 SQL 共享,再评估大小
内存 SGA 频繁 resize → cursor pin/latch 等待 关注 v$sga_resize_ops,避免自动内存管理抖动
硬解析 大量硬解析 → ORA-4031 绑定变量 + 共享 SQL;慎用 flush shared_pool
Buffer Cache 热块 → cache buffers chains latch 争用 用 vlatchchildren+xlatch_children + xlatchchildren+xbh.TCH 定位热块
日志 频繁日志切换 → checkpoint not complete 日志切换时间不低于 10--20 分钟;日志放高速盘
检查点 fast_start_mttr_target 过短 → I/O 繁忙 合理设置,避免 DBWn 写过频
读一致性 undo 不足 → ORA-01555 按最长查询时间评估 undo 空间
锁 应用设计不当 → 死锁 统一加锁顺序,从应用侧根治
字符集 设置错误 → 编码不可逆损坏 安装阶段慎重确定,不轻易变更
启动/关闭 滥用 shutdown abort → 每次启动需实例恢复 优先用 shutdown immediate
运维操作 flush buffer_cache / flush shared_pool 高危,仅测试或确有需要时使用

小结

Oracle 体系结构的核心可以归纳为三条主线:

  1. 内存与进程:SGA 的 Shared Pool / Buffer Cache 决定 SQL 解析与数据访问效率,PGA 与 Server Process 是调优重点;
  2. 一致性与恢复:Redo Log + 检查点队列 + SCN + Undo 共同保证崩溃可恢复、读一致性可维持;
  3. 并发控制:TX/TM 锁与 latch 保障并发正确性,死锁应回到应用设计层根治。

理解这些机制之间的联动关系(解析 → 内存 → 日志 → 检查点 → 恢复),是定位性能问题与保障数据一致性的基础。


相关推荐
一木 之林1 小时前
LangChain 第8章 记忆系统:短期/长期记忆与 PostgreSQL 持久化
数据库·postgresql·langchain
qq_452396231 小时前
第七篇:《向量数据库选型:从 Chroma 到 Milvus 的落地对比》
数据库·milvus
云絮.1 小时前
mybatis(二)
java·数据库·mybatis
yyuuuzz1 小时前
云服务器搭建个人博客记录:一次访问超时的复盘
运维·服务器·数据库
花间相见1 小时前
【计算基础|MySQL06】MySQL 架构与一条 SQL 的旅程
数据库·后端
oradh1 小时前
Oracle 分析函数使用总结
数据库·oracle
updayday8542 小时前
印染产线电脑进程异常占用资源却要逐台排查 - Ping64 远程进程管理
大数据·网络·数据库·安全·智能路由器
QYRdata2 小时前
年复合增长率8.2%!2026-2032年数据库开发服务赛道增长动能持续释放
数据库·服务发现·数据库开发·恒州博智
坊钰2 小时前
【LangGraph框架入门级】12. 人机交互:interrupt 中断与 Command 恢复
开发语言·数据库·python·人机交互·ai编程·langgraph