Дело в том, что "случайный" на самом деле не случайный .Учитывая то же самое начальное значение для DBMS_RANDOM.INITIALISE()
, последующие вызовы DBMS_RANDOM.VALUE()
вернут тот же результат.Проверьте это:
SQL> exec DBMS_RANDOM.initialize (val => 1)
PL/SQL procedure successfully completed.
SQL> select TRUNC(DBMS_RANDOM.value(low => 1, high => 65535)) from dual
2 /
TRUNC(DBMS_RANDOM.VALUE(LOW=>1,HIGH=>65535))
--------------------------------------------
49214
SQL> r
1* select TRUNC(DBMS_RANDOM.value(low => 1, high => 65535)) from dual
TRUNC(DBMS_RANDOM.VALUE(LOW=>1,HIGH=>65535))
--------------------------------------------
56385
SQL> r
1* select TRUNC(DBMS_RANDOM.value(low => 1, high => 65535)) from dual
TRUNC(DBMS_RANDOM.VALUE(LOW=>1,HIGH=>65535))
--------------------------------------------
23941
SQL> exec DBMS_RANDOM.initialize (val => 1)
PL/SQL procedure successfully completed.
SQL> select TRUNC(DBMS_RANDOM.value(low => 1, high => 65535)) from dual;
TRUNC(DBMS_RANDOM.VALUE(LOW=>1,HIGH=>65535))
--------------------------------------------
49214
SQL> r
1* select TRUNC(DBMS_RANDOM.value(low => 1, high => 65535)) from dual
TRUNC(DBMS_RANDOM.VALUE(LOW=>1,HIGH=>65535))
--------------------------------------------
56385
SQL> r
1* select TRUNC(DBMS_RANDOM.value(low => 1, high => 65535)) from dual
TRUNC(DBMS_RANDOM.VALUE(LOW=>1,HIGH=>65535))
--------------------------------------------
23941
SQL>
Если мы посмотрим на код, который вы получили с сайта Тима, мы увидим следующую строку:
l_seed := TO_NUMBER(TO_CHAR(SYSDATE,'YYYYDDMMSS'));
Из чего мы можем предположить, что ваш процесс вставляет 10-11 строк в секунду:)
Если вы замените SYSDATE на SYSTIMESTAMP и измените маску, чтобы перейти на миллисек (или меньше), то вы должны получать разные начальные значения каждый раз, и, следовательно, разные значения каждый раз.Обратите внимание, что вам все равно нужно принудительно переоценить функцию, чтобы гарантировать получение разных результатов для каждой строки (см. Демонстрацию ниже).
Хм, я сказал "гарантия".Ой-ой.Это по своей природе случайный, что он может дать тот же результат, что и два работает.Так что, возможно, это должно быть «для минимизации вероятности получения одинакового результата для каждой строки».
В качестве альтернативы удалите инициализацию из функции и вызовите ее перед началом массовых вставок.Возможно ли это, зависит исключительно от вашей бизнес-логики.
Демонстрация
Вот функция, которая генерирует «случайное» число:
create or replace function get_random_number
(p_seed in number := 0)
return pls_integer
is
begin
if p_seed = 0
then
DBMS_RANDOM.initialize (val => TO_NUMBER(TO_CHAR(SYSDATE,'YYYYDDMMSS')));
else
DBMS_RANDOM.initialize (val => p_seed);
end if;
return TRUNC(DBMS_RANDOM.value(low => 1, high => 65535));
end;
/
Если мы вызываем его двадцать раз спараметр по умолчанию возвращает каждый раз одно и то же число:
SQL> select rownum
, get_random_number
from dual
connect by level <= 20
/
2 3 4 5
ROWNUM GET_RANDOM_NUMBER
---------- -----------------
1 10239
2 10239
3 10239
4 10239
5 10239
6 10239
7 10239
8 10239
9 10239
10 10239
11 10239
12 10239
13 10239
14 10239
15 10239
16 10239
17 10239
18 10239
19 10239
20 10239
20 rows selected.
SQL>
Принимая во внимание, что если мы передаем значение, оно использует разные начальные значения каждый раз, и вот!мы получаем другой результат:
SQL> select rownum
, get_random_number(rownum)
from dual
connect by level <= 20
/
2 3 4 5
ROWNUM GET_RANDOM_NUMBER(ROWNUM)
---------- -------------------------
1 49214
2 6476
3 42426
4 2370
5 48546
6 52483
7 6964
8 46764
9 27569
10 7673
11 52446
12 50229
13 27861
14 31413
15 11518
16 13471
17 38766
18 9949
19 61656
20 25797
20 rows selected.
SQL>
Это работает, потому что передача в ROWNUM вызывает оценку функции для каждой строки.Не следует использовать ROWNUM в качестве начального числа в производственной системе: временные метки лучше.Или объедините дату и время с rownum, чтобы обеспечить уникальное начальное число для каждой строки.