ITPub博客

首页 > Linux操作系统 > Linux操作系统 > v$sqlarea中BUFFER_GET列出现负值

v$sqlarea中BUFFER_GET列出现负值

原创 Linux操作系统 作者:sanxiagirl 时间:2009-02-13 17:59:50 0 删除 编辑

今天在查询V$SQLAREA的时候发现BUFFER_GET列出现了负值,在yangtingkun的BLOG上看到一篇相关的文章(http://yangtingkun.itpub.net/post/468/385990)。

===========================================================
ORACLE动态性能视图统计值溢出
===========================================================

今天同事在查询V$SQL视图的时候发现BUFFER_GET列出现了负值。研究了一下,感觉应该是Oracle的整型数溢出了。


查询Oracle的V$SQL视图,发现其中一条SQL:SELECT 1 FROM DUAL的BUFFER_GETS变成了负值:

SQL> select to_char(buffer_gets) from v$sql where sql_text = 'SELECT 1 FROM DUAL';

TO_CHAR(BUFFER_GETS)
----------------------------------------
-2069050280

1 row selected.

为什么会出现负数呢,除了bug外似乎没有别的解释,不过即使是bug,Oracle也没有道理写一个负数到动态视图中的。

观察一下执行次数:

SQL> select executions, to_char(buffer_gets) from v$sql where sql_text = 'SELECT 1 FROM DUAL';

EXECUTIONS TO_CHAR(BUFFER_GETS)
---------- ----------------------------------------
742004326 -2068982372

对于DUAL表的扫描,一般每次执行都是3个逻辑读。

SQL> select 742004326*3 from dual;

742004326*3
-----------
2226012978

数量级是一样的,只不过buffer_gets的值是负的。

一般来说出现负值都是由于存储数值的变量发生溢出造成的。Oracle的number类型是38位,存储最大数值可以达到10的125次方,不可能在这么小的数值发生溢出。

不过Oracle的核心程序是用C语言写的,C的int型变量是32位的:

SQL> select to_char(power(2, 32)) from dual;

TO_CHAR(PO
----------
4294967296

这个上限值是对于unsigned int而言的,对于可以表示正书和负数的int类型而言,上限仅仅是这个值的一半。

SQL> select 742004326 * 3 - power(2, 32) / 2 from dual;

742004326*3-POWER(2,32)/2
-------------------------
78529330

显然是由于BUFFER_GETS的值已经超出了这个上限值。而且C采用的补码的算法,当超过最大值2147483647后,数值开始从-2147483648向-1递增。

观察上面两次对BUFFER_GETS的查询,该值已经从-2069050280增加到了-2068982372。

Oracle在这里应该使用UNSIGNED INT类型或者LONG类型来保存数值,就不会出现这个问题了。

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

请登录后发表评论 登录
全部评论

注册时间:2008-01-02

  • 博文量
    142
  • 访问量
    498017