2

我正在从一些表中抽取一个随机样本,并注意到根据我编写查询的方式,它不起作用。显然,我没有使用 all_tab_columns,我只是提供了一个适用于 vanilla 实例 (9.2.0.8) 的示例。

为什么这行得通?

select * from (
    select 
        floor(dbms_random.value(0,1000)) as randomval
    from 
        all_tab_columns where rownum < 10000
) where randomval > 200 and randomval < 300;

但这不会返回任何结果。

select * from (
    select 
        floor(dbms_random.value(0,1000)) as randomval
    from 
        all_tab_columns 
) where randomval > 200 and randomval < 300;

查询中的 rownum < 10000 有什么作用?

编辑:澄清什么不起作用。

编辑:添加版本 9.2.0.8

4

3 回答 3

2

我没有明确的答案,但我有一个理论......

我的猜测是您的第二个查询正在为此优化:

select * 
  from all_tab_columns 
 where floor(dbms_random.value(0,1000))> 200 
   and floor(dbms_random.value(0,1000)) < 300;

并且rownum在您的内联视图中以某种方式具有标准正在阻止该优化。

这也可以解释为什么我们中的一些人(包括我在内)无法看到您描述的问题 - 因为我们使用不同版本的 Oracle,并且查询对我们的优化方式不同。

编辑

经过一番谷歌搜索,我遇到了这个 AskTom 问题,这似乎是相关的。Tom Kyte 的回答以这一行结束:

从 SQL 调用函数时,最好不要依赖函数被调用的频率、调用顺序等。简而言之,什么都不做。请记住 - SQL 重写开始了,我们一直在重写您的 SQL。不要依赖副作用

于 2013-02-26T21:52:31.000 回答
1

我认为@Peter 正在做某事,但需要更多解释。

在 Oracle 中,函数可以是 DETERMINISTIC 也可以不是。这意味着该函数在使用相同的参数调用时返回相同的值。所以,sqrt()是确定性的;dbms_random()不是。其他数据库使用术语 STABLE 与 VOLATILE 来表示这两个类别。

如果我不得不猜测,Oracle 引擎足够聪明,知道以下查询应该返回行:

select * from (
    select 
        dbms_random.value(0,1000) as randomval
    from 
        all_tab_columns 
) where randomval > 200 and randomval < 300;

但是,我怀疑它会因为floor(). 也就是说,编译器检测到一个“稳定”函数,所以它只是查找以前的值。而且,它使用缓存的值,多次调用该函数。

如果这是正确的,那么上面的查询将返回行。如果是这样,那么我将把数据库的这个“特性”称为一个错误——不过,可能在某个地方有一个数据库优化工程师,他会认为这是一个非常有用的特性。

于 2013-02-26T22:27:04.853 回答
0

您的两个查询都在 Oracle 11g R2 中工作。ROWNUM 是 Oracle 中的伪列,有兴趣可以阅读。

于 2013-02-27T20:49:13.080 回答