一、体系结构总览:一句话理解 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 的两大成因:
- 系统产生大量硬解析;
- 大量硬解析产生大量碎片,此时又来一个需要大块空间的 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 的处理与规避
ALTER SYSTEM FLUSH SHARED_POOL;(慎用------之后会产生大量硬解析,能解决 4031 但治标不治本);- 共享 SQL(统一风格 + 绑定变量);
dbms_shared_pool.keep('大的对象名');将大对象常驻;- 保留区:在 Shared Pool 中单独划出一块空间只放大对象,设置足够大可减少很多 4031。
sql
-- 查询保留区请求未命中数,结果应为 0;若大于 0,需调整 shared_pool_reserved_size
SELECT request_misses FROM v$shared_pool_reserved;
- 增加 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 的意义
- 减少 I/O(物理 I/O、逻辑 I/O);
- 构造 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/3 重做日志缓冲区未被写入磁盘;
- 有大于 1MB 的重做日志缓冲区未被写入磁盘;
- 每隔 3 秒钟;
- 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 构成:
- private SQL area;
- Session Memory(保存会话变量、登录信息等);
- 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 的三个作用:
- 事务回滚(rollback);
- 读一致性,构造 CR 块;
- 实例恢复,回滚未提交事务。
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"
成因:
- SQL 执行时间太长;
- undo 表空间压力太大;
- 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 和裸设备。
正式安装步骤:
- 确保所需开发工具、系统工具已安装(建议配置 yum 补齐 rpm 包);
- 配置网络环境(IP 与 hosts,主机名与 IP 对应写入 hosts);
- 建立相关用户组、用户;
- 修改 Linux 内核参数、设置环境变量(
$ORACLE_BASE、$ORACLE_HOME、$ORACLE_SID、$LD_LIBRARY_PATH、$NLS_LANG、$NLS_DATE_FORMAT等); - 用 Xmanager 执行
./runInstaller安装; - 仅安装 Oracle 软件,最后按提示执行两个脚本;
dbca创建数据库;netca配置监听。
建库注意:
- 示例方案(Sample Schema)在生产库中不能选,练习环境可选;
- 字符集选择要谨慎;
- 控制文件、数据文件、重做日志文件位置可自定义。
监听识别不了数据库时,强制注册:
sql
SQL> alter system register;
4. 字符集设置
字符集是"字符"与"编码"的对照表,安装时需确认两个字符集:
- 数据库字符集 :需存储多国语言选
AL32UTF8,只有中英文选ZHS16GBK; - 国家字符集 :一般选
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 体系结构的核心可以归纳为三条主线:
- 内存与进程:SGA 的 Shared Pool / Buffer Cache 决定 SQL 解析与数据访问效率,PGA 与 Server Process 是调优重点;
- 一致性与恢复:Redo Log + 检查点队列 + SCN + Undo 共同保证崩溃可恢复、读一致性可维持;
- 并发控制:TX/TM 锁与 latch 保障并发正确性,死锁应回到应用设计层根治。
理解这些机制之间的联动关系(解析 → 内存 → 日志 → 检查点 → 恢复),是定位性能问题与保障数据一致性的基础。