glogin.sql配置不当引起sqlplus hang的假象分析
Tags: Oracle
不久前遇到的一个问题,"故障"现象如下:
A主机上跑了两个单实例的数据库testa和testb,对testa实例进行例行重启时先shutdown immediate,然后再通过sqlplus '/as sysdba'连进去尝试重启时发现,sqlplus Hang住不动了
sqlplus '/as sysdba'
SQL*Plus: Release 11.2.0.3.0 Production on Sat Feb 28 16:53:32 2015
Copyright (c) 1982, 2011, Oracle. All rights reserved.
Connected to an idle instance. <====停在这里不动了
此时使用sqlplus '/as sysdba'连接另一个实例testb是OK的,由于是测试环境于是将testb实例也shutdown immediate,准备重启主机,重启之前对于已经关闭的testb实例用sqlplus '/as sysdba'也无法连上去,现象同testa。主机重启势在必行了,但主机重启后现象依旧,两个实例都无法连接。使用"truss -dfaie -o /tmp/sched_trace.out.02271 sqlplus '/as sysdba'"命令对sqlplus '/as sysdba'的过程进行了跟踪,直奔sched_trace.out.02271文件结尾处发现了以下内容
2949918: 15664107: 0.8794: kopen("/oracle/app/oracle/product/11.2.0/db_1/rdbms/mesg/oraus.msb", O_RDONLY) = 8
2425346: 14746339: 0.8891: kopen("/oracle/app/oracle/product/11.2.0/db_1/rdbms/mesg/oraus.msb", O_RDONLY) = 6
2949918: 15664107: 0.8915: kopen("/oracle/app/oracle/product/11.2.0/db_1/rdbms/mesg/oraus.msb", O_RDONLY) = 8
2949918: 15664107: 0.8960: statx("/oracle/app/oracle/product/11.2.0/db_1/sqlplus/admin/glogin.sql", 0x0FFFFFFFFFFFDA40, 176, 010) = 0
2949918: 15664107: 0.8963: statfs("/oracle/app/oracle/product/11.2.0/db_1/sqlplus/admin/glogin.sql", 0x0FFFFFFFFFFFD620) = 0
2949918: 15664107: 0.8979: kopen("/oracle/app/oracle/product/11.2.0/db_1/sqlplus/admin/glogin.sql", O_RDONLY|O_LARGEFILE) = 8
2425346: 14746339: 0.9041: kopen("/oracle/app/oracle/product/11.2.0/db_1/rdbms/mesg/oraus.msb", O_RDONLY) = 6
2949918: 15664107: 0.9065: kopen("/oracle/app/oracle/product/11.2.0/db_1/rdbms/mesg/oraus.msb", O_RDONLY) = 11
2949918: 15664107: 0.9086: kopen("/oracle/app/oracle/product/11.2.0/db_1/rdbms/mesg/oraus.msb", O_RDONLY) = 11
2425346: 14746339: 906.0540: kopen("/oracle/app/oracle/product/11.2.0/db_1/rdbms/mesg/diaus.msb", O_RDONLY) = 5
2425346: 14746339: 906.0565: statx("/oracle/app/oracle", 0x0FFFFFFFFFFFDAF0, 176, 0) = 0
从后往前查,diaus.msb=>oraus.msb=>glogin.sql,前面两个文件的大小和权限与其他服务器上的同名文件相比较均一致,检查glogin.sql的时候发现该文件最近被修改过,其内容如下
set termout off
col newprom new_value newprom1
select user||'@'||sys_context('userenv','instance_name')||'-'||'SQL> ' newprom from dual;
set sqlprompt '&newprom1'
set termout on
set serveroutput on
当实例还未启动的时候这条sql是没有任何结果的,
select user||'@'||sys_context('userenv','instance_name')||'-'||'SQL> ' newprom from dual;
导致接下来set sqlprompt '&newprom1'运行的时候变量newprom1值为空,从而会等待前台输入值给newprom1变量,这个等待的过程就会给用户造成sqlplus hang住的假象,按照一般用户的习惯发现sqlplus hang住时会频繁的敲回车,敲完回车后sqlplus还是hang那里。仔细分析一下敲回车后其实已经给newprom1变量赋值了,后续已经可以执行startup命令启动instance了,只不过此时newprom1变量值为空,没有回显我们熟悉的SQL>到屏幕上,所以让我们误以为sqlplus hang住了。以下测试验证上面的判断:
tstdb1@jq570322b:/home/tstdb1>sqlplus '/as sysdba'
SQL*Plus: Release 11.2.0.3.0 Production on Mon Mar 2 10:35:36 2015
Copyright (c) 1982, 2011, Oracle. All rights reserved.
Connected to an idle instance. <===== sqlplus hang住了,但其实在等待前台输入
<=====此处敲击回车
startup <=====运行起库命令
ORACLE instance started.
Total System Global Area 6413680640 bytes
Fixed Size 2233480 bytes
Variable Size 4060089208 bytes
Database Buffers 2332033024 bytes
Redo Buffers 19324928 bytes
Database mounted.
Database opened. <=====数据库启动成功
quit <=====退出sqlplus
tstdb1@jq570322b:/home/tstdb1>sqlplus '/as sysdba' <=====再次sqlplus连接数据库
SQL*Plus: Release 11.2.0.3.0 Production on Mon Mar 2 10:38:37 2015
Copyright (c) 1982, 2011, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SYS@tstdb1-SQL> <=====这时提示符正常显示了,因为instance启动了
解决这个问题只要在glogin.sql里加入一行:为newprom1变量定义一个初始值(红色部分)
set termout off
col newprom new_value newprom1
define newprom1="SQL> "
select user||'@'||sys_context('userenv','instance_name')||'-'||'SQL> ' newprom from dual;
set sqlprompt '&newprom1'
set termout on
set serveroutput on
有了这个初始值,在instance未启动的情况下,sqlplus连接后就会出现我们熟悉的SQL> 提示符,sqlplus就不会再hang住了。
需要注意的是还有一个作用于glogin.sql类似的文件login.sql,执行sqlplus的时候会先去执行glogin.sql,然后会在当前目录下寻找login.sql文件,如果有的话执行login.sql;如果当前目录没有那么到SQLPATH环境变量定义的路径里进一步寻找login.sql文件如果找到的话执行login.sql内容。glogin.sql和login.sql的区别在于前者是全局有效的,后者属于每个用户的个性化设置。有点像shell里的.login和.profile的关系。
这个例子其实是glogin.sql给我们开了个小小的玩笑,提醒我们glogin.sql、login.sql是进入sqlplus的两道关口,做配置的时候要不要轻视它们