怎样用调试工具Dump Oracle系统状态

Posted by 老熊 on 11月 21st, 2008

如果Oracle数据库hang住了,对Oracle做system dump,或做hang analyze,是研究和解决问题的有效办法,至少在提交SR时能够有更多的有用信息。如果能够连接数据库,并能够进行操作,那么用oradebug是简单快捷的办法。

但有的时候,数据库由于hang住,sqlplus不能连接时(在10g可以尝试用sqlplus -prelim连接数据库),可以使用操作系统上的调试工具来dump oracle系统状态。在记一次Oracle数据库无响应(hang住)故障的处理一文中,就曾使用dbx做systemstate dump,并发现问题所在,并最终解决了问题。下面是当时用dbx做dump的过程:

# dbx -a 446910
Waiting to attach to process 446910 …
Successfully attached to oracle.
Type ‘help’ for help.
reading symbolic information …
stopped in iosl.select at 0×9000000000c94d8 ($t2)
0×9000000000c94d8 (select+0xfffffffffff06318) e8410028 ld r2,0×28(r1)
(dbx) print ksudss(10)

Segmentation fault in slrac at 0×100083aa0 ($t2)
0×100083aa0 (slrac+0xe4) 88030000 lbz r0,0×0(r3)
(dbx) detach

从上面可以看到,使用dbx做dump的过程为:

  • 找到有异常的进程号,比如CPU非常高,HANG住的进程等。如果做系统范围的systemstate dump,可以是其他的进程。
  • dbx -a < 进程号>
  • print ksudss(10) --这里是直接调用ORACLE程序中的ksudss函数,dump level为10,就等同于在sqlplus 中用oradebug dump systemstate 10
  • detach
  • quit

在LINUX下可以使用gdb,下面是一个例子:

