2016-05-17 158 views
1

我们有一个每周生成1000万个随机数的过程,并将它们存储在数据库表(Oracle)中。 我们有下面的逻辑来创建给定范围的随机数字。我们保持生成号码的严格唯一性与先前生成的号码 (已在db表中)。在插入表 (异常情况下重新生成随机数)时,我们通过索引存储随机数和捕获异常的表列来实现此目的。完成这一过程需要将近一天的时间,并继续增加所需的处理时间。用数据库表生成唯一随机数

请帮助我们进行以下查询以改善此过程的性能。

  1. 任何可能的方法来改善我们的随机数生成算法?
  2. 任何可能性,以提高数据库的操作

的事情,我们尝试: 我们已经清除多达可以表数据。 对表格的批插入(2500条记录)已将该过程增加到3-4天,因为每个异常都会导致重新创建每批数字。 我们正在评估并行处理以获得一些改进。

int itemsInPack = 10000000; 
int pinLength = 10; 
int randomSeedByteCount = 10; 
long lowerRangeValue = (long) Math.pow(10.0, (double) (pinLength - 1)); 
long higherRangeValue = 10 * lowerRangeValue; 
long numberRange = higherRangeValue - lowerRangeValue; 

SecureRandom secureRandomNumberGen = SecureRandom.getInstance("SHA1PRNG"); 
byte[] bytes = new byte[1024/8]; 
secureRandomNumberGen.nextBytes(bytes); 
byte[] seed = secureRandomNumberGen.generateSeed(randomSeedByteCount); 
secureRandomNumberGen.setSeed(seed); 

for(int k=0;k<itemsInPack;k++){ 
    double nextDouble = secureRandomNumberGen.nextDouble(); 
    long fraction = (long)(numberRange * nextDouble); 
    long pinNumber = (long)(fraction + lowerRangeValue);//Insert this to table 
    System.out.println("pinNumber: " + pinNumber); 
} 
+0

您不能在Oracle中使用存储过程来执行此操作吗?这似乎是最合适的方法? – RobAu

+0

还有什么是随机数的用例? – RobAu

+0

在数据库中,生成一个从最小值到最大值的数字列表 - 随机排序,然后获取前n行。 – MT0

回答

2

您可以尝试使用Oracle的DBMS_RANDOM.VALUE(low, high)功能做这一切在数据库:

甲骨文设置

CREATE TABLE randomValues (
    rnd NUMBER(11,0) PRIMARY KEY 
); 

插入

DECLARE 
    batchSize NUMBER(4,0) := 2500; 
    numRows NUMBER(8,0) := 1000000; 
BEGIN 
    FOR i IN 1 .. numRows LOOP 
    INSERT INTO randomValues 
    SELECT rnd 
    FROM (
     SELECT DISTINCT 
      FLOOR(
       DBMS_RANDOM.VALUE(
       POWER(10, 10), 
       POWER(10, 11) 
       ) 
      ) AS rnd 
     FROM DUAL 
     CONNECT BY ROWNUM <= batchSize * 1.1 
    ) r 
    WHERE ROWNUM <= batchSize 
    AND NOT EXISTS (SELECT 'X' 
         FROM randomValues e 
         WHERE e.rnd = r.rnd); 
    END LOOP; 
END; 
/

这将在100 - 140秒之间插入1,000,000行。

您可以删除循环和代码简化为:

INSERT INTO randomValues 
SELECT rnd 
FROM (
    SELECT DISTINCT 
     FLOOR(
      DBMS_RANDOM.VALUE(
      POWER(10, 10), 
      POWER(10, 11) 
      ) 
     ) AS rnd 
    FROM DUAL 
    CONNECT BY ROWNUM <= :numRows * 1.1 
) r 
WHERE ROWNUM <= :numRows 
AND NOT EXISTS (SELECT 'X' 
        FROM randomValues e 
        WHERE e.rnd = r.rnd); 

然而,测试的少数我已经做了,这是服用约200秒插入1,000,000行。

+0

非常感谢您的建议。我们将尝试这些,并让您知道结果(对不起,因为我们现在受到洪水的影响而延迟回应,并且仍然限制访问互联网) –

+0

通过进行以下更改,我们设法将处理时间缩短到约4小时。 通过ThreadLocalRandom.current()。nextLong(lowerRangeValue,higherRangeValue)生成随机数并引入并行处理。 (对不起,我们还没有试过建议的DBMS_RANDOM.VALUE(低,高)) –