为什么在使用dbms_random.value函数时需要在Oracle SQL查询中包含rownum字段?

为什么在使用dbms_random.value函数时需要在Oracle SQL查询中包含rownum字段?,sql,oracle,random,sample,rownum,Sql,Oracle,Random,Sample,Rownum,我从一些表中随机抽取了一个样本,并注意到根据我编写查询的方式,它不起作用。显然,我并没有使用所有的_tab_列,我只是提供了一个可以在香草实例9.2.0.8上使用的示例 为什么这样做有效 select * from ( select floor(dbms_random.value(0,1000)) as randomval from all_tab_columns where rownum < 10000 ) where randomva

我从一些表中随机抽取了一个样本,并注意到根据我编写查询的方式,它不起作用。显然,我并没有使用所有的_tab_列,我只是提供了一个可以在香草实例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版

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

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

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

在内联视图中使用rownum标准会妨碍这种优化

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

编辑

在谷歌搜索了一下之后,我发现了这一点,这似乎是相关的。Tom Kyte的回答以这句话结尾:

从SQL调用函数时,最好不要依赖频率 函数被调用,以什么顺序调用,或者其他什么。简言之,假设 没有什么记住——SQL重写开始了,我们重写您的SQL 一直如此。不要依赖副作用


我认为@Peter已经了解了一些事情,但这需要更多的解释

在Oracle中,函数可以是确定性的,也可以不是确定性的。这意味着当使用相同的参数调用函数时,返回相同的值。因此,sqrt是确定性的;dbms_随机不是。其他数据库对这两个类别使用术语“稳定”和“易失性”

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

select * from (
    select 
        dbms_random.value(0,1000) as randomval
    from 
        all_tab_columns 
) where randomval > 200 and randomval < 300;
然而,我怀疑它是因为地板而绊倒的。也就是说,编译器检测到一个稳定的函数,所以它只查找上一个值。并且,它使用缓存的值,多次短路调用函数


如果这是正确的,那么上面的查询将返回行。如果是这样的话,那么我将把数据库的这一功能称为bug——不过,可能有一位数据库优化工程师在某处为这一非常有用的功能辩护。

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

您能定义它不起作用吗?第二个查询肯定会返回行。两个查询返回的行数未知,尽管第一个查询返回的行数不可能超过10000行。第二个查询根本不为我返回任何行。我在sqlplus中没有选择行。随机性的本质是它是随机的。因此,内部查询很可能不返回201和299之间的值。事实上,在ROWNUM上添加一个过滤器可能会使这种结果更有可能,而不是更少。因此,我认为您不太可能有一个可复制的测试用例。APC-我使用了一个有600万个结果的表,并尝试了rownum<10000000的查询。查询返回了大约600000。这是我争取的10%随机样本。我只是不明白为什么查询似乎需要rownum0或者可能还有一个no_merge/no_push_pred提示。在9i9.2.0.2-.8中有一个bug,特别是在使用dbms_random的查询中,视图被合并,我认为这就是这里发生的事情,并且不知何故具有rownum标准。rownum阻止谓词推送,即谓词不能推送超过rownum,因为它可能会更改所有对象的答案,例如从select*选择rownum>0,其中对象名称='DUAL'和所有者='SYS'不会被重写,以将对象名称/类型推送到内部视图中,因此在该示例中,您将看到它必须完全扫描整个视图第一,表现不佳。内部select与where子句中的rownum也会产生相同的效果。