ITPub博客

首页 > Linux操作系统 > Linux操作系统 > V$SQL视图显示结果异常的诊断

V$SQL视图显示结果异常的诊断

原创 Linux操作系统 作者:yangtingkun 时间:2007-11-02 00:00:00 0 删除 编辑

今天碰到一个奇怪的现在,在检查会话执行的SQL时发现,V$SQL视图中SQL_TEXT列中的数据是不正常的。


为了方便的定位问题,将显示异常的V$SQL记录备份到了BAK_V$SQL表中,首先看一下异常的SQL语句:

SQL> SELECT SQL_TEXT FROM BAK_V$SQL;

SQL_TEXT
--------------------------------------------------------------------------------------------
info.CONTRACT_ITEM_ID,info.BUYER_ORG_ID a
el
未承诺'DISCOUNT_STEP is null or INC.NUM_STEP is null then
to_char(INC.DISCOUNT_STEP * 100,'0.0') || '%'
劭勐
?' ||
'
CASH.CASH is null and CASH.CASH_THIRTY is null then
'
现款
:' || to_char(CASH.CASH * 100,'0.0'
'30
日结款
:'SH_THIRTY is not null then
case whend end as CASH_DISCOUNT,0,'0.0') || '%;'
en info.modify_date > inc.modify_date and info.modify_date > cash.modify_date then info.mo


显然这个SQL语句是不正常的,语句中甚至连SELECTINSERTUPDATEDELETE命令都不包括。但是SQL又不完全是乱码,从显示的部分看,大部分是有一定逻辑在里面的。

观察这个SQL,感觉像是V$SQL视图中显示了部分SQL,而没有从开头显示,而且即使是部分SQL,也没有连续显示,因为连续的两行并不连贯。

首先想到的就是Oraclebug,因为除了这个解释外,很难解释这个现象。那么如果确实是由于bug,导致V$SQL显示不完整,那么完整的SQL又是什么呢,是否完整的SQL也会存在问题:

SQL> SELECT SQL_TEXT FROM V$SQLTEXT_WITH_NEWLINES
2 WHERE HASH_VALUE IN (SELECT HASH_VALUE FROM BAK_V$SQL)
3 ORDER BY PIECE;