[oracle@xty ~]$ ps -ef | grep LOCAL
oracle 3765 3764 1 05:55 ? 00:00:00 oraclexty (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
oracle 3767 3668 0 05:55 pts/2 00:00:00 grep LOCAL
[oracle@xty ~]$ gdb $ORACLE_HOME/bin/oracle 3765
GNU gdb Red Hat Linux (6.1post-1.20040607.62rh)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB. Type “show warranty” for details.
This GDB was configured as “i386-redhat-linux-gnu”…(no debugging symbols found)…Using host libthread_db library “/lib/tls/libthread_db.so.1″.

Attaching to program: /u01/app/oracle/product/10.1.0/db_1/bin/oracle, process 3765
Reading symbols from /u01/app/oracle/product/10.1.0/db_1/lib/libskgxp10.so…(no debugging symbols found)…done.
Loaded symbols for /u01/app/oracle/product/10.1.0/db_1/lib/libskgxp10.so
Reading symbols from /u01/app/oracle/product/10.1.0/db_1/lib/libhasgen10.so…done.
Loaded symbols for /u01/app/oracle/product/10.1.0/db_1/lib/libhasgen10.so
Reading symbols from /u01/app/oracle/product/10.1.0/db_1/lib/libskgxn2.so…done.
Loaded symbols for /u01/app/oracle/product/10.1.0/db_1/lib/libskgxn2.so
Reading symbols from /u01/app/oracle/product/10.1.0/db_1/lib/libocr10.so…done.
Loaded symbols for /u01/app/oracle/product/10.1.0/db_1/lib/libocr10.so
Reading symbols from /u01/app/oracle/product/10.1.0/db_1/lib/libocrb10.so…done.
Loaded symbols for /u01/app/oracle/product/10.1.0/db_1/lib/libocrb10.so
Reading symbols from /u01/app/oracle/product/10.1.0/db_1/lib/libocrutl10.so…done.
Loaded symbols for /u01/app/oracle/product/10.1.0/db_1/lib/libocrutl10.so
Reading symbols from /u01/app/oracle/product/10.1.0/db_1/lib/libjox10.so…done.
Loaded symbols for /u01/app/oracle/product/10.1.0/db_1/lib/libjox10.so
Reading symbols from /u01/app/oracle/product/10.1.0/db_1/lib/libclsra10.so…done.
Loaded symbols for /u01/app/oracle/product/10.1.0/db_1/lib/libclsra10.so
Reading symbols from /u01/app/oracle/product/10.1.0/db_1/lib/libdbcfg10.so…done.
Loaded symbols for /u01/app/oracle/product/10.1.0/db_1/lib/libdbcfg10.so
Reading symbols from /u01/app/oracle/product/10.1.0/db_1/lib/libnnz10.so…done.
Loaded symbols for /u01/app/oracle/product/10.1.0/db_1/lib/libnnz10.so
Reading symbols from /usr/lib/libaio.so.1…done.
Loaded symbols for /usr/lib/libaio.so.1
Reading symbols from /lib/libdl.so.2…done.
Loaded symbols for /lib/libdl.so.2
Reading symbols from /lib/tls/libm.so.6…done.
Loaded symbols for /lib/tls/libm.so.6
Reading symbols from /lib/tls/libpthread.so.0…done.
[Thread debugging using libthread_db enabled]
[New Thread -1219938624 (LWP 3765)]
Loaded symbols for /lib/tls/libpthread.so.0
Reading symbols from /lib/libnsl.so.1…done.
Loaded symbols for /lib/libnsl.so.1
Reading symbols from /lib/tls/libc.so.6…done.
Loaded symbols for /lib/tls/libc.so.6
Reading symbols from /lib/ld-linux.so.2…done.
Loaded symbols for /lib/ld-linux.so.2
Reading symbols from /lib/libnss_files.so.2…done.
Loaded symbols for /lib/libnss_files.so.2
0×006967a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
(gdb) print ksudss(10)
[Switching to Thread -1219938624 (LWP 3765)]
$1 = 213658428
(gdb) detach
Detaching from program: /u01/app/oracle/product/10.1.0/db_1/bin/oracle, process 3765
(gdb) quit

然后我们可以找到有dump结果的trace文件:
Read the rest of this entry »

inside sqlplus prelim

Posted by 老熊 on 11月 15th, 2008

我们知道,在Oracle 10g中,如果数据库实例hang住了,应用及sqlplus都不能连接时,可以用sqlplus -prelim连接数据库。那么sqlplus连接时,加上-prelim这个参数有什么特别的地方呢?下面,让我们来研究一下:

测试环境:Linux AS4上的Oracle 10.2.0.1,客户端(sqlplus)版本为Windows 2003下的10.2.0.1。

首先在数据库上启用10046事件:

SQL> alter system set events ‘10046 trace name context forever’;

System altered.

先用普通的方式连接:

D:\>sqlplus /nolog

SQL*Plus: Release 10.2.0.1.0 - Production on 星期六 11月 15 15:36:02 2008

Copyright (c) 1982, 2005, Oracle. All rights reserved.

SQL> conn sys/manage@xty as sysdba
已连接。
SQL> exit
从 Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options 断开

再看看加prelim参数时的情况:

D:\>sqlplus -prelim /nolog

SQL*Plus: Release 10.2.0.1.0 - Production on 星期六 11月 15 15:36:34 2008

Copyright (c) 1982, 2005, Oracle. All rights reserved.

SQL> conn sys/manage@xty as sysdba
初级连接已建立
SQL> exit
从 ORACLE 断开

从上面的信息可以看到,在使用prelim连接时,提示为“初级连接已建立”,退出sqlplus没有显示banner。
也可以通过下面的方式来用prelim方式连接数据库:

[oracle@xty ~]$ sqlplus /nolog

SQL*Plus: Release 10.2.0.3.0 - Production on Tue Dec 2 07:04:28 2008

Copyright (c) 1982, 2006, Oracle. All Rights Reserved.

SQL> set _prelim on
SQL> connect / as sysdba
Prelim connection established

再看看数据库的10046 trace:

从生成的trace文件中,可以发现在正常连接时,连接上数据库后,sqlplus自动执行了下面的SQL:

ALTER SESSION SET NLS_LANGUAGE= ‘SIMPLIFIED CHINESE’ NLS_TERRITORY= ‘CHINA’ NLS_CURRENCY= ‘¥’ NLS_ISO_CURRENCY= ‘CHINA’ NLS_NUMERIC_CHARACTERS= ‘.,’ NLS_CALENDAR= ‘GREGORIAN’ NLS_DATE_FORMAT= ‘DD-MON-RR’ NLS_DATE_LANGUAGE= ‘SIMPLIFIED CHINESE’ NLS_SORT= ‘BINARY’ TIME_ZONE= ‘+08:00′ NLS_COMP= ‘BINARY’ NLS_DUAL_CURRENCY= ‘¥’ NLS_TIME_FORMAT= ‘HH.MI.SSXFF AM’ NLS_TIMESTAMP_FORMAT= ‘DD-MON-RR HH.MI.SSXFF AM’ NLS_TIME_TZ_FORMAT= ‘HH.MI.SSXFF AM TZR’ NLS_TIMESTAMP_TZ_FORMAT= ‘DD-MON-RR HH.MI.SSXFF AM TZR’

select value$ from props$ where name = ‘GLOBAL_DB_NAME’

select SYS_CONTEXT(’USERENV’, ‘SERVER_HOST’), SYS_CONTEXT(’USERENV’, ‘DB_UNIQUE_NAME’), SYS_CONTEXT(’USERENV’, ‘INSTANCE_NAME’), SYS_CONTEXT(’USERENV’, ‘SERVICE_NAME’), INSTANCE_NUMBER, STARTUP_TIME, SYS_CONTEXT(’USERENV’, ‘DB_DOMAIN’) from v$instance where INSTANCE_NAME=SYS_CONTEXT(’USERENV’, ‘INSTANCE_NAME’)

select decode(failover_method, NULL, 0 , ‘BASIC’, 1, ‘PRECONNECT’, 2 , ‘PREPARSE’, 4 , 0), decode(failover_type, NULL, 1 , ‘NONE’, 1 , ‘SESSION’, 2, ‘SELECT’, 4, 1), failover_retries, failover_delay, flags from service$ where name = :1

而sqlplus使用prelim连接上数据库后,没有生成10046 trace文件,看起来没有执行SQL,也就是没有执行任何初始化动作和查询必要的信息。也许这也就是称之为“初级连接”的来历吧。

由于使用prelim方式连接,没有执行sql语句的,所以在数据库的某些hang住的情况下,能够连接上数据库。比如由于library cache latch 被长时间持有不能释放,不能解析SQL语句引起的hang。有的人会说,我的应用刚连上去还没做任何操作就hang住了。这只是表面现象,连接上数据库后,一般都会做一些初始化的操作,如设定环境之类的。

sqlplus -prelim能够在数据库hang住的情况下连接数据库,但只能说是连接,并不代表能够做很多操作。比如执行SQL查询。这种情况下,可能最有用的就是使用oradebug。

本文只是简单地“inside”,其实并不很深入,Oracle还会有其他的跟prelim有关的东西,是我们还没发现的。有兴趣的朋友,可以进一步研究。比如通过抓取tns包进行分析等等。

儿子两岁了

Posted by 老熊 on 11月 13th, 2008

明天,儿子就两岁了。

儿子很很喜欢飞机,天上有飞机飞过,总要抬头看看,直到看不见为止。经常缠着我们在网上找飞机图片给他看。现在至少是能分辨客机和直升机了,不过他更喜欢直升机。

儿子很喜欢建筑相关的东西,喜欢看修房子,喜欢混凝土车,喜欢挖掘车。不知道他为什么会有这种奇特的喜好?似乎小孩对什么东西都是很新奇的。

儿子常常说的话是,“爸爸是老帅哥,超超是小帅哥”

儿子常常让他妈妈做的事情是,“画鱼摆摆吹泡泡”

儿子最喜欢的电视节目是每晚19点CCTV3的“动物世界”

在儿子两岁之即,特记之。

db_block_checking和db_block_checksum III

Posted by 老熊 on 11月 6th, 2008

前面两篇文章简要介绍了db_block_checking和db_block_checksum参数,并提到这两个参数对性能的影响。下面做个测试:

首先建一个测试表,并设置db_block_checking和db_block_checksum为false:

SQL> create table t2 (a int) tablespace test;

表已创建。
SQL> alter system set db_block_checking=false;

系统已更改。

SQL> alter system set db_block_checksum=false;

向测试表T2中四次分别插入100,000行数据:

SQL> begin
2 for i in 1..100000 loop
3 insert into t2 values(i);
4 end loop;
5 end;
6 /

PL/SQL 过程已成功完成。

已用时间: 00: 00: 06.02
SQL> commit;

提交完成。

已用时间: 00: 00: 00.00
SQL> alter system checkpoint;

系统已更改。

已用时间: 00: 00: 01.02
SQL> begin
2 for i in 1..100000 loop
3 insert into t2 values(i);
4 end loop;
5 end;
6 /

PL/SQL 过程已成功完成。

已用时间: 00: 00: 05.04
SQL> commit;

提交完成。

已用时间: 00: 00: 00.00
SQL> alter system checkpoint;

系统已更改。

已用时间: 00: 00: 01.02
SQL> begin
2 for i in 1..100000 loop
3 insert into t2 values(i);
4 end loop;
5 end;
6 /

PL/SQL 过程已成功完成。

Read the rest of this entry »

db_block_checking和db_block_checksum II

Posted by 老熊 on 11月 3rd, 2008

在之前的一篇文章db_block_checking和db_block_checksum,简要地描述了db_block_checking和db_block_checksum这两个参数的作用以及性能方面的影响。在10gR1及这前的版本中,这两个参数可以设置为false和true。而在10gR2版本中,这两个参数发生了一点变化。

先来看看db_block_checking,这个参数现在有四个可能的设置:

  • OFF - 与原来的FALSE一样,对非SYSTEM表空间的块关闭检查,这个值在设置时仍然可以用false。
  • LOW - 只检查块头。这个检查发生在当块的内容在内存中发生改变时,比如UPDATE、INSERT、DELETE等,以及将块从磁盘读入、RAC结点间块的传输。
  • MEDIUM - 比LOW更高一级,还包括了非IOT的表的块内部检查(即不仅仅是块头)。
  • FULL - 与原来的TRUE一样,与MEDIUM相比,还包括了索引块的检查。

再看看db_block_checksum这个参数有什么变化:

  • OFF - 与原来的FALSE一样,只会给SYSTEM表空间的块计算checksum值。
  • TYPICAL - 与原来的TRUE一样,Oracle在向磁盘写入块时计算checksum值,下次读入时进行校验。
  • FULL - 这是新增的值,Oracle不关在写入块时计算checksum值,而且在更改块(比如执行UPDATE语句等)之前对checksum值进行校验,同时在更改块之后对checksum值进行重新计算。另外Oracle也会在写入日志块时,计算块的checksum。这个设置大大增加了系统负荷,大约带来了4-5%的负荷。而TYPICAL值会带来1-2%的负荷。

Oracle数据库的global_name

Posted by 老熊 on 10月 23rd, 2008

Oracle数据库的global_name,在Database Link与GLOBAL_NAMES参数一文中提到了,设置global_names初始化参数为true后,本地的数据库链接名称必须与远程数据库的global_name相同,才能正常使用数据库链接。那么怎么查询数据库的global_name呢?

SQL> col global_name for a30
SQL> select * from global_name;

GLOBAL_NAME
------------------------------
DMDB

那么怎么样修改global_name?

ALTER DATABASE
RENAME GLOBAL_NAME TO NEW_NAME;

注意不要直接用update global_name set global_name=”将global_name设置为空,否则数据库不能启动,会报ORA-00600[18061] 或 ORA-00600[18062]这样的错误。 只有用备份进行恢复后才能打开。(参见metalink note 743676.1)。

那么global_name到底是个什么对象呢?

SQL> select owner,object_name,object_type from dba_objects where object_name=’GLOBAL_NAME’;

OWNER OBJECT_NAME OBJECT_TYPE
---------- -------------------- --------------------
SYS GLOBAL_NAME VIEW
PUBLIC GLOBAL_NAME SYNONYM

SQL> select text from dba_views where view_name=’GLOBAL_NAME’;

TEXT
----------------------------------------------------------------
select value$ from sys.props$ where name = ‘GLOBAL_DB_NAME’

Read the rest of this entry »

Oracle权限之references权限

Posted by 老熊 on 10月 23rd, 2008

如果一个表的外键引用的是另一个用户的表,需要特别的权限吗?答案就是refrences权限。虽然一个schema(用户)下表的外键引用的是其他schema(用户)的表,是一种不太好的设计。但现实中仍然会有这种情况。下面来看看reference的作用:

测试环境:
Oracle 10.2.0.1
Redhat Linux AS4
数据库里用于测试的两个用户test1和test2,只有connect角色权限和表空间使用权限。

SQL> connect / as sysdba
Connected.
SQL> create table test1.t1 as select * from dba_objects where rownum< =1000;

Table created.

SQL> create table test2.t2 as select * from dba_objects where rownum< =1000;

Table created.

SQL> alter table test1.t1 add constraint pk_t1 primary key(object_id);

Table altered.

现在,我们用用户test2连接到数据库,在表test2.t2的object_id字段上增加一个外键,外键引用test1.t1表的object_id字段:

SQL> connect test2/test
Connected.
SQL> alter table t2 add constraint fk_t2 foreign key (object_id) references test1.t1(object_id);
alter table t2 add constraint fk_t2 foreign key (object_id) references test1.t1(object_id)
*
ERROR at line 1:
ORA-00942: table or view does not exist

我们将test1.t1表的查询权限赋给test2:

SQL> grant select on test1.t1 to test2;

Grant succeeded.

再次增加外键:

SQL> alter table t2 add constraint fk_t2 foreign key (object_id) references test1.t1(object_id);
alter table t2 add constraint fk_t2 foreign key (object_id) references test1.t1(object_id)
*
ERROR at line 1:
ORA-01031: insufficient privileges

可以看到报权限不足。我们再看看如果将DBA权限给test2会怎么样:
Read the rest of this entry »

10月22日

Posted by 老熊 on 10月 22nd, 2008

今天是2008年10月22日,农历戊子年九月二十四。

今天是我的法律意义上的生日。虽然很早以前在办户籍时把我的出生日期给搞错了,提前了一个月。但到如今只有将错就错了。

今天是我儿子农历两岁生日,看着儿子一天天长大,那种快乐实不足以用言语来表达。祝福他永远快乐地成长下去。

三年前的今天,我正在当新郎官。

今天是个有意义的日子。

记一次并行恢复问题导致Oracle数据库Crash故障的处理

Posted by 老熊 on 10月 16th, 2008

环境:HP-UX 11.31
Oracle 9.2.0.8

数据库异常崩溃,询问维护人员之前有大量数据操作。查看alert日志:

Thu Oct 9 02:20:18 2008
Errors in file /oracle/OraHome1/rdbms/log/acct_ora_11361.trc:
ORA-00600: internal error code, arguments: [ktprhtnew6], [], [], [], [], [], [], []
Thu Oct 9 02:20:19 2008
Fatal internal error happened while SMON was doing active transaction recovery.
Thu Oct 9 02:20:19 2008
Errors in file /oracle/OraHome1/rdbms/log/acct_ora_11361.trc:
ORA-00600: internal error code, arguments: [ktprhtnew6], [], [], [], [], [], [], []
SMON: terminating instance due to error 600
Instance terminated by SMON, pid = 11361

检查trace文件,没有发现有用的信息。

重启数据库,数据库能打开,但不到一分钟实例就crash。在alert日志中的错误信息均如上所示。
在网上及在metalink中以ktprhtnew6为关键字搜索,没有找到相似的BUG和案例。同时当时手边是用的163拨号上网,速度非常慢,只有通过分析来解决问题。

仔细分析alert日志可以发现是在做事务恢复时SMON出错,导致实际中止:

Fatal internal error happened while SMON was doing active transaction recovery.

我们知道ORA-600错误后面参数,如果像ktprhtnew6这样的均表示出错的函数。这里可以看出是在做并行恢复:

[K]enerl [T]ransaction [P]arallel [R]ecovery

设置fast_start_parallel_rollback参数为false,关闭数据库的并行恢复功能,重启数据库,数据库正常,故障消失。
看起来这应该又是一个BUG。

怎样关闭Oracle监听日志

Posted by 老熊 on 10月 15th, 2008

Oracle的监听(Listener)在缺省情况下,会在文件中记录日志,记录数据库实例注册操作、客户端的连接等。缺省(没有设置log_file参数时)的文件是$ORACLE_HOME/network/log/listener.log。对于一些使用短连接的,频繁的连接数据库的应用,listener.log增长很快。有的可以在比较短的时间内(十几天)就可以超过2GB。对于一些平台的某些版本的Oracle,在监听日志增大到2GB以后会导致监听不能正常工作(我没遇到过,不过感兴趣的朋友可以在网上搜索一下,有这样的案例)。

对于这种listener.log增长非常迅速的系统,可以关闭监听日志,不让监听写日志到文件。也可以写个job定期清理。本文主要描述怎么样关闭监听日志:

可以在监听命令行接口中使用命令:
D:\>lsnrctl

LSNRCTL for 32-bit Windows: Version 9.2.0.1.0 - Production on 15-10月-2008 20:52:11

Copyright (c) 1991, 2002, Oracle Corporation. All rights reserved.

欢迎来到LSNRCTL,请键入”help”以获得信息。

LSNRCTL> set log_status off
正在连接到 (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=dreamf)(PORT=1521)))
LISTENER 参数 \log_status\ 被设为 OFF
命令执行成功
LSNRCTL> save_config
正在连接到 (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=dreamf)(PORT=1521)))
未保存对LISTENER所作的更改
命令执行成功
LSNRCTL>

我们可以在listener.ora文件中可以看到增加了下面的内容:

#----ADDED BY TNSLSNR 15-10月-2008 10:05:43---
LOGGING_LISTENER = OFF
#---------------------------------------------

所以我们也可以在listener.ora文件增加上面的内容来关闭监听日志。但是只有在监听重启后才会生效,而通过lsnrctl 这个命令接口设置,可以立即生效,Windows平台上的文件会立即关闭。因此可以利用这个特性,用来删除WINDOWS平台上的监听日志文件,因为不这样,在监听运行时监听日志是不能删除的。


Copyright © 2007 老熊的三分地-Oracle、UNIX、数据恢复. All rights reserved.