gpt4 book ai didi

oracle - systimestamp 和 sysdate 的奇怪行为

转载 作者:行者123 更新时间:2023-12-04 09:38:31 26 4
gpt4 key购买 nike

今天我遇到了一个我无法解释的情况,希望你能。

归结为:

比方说 function sleep() return number;循环 10 秒,然后返回 1。

一个 sql 查询,如

SELECT systimestamp s1, sleep(), systimestamp s2 from dual;

将导致 s1 和 s2 的两个相同值。所以这有点优化。

一个 PLSQL 块
a_timestamp := systimestamp + 5sec;
IF systimestamp < a_timestamp and sleep() = 1 and systimestamp > a_timestamp THEN
[...]
END IF;

将评估为真,因为表达式是从左到右评估的,并且由于 sleep(),第二个系统时间戳比第一个大 10 秒,并且 a_timestamp 介于两者之间。 +5sec 语法是伪代码,但请耐心等待。所以这里的系统时间戳没有优化。

但现在它变得时髦:
IF systimestamp between systimestamp and systimestamp THEN [...]

总是假的,但是
IF systimestamp + 0 between systimestamp + 0 and systimestamp + 0 THEN [...]

永远是真的。

为什么?我很迷惑...

这也发生在 sysdate 上

最佳答案

当你这样做时:

if systimestamp between systimestamp and systimestamp then

非确定性 systimestamp call 只是被评估了 3 次,每次得到的结果都略有不同。

你可以看到同样的效果
if systimestamp >= systimestamp then

这也总是返回 false。

除了,它并不总是如此。如果服务器足够快和/或它所在的平台对于时间戳小数秒的精度足够低(即在 Windows 上,我相信它仍然将精度限制为毫秒),那么所有这些调用仍然可以获得相同的值。大多数时候。

SQL 中的情况有点不同;作为等价物:
select *
from dual
where systimestamp between systimestamp and systimestamp;

将始终返回一行,因此条件始终为真。即 explicitly mentioned in the documentation :

All of the datetime functions that return current system datetime information, such as SYSDATE, SYSTIMESTAMP, CURRENT_TIMESTAMP, and so forth, are evaluated once for each SQL statement, regardless how many times they are referenced in that statement.



在 PL/SQL 中没有这样的限制/优化(取决于您如何看待它)。当您使用 between it does say :

The value of the expression x BETWEEN a AND b is defined to be the same as the value of the expression (x>=a) AND (x<=b) . The expression x will only be evaluated once.



和 SQL 引用 also mentions that :

In SQL, it is possible that expr1 will be evaluated more than once. If the BETWEEN expression appears in PL/SQL, expr1 is guaranteed to be evaluated only once.



但它没有说明跳过对 a 和 b(或 expr2 或 expr3)的评估,即使对于 PL/SQL 中的系统日期时间函数也是如此。

所以你的 between 中的所有三个表达式将被评估,它将对 systimestamp 发出三个单独的调用,它们都会(通常)得到略有不同的结果。你最终得到:
if initial_time between initial_time + 1 microsecond and initial_time + 2 microseconds then

或者换一种方式
if (initial_time >= initial_time + 1 microsecond) and (initial_time <= initial_time + 2 microseconds) then

虽然 (initial_time <= initial_time + 2 microseconds)永远都是真的, (initial_time >= initial_time + 1 microsecond)必须为 false - 除非该平台/服务器/调用的第一次和第三次评估之间的间隔实际上为零。当它为零时,条件评估为真;其余时间,当有任何可测量的延迟时,它将评估为 false。

正如@Connor 所示(我在评论中提到),您的其他示例都以删除小数秒的方式操作时间戳,将部分或全部结果转换为日期。这些与您的核心问题无关,为什么 if systimestamp between systimestamp and systimestamp then是(通常)错误的。

关于oracle - systimestamp 和 sysdate 的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62437737/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com