我需要从Oracle数据库中随机选择行。
例如:假设有一个包含100行的表,我如何从这100行中随机返回20条记录。
SELECT *
FROM (
SELECT *
FROM table
ORDER BY DBMS_RANDOM.RANDOM)
WHERE rownum < 21;
SAMPLE()不能保证返回恰好20行,但对于大型表格而言,可能更加适用(且性能显著优于完整的随机排序查询):
SELECT *
FROM table SAMPLE(20);
注意: 这里的20
是大约的百分比,不是期望的行数。在这种情况下,由于您有100行数据,要获取大约20行,您需要请求一个20%的样本。
SELECT * FROM table SAMPLE(10) WHERE ROWNUM <= 20;
这种方法更有效率,因为它不需要对表格进行排序。
SELECT column FROM
( SELECT column, dbms_random.value FROM table ORDER BY 2 )
where rownum <= 20;
对于大表格,使用 dbms_random.value 排序的标准方法并不高效,因为你需要扫描整个表格,并且 dbms_random.value 是一个相当慢的函数,它需要上下文切换。针对这种情况,有三种附加方法:
1:使用 sample 子句:
例如:
select *
from s1 sample block(1)
order by dbms_random.value
fetch first 1 rows only
如果ie获得了1%的所有区块,那么对它们进行随机排序并只返回一行。
2: 如果在服从正态分布的列上拥有索引/主键,则可以获取最小值和最大值,在此范围内获取随机值,并获取第一行具有大于或等于该随机生成值的值。
示例:
--big table with 1 mln rows with primary key on ID with normal distribution:
Create table s1(id primary key,padding) as
select level, rpad('x',100,'x')
from dual
connect by level<=1e6;
select *
from s1
where id>=(select
dbms_random.value(
(select min(id) from s1),
(select max(id) from s1)
)
from dual)
order by id
fetch first 1 rows only;
select *
from s1
where rowid = (
select
DBMS_ROWID.ROWID_CREATE (
1,
objd,
file#,
block#,
1)
from
(
select/*+ rule */ file#,block#,objd
from v$bh b
where b.objd in (select o.data_object_id from user_objects o where object_name='S1' /* table_name */)
order by dbms_random.value
fetch first 1 rows only
)
);
总之,介绍了两种方法
1) using order by DBMS_RANDOM.VALUE clause
2) using sample([%]) function
第一种方法具有“正确性”的优势,这意味着如果结果实际存在,您将永远不会失败获得结果,而在第二种方法中,即使存在满足查询条件的案例,由于采样时信息减少,您也可能没有结果。
第二种方法具有“效率”的优势,这意味着您可以更快地获得结果并给数据库带来轻负载。我收到了 DBA 的警告,因为使用第一种方法的查询会给数据库带来负载。
您可以根据自己的兴趣选择其中一种方法!
Select *
from (select *
from table
order by dbms_random.value) -- you can also use DBMS_RANDOM.RANDOM
where rownum < 21;
以下是如何从每个组中随机抽取样本的方法:
SELECT GROUPING_COLUMN,
MIN (COLUMN_NAME) KEEP (DENSE_RANK FIRST ORDER BY DBMS_RANDOM.VALUE)
AS RANDOM_SAMPLE
FROM TABLE_NAME
GROUP BY GROUPING_COLUMN
ORDER BY GROUPING_COLUMN;
我不确定它有多高效,但如果你有很多类别和子类别,这似乎可以很好地完成工作。