1.3.2 数据库局部性 HANG 处理过程
数据库局部性 HANG,通常表现为部分会话 HANG。观察会话是否为 HANG,笔者比
较喜欢查询 V$SESSION_WAIT 视图,然后观察该会话的 P1、P2、P3 值,如果该值在不停
地改变,则说明会话没有 HANG,而可能只是比较慢。
如果要进一步观察会话 HANG 或者慢的原因,则可以对该会话设置 10046 事件和
errorstack 来帮助诊断故障原因。如需要对 9834 号进程做跟踪,其语法如下所示:
connect / as sysdba
SQL>ALTER SESSION SET tracefile_identifier = 'STACK_10046';
SQL>oradebug setospid 9834
SQL>oradebug unlimit
SQL>oradebug event 10046 trace name context forever,level 12
SQL>oradebug dump errorstack 3
SQL>oradebug dump errorstack 3
SQL>oradebug dump errorstack 3
SQL>oradebug tracefile_name
SQL>oradebug event 10046 trace name context off
1.4.1 性能类故障的处理思路
处理数据库性能类故障时,笔者喜欢自上而下的分析方法,即先宏观地了解系统状况,
然后再具体问题具体分析。以下为分析思路:
(1)了解主机的硬件情况、业务系统的拓扑架构,了解业务最近是否发生了变动。这一
步通常只要简单地沟通几分钟就可以完成了解。
(2)登录到主机,查看主机的资源消耗情况(主要使用 top/topas、vmstat、iostat 等常见
的操作系统命令)。观察主机资源的消耗情况时主要查看是否因 CPU 资源耗尽而产生了大量
的运行队列、是否因 I/O 资源耗尽而产生了大量的阻塞队列,以及是否因内存资源耗尽而产
生了大量的系统交换。此外还需观察是否存在消耗比较多的操作系统资源的业务进程,如果
存在,则使用以下命令跟踪这些客户端进程,观察 SQL 的执行计划。
SQL> oradebug setospid xxx;
SQL> oradebug unlimit;
SQL> oradebug event 10046 trace name context forever, level 12;
SQL> oradebug event 10046 trace name context off;
(3)登录到数据库,查看活动状态的会话数,确认是否存在排队效应。排队效应的一个
典型症状是活动的会话数量比平时高很多。
(4)查询 V$SESSION_WAIT 视图,查看是否有特殊的等待事件。该视图是性能问题现
场诊断过程中最常使用的视图。
(5)如果是 Oracle 9i,建议马上采样一份 10 分钟左右的 6 级 statspack 报告,这样就可
以根据 statspack 报告中的 hash_value 值调用脚本 ?/rdbms/admin/sprepsql.sql 生成 SQL 的执
行计划了。如果是 Oracle 10g 以上版本,建议马上手动采样一份 10 分钟左右的 AWR 报告,
同时生成一份该时间段的 ASH 报告。性能故障时的 AWR/ASH 报告中的各类统计数据没有
被时间平均化,所以是处理性能问题时强有力的参考点。
(6)检查其他系统组件是否碰到了性能瓶颈,如中间件、网络等。
1.4.2 怎样快速定位资源持有者
从本质上来讲,Oracle 所有资源都是串行化操作的,即 Oracle 不允许多个进程同时对同
一对象进行修改。为了在串行化上实现并行化,Oracle 推出了 LOCK、LATCH、MUTEX 三
种不同的机制来保护不同的对象,所以快速定位资源持有者是 DBA 处理性能问题时的一个
必备技能。
下面是获取 LOCK 相关的资源持有者信息的 SQL:
select * from gv$lock where block=1;
select * from dba_waiters;
下面是获取 LATCH 相关的持有者信息的 SQL:
select * from v$latchholder;
在获取 MUTEX 相关的持有者信息时,假如当前系统正在发生 cursor: pin S wait on X 争
用,可以用以下 SQL 查出 MUTEX 的持有者信息:
select to_number(substr(to_char(rawtohex(p2raw)),1,8),'XXXXXXXX') sid
from v$session
where event = 'cursor: pin S wait on X';
在高并发的环境中,争用往往发生在 Library Cache Handle(以下简称 Handle)和
Library Cache Object(以下简称 LCO)中。Handle 上的 LATCH 争用主要表现为 Library
Cache Lock 等待事件,可以用以下 SQL 查出 Handle 上的持有者信息:
select b.sid,a.user_name,a.kglnaobj
from x$kgllk a , v$session b
where a.kgllkhdl in
(select p1raw from v$session_wait
where wait_time=0 and event = 'library cache lock')
and a.kgllkmod <> 0
and b.saddr=a.kgllkuse;
LCO 上的争用主要表现为 Library Cache Pin 等待事件,可以用以下 SQL 查出 Handle 上
的持有者信息:
select sid from x$kglpn , v$session
where KGLPNHDL in
(select p1raw from v$session_wait
where wait_time=0 and event like 'library cache pin%')
and KGLPNMOD <> 0
and v$session.saddr=x$kglpn.kglpnuse;
下面是用于获取 Row Cache 相关的持有者信息的 SQL:
select * from v$rowcache_parent where lock_mode<>0;
提示 从 Oracle 10g 开始,V$SESSION 视图增加了 BLOCKING_SESSION 字段,很多资源
阻塞者会话都可以通过该字段查到。
1.5 数据误操作类故障的处理思路
数据误操作故障指的是表误删除、数据误删除等故障。笔者处理此类故障的思路如下:
(1)如果数据库有备份,则评估一下恢复时间和数据丢失率,如果两者都可以接受则考
虑备份来恢复误操作对象。
(2)如果表被误删除(DROP),且 Oracle 版本为 10g 以上,则首先查看回收站中是否
存在误删除表。如果回收站中也不存在,则使用 DUL 等挖掘工具恢复数据。
(3)如果数据被误删除(DELETE),则使用表闪回版本查询特性查看是否能挽救误删除
的数据。
(4)表闪回版本查询特性依赖于保存在 UNDO 中的前映像数据,如果表闪回查询失效,
则可以尝试使用 logmnr 工具挖掘归档日志,以恢复误删除的数据。
1.6 数据库坏块类故障
正常的数据块有其特有的固定格式,如果某数据块内部出现了混乱而导致 Oracle 无法读
取,则可称其为坏块。数据库坏块的影响范围可大可小,严重时会导致数据库无法打开。当
数据库出现坏块时,一般出现 ORA-01578 错误、ORA-10632 错误或者 ORA-00600 错误。数
据库产生坏块的原因主要有以下几种:
硬件问题。如内存混乱,CPU 计算错误会导致内存中的数据块内容混乱,进而导致保
存到磁盘后数据块损坏。
操作系统 bug。Oracle 的 I/O 写最终会由操作系统内核调用(system call)完成,当内
核调用出现问题时,就可能产生坏块。
非 Oracle 进程异常修改 Oracle SGA 内存区域。如调用 Linux 或者 UNIX 操作系统的
函数 shmat 非法 attach 到 SGA 中。
主机或者存储异常掉电。当掉电后存储的 CACHE 机制无法发挥正常作用时,极容易
产生坏块。
Oracle bug。某些版本下的 Oracle bug 可能也会导致坏块产生,如 bug 4493447。
1.6.1 数据库对象坏块的处理思路
业务对象上的坏块通常不会导致数据库宕机。假设数据库没有备份,数据库对象坏块的
处理思路如下:
(1)可以使用 dbv、RMAN、EXP/EXPDP 或者 VALIDATE 命令校验数据库的坏块数量。
建议使用 dbv 校验,因为 RMAN、EXP/EXPDP 或者 VALIDATE 校验坏块过程中可能会使数
据库实例宕掉。此外 EXP/EXPDP 校验坏块时不会校验索引的坏块。
(2)如果索引出现坏块,则考虑删除并重建索引。索引有坏块时,一般不建议使用
rebuild 选项重建索引。
(3)如果表出现坏块,则设置 10231 事件或者使用 dbms_repair 包,从而在全表扫描时
可以跳过坏块,也可以使用 ROWID RANGE SCAN 跳过坏块的数据。其使用方法可以参考
MOS 文章 422547.1。
(4)使用 bbed 工具尝试修复坏块。需要注意的是,使用 bbed 修复坏块过程较为复杂且
风险较大。
1.6.2 SYSTEM/UNDO 表空间损坏的处理思路
SYSTEM/UNDO 表空间损坏是比较棘手的故障,通常会导致数据库异常宕机进而无法打
12
第1章 数据库故障的诊断方法与分析思路
开数据库。数据库的打开故障处理起来相对比较麻烦,读者可以参考本书第 5 章进一步了解
该类故障的处理过程。如果数据库没有备份,通常需要设置官方不推荐的隐含参数或者使用
bbed 工具修复损坏的数据块来强制打开数据库,所以此类故障处理起来存在着风险性和不可
预知性。当碰到此类故障时,笔者的处理思路如下(假设数据库没有备份):
(1)检查数据库的警告日志,初步确定数据库打不开的原因。如果是 RAC,则检查所有
节点的警告日志。
(2)物理备份整个数据库。如果备份到本地磁盘,其备份速度最终取决于数据库大小和
磁盘的 I/O 能力。如果通过网络备份到异地,那么其备份速度还取决于网络带宽。
(3)用 dbv 工具校验 SYSTEM/UNDO 表空间,确定数据块的损坏范围和严重程度。
(4)关闭监听。其目的是数据库成功打开之后,外部应用不会立刻连接至数据库。
(5)进行故障处理。具体的处理思路请参考第 5 章。
(6)如果是 UNDO 表空间有坏块,可以设置隐含参数 _offline_rollback_segments 屏蔽坏块
所在的回滚段来打开数据库。如果熟悉数据块格式,则可以用 bbed 工具修复损坏的数据块。
提示 如果空间不够或者整个数据库备份时间过长,则依然需要备份 SYSTEM、UNDO 和
SYSAUX 表空间下的数据文件、控制文件、所有在线日志文件。非常规手段修复数据
库所带来的副作用很难被 DBA 全部预见到,为防止事态进一步恶化,在处理问题之
前必须全部备份上述文件。对于不可逆转的修复,DBA 一定要小心,做好备份工作!
1.6.3 数据库在线日志文件损坏的处理思路
千万不要在数据库运行时,突然关闭主机或者存储,由于在线日志的写操作非常频繁,所
以主机或者存储异常宕机之后,在线日志往往会损坏。在线日志损坏也就意味着丢失数据,数据
库就无法正常打开,所以需要引起读者足够的重视。当碰到此类故障时,笔者的处理思路如下:
(1)如果损坏的是 INACTIVE 状态的在线日志,则启动数据库至 MOUNT 状态,然后
使用 CLEAR LOGFILE 命令重新生成该日志文件,这样就可以正常打开数据库。在 CLEAR
LOGFILE 过程中,服务器进程会根据记录在控制文件的日志文件的大小重新格式化日志块,
所以刚生成的日志文件块除了块头信息,没有其他任何内容。
(2)如果损坏的是 ACTIVE 或者 CURRENT 状态的在线日志,则设置隐含参数
_allow_resetlogs_corruption 为 TRUE,然后进行不完全恢复,并使用 RESETLOGS 模式强
制打开数据库。
(3)在强制打开数据库的过程中,如果出现 ORA-00600 [2662] 错误,则可以使用 10015
事件或者隐含参数 _minimum_giga_scn 递增全库 SCN 值。
1.6.4 控制文件损坏的处理思路
虽然控制文件很重要,但它损坏了至少不会丢失业务数据,而且控制文件损坏的处理流
程也相对比较简单。当碰到控制文件损坏且没有备份时,笔者的处理思路如下:
(1)数据库打开过程中,观察数据库是否能到 MOUNT 阶段。如果能,则将控制文件备
份到跟踪文件中,然后使用 NORESETLOGS 选项重建控制文件。
(2)如果不能 MOUNT 数据库,则使用操作系统命令 strings 命令提取控制文件的数据
文件、在线日志文件位置和路径,然后按照重建控制文件的格式,以 NORESETLOGS 选项
重建控制文件。
(3)如果操作系统命令 strings 命令无法读取控制文件,那么只能到文件系统中寻找当前
数据库的数据文件和在线日志文件,然后按照重建控制文件的格式,以 NORESETLOGS 选
项重建控制文件。