代码之家  ›  专栏  ›  技术社区  ›  skaffman

dbms-utility.get-time滚动?

  •  2
  • skaffman  · 技术社区  · 15 年前

    我遇到了一个庞大的遗留PL/SQL过程的问题,它具有以下逻辑:

    l_elapsed := dbms_utility.get_time - l_timestamp;
    

    哪里 l_elapsed l_timestamp 属于类型 PLS_INTEGER Ly时间戳 保留上一次调用的结果 get_time

    在批处理运行期间,该行突然开始出现故障, ORA-01426: numeric overflow

    有关的文档 获得时间 有点模糊,可能是故意的,但它强烈地表明返回值没有绝对意义,可以是几乎任何数值。所以我怀疑它被分配给 PLS-整数 ,它只能支持32位整数。然而,互联网上充斥着人们做这种事情的例子。

    当我呼叫时发现了吸烟枪 获得时间 手动返回值 - 214512572 ,可能接近32位有符号整数的最小值。我想知道在第一次呼叫 获得时间 接下来,Oracle的内部计数器从其最大值和最小值滚过来,导致在试图从另一个值中减去一个值时溢出。

    这可能是一个解释吗?如果是这样,这是否是 获得时间 功能?我可以等到今晚再看看这批货是否会失败,但我很想在那之前得到一个解释。

    3 回复  |  直到 13 年前
        1
  •  2
  •   Vincent Malgrat    15 年前

    10g doc :

    根据平台和机器的不同,返回的数字范围为-2147483648到2147483647,应用程序在确定间隔时必须考虑数字的符号。例如,在两个负数的情况下,应用程序逻辑必须允许第一个(早)数字大于第二个(晚)数字,后者更接近于零。同样,应用程序也应该允许第一个(早期)数字为负数,第二个(后期)数字为正数。

    因此,尽管可以安全地分配 dbms_utility.get_time 到A PLS_INTEGER 理论上,在批处理运行的执行过程中可能(但不太可能)发生溢出。两个值之间的差异将大于2^31。

    如果您的工作需要很多时间(因此增加了溢出发生的可能性),您可能需要切换到timestamp数据类型。

        2
  •  3
  •   JulesLt    14 年前

    可能会晚些,但这可能会有利于搜索同一问题的人。

    底层实现是一个简单的32位二进制计数器,从上次启动数据库开始,每隔100秒递增一次。

    此二进制计数器正在映射到一个pl/sql binary_integer类型-这是一个有符号的32位整数(在64位计算机上没有将其更改为64位的迹象)。

    因此,假设时钟从零开始,大约248天后,它将达到+ve整数限制,然后翻转成-ve值,然后下降到零。

    好消息是,如果两个数字的符号相同,您可以做一个简单的减法来查找持续时间,否则您可以使用32位的余数。

        IF SIGN(:now) = SIGN(:then) THEN
            RETURN :now - :then;
        ELSE
            RETURN MOD(:now - :then + POWER(2,32),POWER(2,32));
        END IF;
    

    编辑:如果时间间隔太大(248天),则此代码将突破in t限制并失败,但无论如何,您不应该使用get_time来比较以天为单位的持续时间度量(见下文)。

    最后一个问题是,为什么你要用“获取时间”。

    历史上,它是获得次二次的唯一方法,但是自从引入了systimestamp之后,您使用get-time的唯一原因是因为它很快——它是一个32位计数器的简单映射,没有真正的类型转换,并且不会对底层的OS时钟功能造成任何影响(systimestamp似乎如此)。

    因为它只测量相对时间,所以它只用于测量两点之间的持续时间。对于任何花费大量时间的任务(你知道,超过1/1000秒左右),使用时间戳的成本是微不足道的。

    实际有用的次数很少(我唯一发现的是检查缓存中数据的年龄,在缓存中对每个访问进行时钟命中会变得很重要)。

        3
  •  0
  •   Rob van Wijk    15 年前

    将负值赋给PLS_整型变量会引发ORA-01426:

    SQL> l
      1  declare
      2    a pls_integer;
      3  begin
      4    a := -power(2,33);
      5* end;
    SQL> /
    declare
    *
    FOUT in regel 1:
    .ORA-01426: numeric overflow
    ORA-06512: at line 4
    

    但是,您似乎建议-214512572接近-2^31,但除非您忘记键入数字,否则它不是。我们在看一把吸烟枪吗?

    当做, Rob。