yangtingkun
===========================================================
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类型来保存数值,就不会出现这个问题了。

yangtingkun 发表于:2007.08.21 23:01 ::分类: ( ORACLE , Bug ) ::阅读:(1775次) :: 评论 (0)

发表评论
标题

在此添加评论
表情符号: smile laughing tongue angry crying sad wassat wink

称呼

邮箱地址(可选)

个人主页(可选)

 authimage


切换风格
新闻聚合
博客日历
文章归档...
最新发表...
最新评论...
最多阅读文章...
最多评论文章...
博客统计...
Blog信息
网站链接...