SQL_TEXT
----------------------------------------------------------------
SELECT * FROM (
SELECT ROWNUM as numrow, yy.* from ( select


info.record_id,
info.CONTRACT_ITEM_ID,info.BUYER_ORG_ID

.

.

.

WHERE numrow >= 1

32 rows selected.

V$SQLTEXT_WITH_NEWLINES中查询,发现SQL的结果是正常的,而且V$SQL中显示的内容基本上在V$SQLTEXT_WITH_NEWLINES中都可以找到,只不过不是连续的。

从这一点上看,似乎更可以肯定是bug了。在Metalink上查找了半天,却没有发现类似的描述。

而且一直存在一个疑惑,没有道理完全显示是正常的,而显示前1000个就出现错误,而且错误出现的那么离谱,很多信息都是跳着显示的。更关键的是,想不到引发这个bug的原因。如果确实是显示问题,那么应该对所有的SQL都会有问题,如果仅仅对这个SQL有问题,那么多半问题出在这个SQL的本身。

V$SQL中的SQL_TEXT字段长度为1000,对于长度大于1000SQL,会显示前面1000个字符。而从V$SQLTEXT_WITH_NEWLINES视图的结果看,SQL的长度肯定超过了1000,而从V$SQL中的查询结果看,长度远远小于1000

查询一下V$SQLSQL_TEXT的具体长度:

SQL> SELECT LENGTH(SQL_TEXT) FROM BAK_V$SQL;

LENGTH(SQL_TEXT)
----------------
980

长度为980,这个长度到是对的,可是查询出来的内容却很少,再次查询,将长度和内容一起显示:

SQL> SELECT LENGTH(SQL_TEXT), SQL_TEXT FROM BAK_V$SQL;

LENGTH(SQL_TEXT)
----------------
SQL_TEXT
-----------------------------------------------------------------------------------------
980
info.CONTRACT_ITEM_ID,info.BUYER_ORG_ID a
el
未承诺'DISCOUNT_STEP is null or INC.NUM_STEP is null then
to_char(INC.DISCOUNT_STEP * 100,'0.0') || '%'
劭勐
?' ||
'
CASH.CASH is null and CASH.CASH_THIRTY is null then
'
现款
:' || to_char(CASH.CASH * 100,'0.0'
'30
日结款
:'SH_THIRTY is not null then
case whend end as CASH_DISCOUNT,0,'0.0') || '%;'
en info.modify_date > inc.modify_date and info.modify_date > cash.modify_date then info.mo


这个格式不是很美观,设置COL调整一下输出的格式:

SQL> COL SQL_TEXT FORMAT A70 WRAP
SQL> SELECT LENGTH(SQL_TEXT), SQL_TEXT FROM BAK_V$SQL;

LENGTH(SQL_TEXT) SQL_TEXT
---------------- ----------------------------------------------------------------------
info.T ROWNUM as numrow, yy.* from ( select
info.CONTRACT_ITEM_ID,info.BUYER_ORG_ID as BUYER_OR
when INC.DISCOUNT_STEP is null or INC.NUM_
'
起付诺'EP is null then
to_char(
:' || to_char(INC.NUM_STEP) || ',折扣率
:' ||
end as NUM_DISCOUNT,T_STEP * 100,'0.0') || '%'
when CASH.CASH is null and CASH.CASH_THIR
case
? is null then
'
现款
:' || to_char(CSH.CASH is not null then
end''e ASH.CASH * 100,'0.0') || '%;'
'en CASH.CASH_THIRTY is not null then
30
日结款
:' || to_char(CASH.CASH_THIRTY * 100,'0.0') || '%;'
case whend end as CASH_DISCOUNT,
en info.modify_date > inc.modify_date and info.modify_date > cash.modi
fy_date then info.mo


奇怪的事情出现了,不仅SQL_TEXT的长度内容被覆盖掉了,而且SQL_TEXT的内容并没有从SQL_TEXT的栏位开始,而是从一行的开始位置开始的。更关键的是,查询的内容已经发生了变化。

到这里已经可以确定问题的原因了,为了更加精确的定位问题,将SQL_TEXT中的内容进行DUMP

SQL> SELECT DUMP(SUBSTR(SQL_TEXT, 1, 100), 16) FROM BAK_V$SQL;

DUMP(SUBSTR(SQL_TEXT,1,100),16)
-------------------------------------------------------------------------------------------
Typ=1 Len=100: 20,53,45,4c,45,43,54,20,2a,20,46,52,4f,4d,20,28,20,d,20,53,45,4c,45,43,54,20,52,4f,57,4e,55,4d,20,61,73,20,6e,75,6d
,72,6f,77,2c,20,79,79,2e,2a,20,66,72,6f,6d,20,28,20,73,65,6c,65,63,74,20,d,20,69,6e,66,6f,2e,72,65,63,6f,72,64,5f,69,64,2c,d,20,20
,20,20,20,20,20,20,69,6e,66,6f,2e,43,4f,4e,54,52,41


SQL> SELECT SUBSTR(SQL_TEXT, 1, 100) FROM BAK_V$SQL;

SUBSTR(SQL_TEXT,1,100)
-------------------------------------------------------------------------------------------
info.CONTRAumrow, yy.* from ( select

DUMP文件中已经可以清晰的看到问题的原因了,SQL语句中的仅使用了ASCII(0XD)回车符,而没有使用ASCII(0XA)换行。

这会导致在UNIXLINUX环境下,随后的数据仍然从第一行的第一列位置开始继续输出,这样就会覆盖前面的内容。

一个简单的例子:

SQL> SELECT 'AB' || CHR(13) || 'C' FROM DUAL;

'AB'
----
CB

1 row selected.

SQL> SELECT 'AB' || CHR(10) || CHR(13) || 'C' FROM DUAL;

'AB'|
-----
AB
C


1 row selected.

正式这个原因造成了V$SQL中显示不正常,而V$SQLTEXT_WITH_NEWLINES中由于每行只有64个字符,因此还没有被覆盖就切换到下一条记录了。

了解了问题的原因,剩下的就简单了:

SQL> SELECT REPLACE(SQL_TEXT, CHR(13), CHR(10) || CHR(13)) FROM BAK_V$SQL;

REPLACE(SQL_TEXT,CHR(13),CHR(10)||CHR(13))
----------------------------------------------------------------------------------------
SELECT * FROM (
SELECT ROWNUM as numrow, yy.* from ( select
info.record_id,
info.CONTRACT_ITEM_ID,info.BUYER_ORG_ID as BUYER_ORGID,
case
.
.
.
end end as CASH_DISCOUNT,

case when info.modify_date > inc.modify_date and info.modify_date > cash.modify_date then info.mo


手工添加换行信息,就可以解决上面的问题。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/4227/viewspace-69487/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
暂无介绍

注册时间:2007-12-29

  • 博文量
    1954
  • 访问量
    10889449