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

时间:2013-02-26 21:20:35

标签: sql oracle random sample rownum

我从一些表中提取随机样本并注意到,根据我编写查询的方式,它不起作用。显然,我没有使用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&lt;查询中的10000完成了吗?

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

编辑:添加版本9.2.0.8

3 个答案:

答案 0 :(得分:2)

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

我的猜测是你的第二个查询正在优化:

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

并且在内联视图中以某种方式具有rownum条件会阻止优化。

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

修改

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

  

从SQL调用函数时,最好不要依赖于频率   函数被调用,以什么顺序或其他什么。简而言之,假设   没有。并记住 - SQL重写启动,我们重写您的SQL   一直以来。不要依赖副作用

答案 1 :(得分: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(),我怀疑它会被绊倒。也就是说,编译器检测到“稳定”函数,因此它只查找前一个值。并且,它使用缓存值,多次调用函数进行短路。

如果这是正确的,那么上面的查询将返回行。如果是这样,那么我会把数据库的这个“特性”称为一个错误 - 可能有一个数据库优化工程师,但是,谁会将其作为一个非常有用的功能进行辩护。

答案 2 :(得分:0)

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