首页 > Linux操作系统 > Linux操作系统 > V$SQL视图显示结果异常的诊断
今天碰到一个奇怪的现在,在检查会话执行的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语句是不正常的,语句中甚至连SELECT、INSERT、UPDATE、DELETE命令都不包括。但是SQL又不完全是乱码,从显示的部分看,大部分是有一定逻辑在里面的。
观察这个SQL,感觉像是V$SQL视图中显示了部分SQL,而没有从开头显示,而且即使是部分SQL,也没有连续显示,因为连续的两行并不连贯。
首先想到的就是Oracle的bug,因为除了这个解释外,很难解释这个现象。那么如果确实是由于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,对于长度大于1000的SQL,会显示前面1000个字符。而从V$SQLTEXT_WITH_NEWLINES视图的结果看,SQL的长度肯定超过了1000,而从V$SQL中的查询结果看,长度远远小于1000。
查询一下V$SQL中SQL_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)换行。
这会导致在UNIX和LINUX环境下,随后的数据仍然从第一行的第一列位置开始继续输出,这样就会覆盖前面的内容。
一个简单的例子:
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/,如需转载,请注明出处,否则将追究法律责任。