【发布时间】:2019-10-29 00:07:24
【问题描述】:
不久前,我需要从 Oracle 数据库中的表中获取随机行。我发现的最普遍的解决方案是:
SELECT * FROM
( SELECT * FROM tabela WHERE warunek
ORDER BY dbms_random.value )
WHERE rownum = 1
但是,这对于大型表来说性能非常高,因为它首先按随机顺序对表进行排序,然后抓取第一行。
今天,我的一位同事提出了一种不同的方法:
SELECT * FROM (
SELECT * FROM MAIN_PRODUCT
WHERE ROWNUM <= CAST((SELECT COUNT(*) FROM MAIN_PRODUCT)*dbms_random.value AS INTEGER)
ORDER BY ROWNUM DESC
) WHERE ROWNUM = 1;
它的运行速度更快,并且似乎返回随机值,但真的如此吗?有人可以深入了解它是否真的是随机的并且行为是否符合预期?我真的很好奇为什么我在寻找时没有在其他任何地方找到这种方法,如果它确实是随机的并且在性能方面更好,为什么它没有更普遍?
【问题讨论】:
-
使用
SELECT * FROM tabela WHERE warunek AND ROWNUM =1。当然,当你多次执行查询时,你会得到相同的行,但原则上你会得到一个随机的行。 -
也看到了这种方法,但遗憾的是它不能满足我的需求(在测试场景中随机行被获取然后传递给一个 SOAP 请求,这意味着查询将被执行多次)
-
您对为什么第一个查询慢的解释不正确。内部查询需要很长时间,因为需要很长时间才能为 EACH ROW 生成不同的随机数。 Oracle不会根据随机数对内部查询的所有行进行排序;相反,它能够在内部查询中推送外部 ROWNUM = 1 条件 - 它只会返回具有最小随机值的行,它不会按随机值对所有行进行排序。第二种方法更好,因为它只需要生成一个随机值。
-
"Oracle 不会根据随机数对内部查询的所有行进行排序;相反,它能够将外部 ROWNUM = 1 条件推入内部查询" @mathguy 真的吗?这听起来不太合乎逻辑检查manual 所说的内容,因为您说优化将
SELECT * FROM ( SELECT * FROM tabela ORDER BY dbms_random.value ) WHERE rownum = 1重写为SELECT * FROM tabela WHERE rownum = 1 ORDER BY dbms_random.value??这是不正确的,因为这些查询并不意味着同样的事情。 -
@RaymondNijland - 不,这不是我要说的。如果没有内部查询 - 外部查询结构,您将无法重写查询。相反,我解释的是如何在内部解释查询。如果我说“订购这组”,然后我说“给我 xyz 值最小的行”,我不会真正订购该组中的所有东西。我将一一检查每一行中的 xyz 值;每当我发现比以前记录的值低时,我将覆盖“记录”行并继续前进。我不需要按 xyz 排序所有行。确实,这就是 Oracle 运行时的工作方式。