OracleDBからランダムに行を選択する必要があります。
例: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;
これは、テーブルを並べ替える必要がないため、より効率的です。
要約すると、2つの方法が導入されました
1) using order by DBMS_RANDOM.VALUE clause
2) using sample([%]) function
最初の方法は「CORRECTNESS」に利点があります。つまり、実際に存在する場合でも結果の取得に失敗することはありません。一方、2番目の方法では、サンプリング中に情報が減少するため、クエリ条件を満たす場合でも結果が得られない可能性があります。
2番目の方法は、「効率的」という利点があります。つまり、結果が早く得られ、データベースへの負荷が軽くなります。DBAから、最初の方法を使用したクエリでデータベースに負荷がかかるという警告が表示されました。
あなたの興味に応じて2つの方法のいずれかを選択できます!
巨大なテーブルの場合、dbms_random.valueによるソートを使用した標準的な方法は効果的ではありません。これは、テーブル全体をスキャンする必要があり、dbms_random.valueは非常に遅い関数であり、コンテキストスイッチが必要なためです。このような場合、3つの追加の方法があります。
1:使用sample
句:
例えば:
select *
from s1 sample block(1)
order by dbms_random.value
fetch first 1 rows only
つまり、すべてのブロックの1%を取得してから、ランダムに並べ替えて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;
3:ランダムなテーブルブロックを取得し、ROWIDを生成し、このROWIDによってテーブルから行を取得します。
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
)
);
テーブル
SELECT * FROM
(
SELECT column_name FROM table_name
ORDER BY dbms_random.value
)
WHERE rownum = 1;