В случае огромных таблиц стандартный способ с сортировкой по dbms_random.value неэффективен, потому что вам нужно сканировать всю таблицу, а dbms_random.value - довольно медленная функция и требует переключения контекста. Для таких случаев есть 2 хорошо известных метода:
- Использование
sample
clause:
например:
select *
from s1 sample block(1)
order by dbms_random.value
fetch first 1 rows only
ie получить 1% всех блоков, затем отсортировать их случайным образом и вернуть только 1 строку.
если у вас есть индекс / первичный ключ в столбце с нормальным распределением, вы можете получить минимальные и максимальные значения, получить случайное значение в этом диапазоне и получить первую строку со значением, большим или равным этому случайно сгенерированному значению.
Пример:
--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
)
);