问题需求:要得到一千亿的随机数(0-100000000000),起初用得最笨的方法就是调用(java)随机函数,每生成一个random,就check一下。考虑到最后的效率,最终放弃了。
       现在考虑将一千亿的数先直接生成,然后用一个方法从里面去抽取,是有随机性。
         我目前的实现是  采用java+oracl数据库
     由于我电脑的存储空间有限,测试的时候暂时只考虑8位的情况,也就是千万  
     step1:先顺序生成0-10000000的有序数,存储在数据库中
     step2:每次产生一个随机数,通过这个随机数random去数据库中取数,取完后删除有序表的对应的这个数。
     step3:直到执行完
     我是利用oracle的rownum 来确定数据库表所对应的数
sq1 = "select * from (select id,rownum r from random where rownum <='"+k+"' )where r>'"+(k-1)+"' ";我所遇到的问题:
    Q1:速度很慢,也就是说我每次只可以取random表中靠前的数据,上面的sq1 语句执行速度勉强可以接受,一旦如果
       随机数 rand  = k  ,k = 999999 也就是当k 很大的时候 ,每执行一次会很慢 很慢 
    由于编程经验有限,对oracle数据库了解不多 请坛子里的高手 帮帮忙 啊  我是没得救了  弄了好几天都没点思路 
   或者有其他方法能实现上面说的要求也行 的  
 

解决方案 »

  1.   

    SELECT floor((dbms_random.value)*1000000000000000) FROM dual
      

  2.   

    不要用数据库的表记录来做这个操作,你的这个算法的运算是对千亿级的表执行千亿次的删除操作,肯定是慢得无法忍受。
    建议采用1楼的方法,通过connect来执行千亿次即可。select trunc(dbms_random.value * 100000000000) from dual connect by level <=100000000000;
      

  3.   

    实测成功:
    select trunc(dbms_random.value * 1000000) AS 随机数 
    from dual connect by level <=1000000;
      

  4.   

    select trunc(dbms_random.value * 100000000000) from dual connect by level <=100000000000;
        恩 这个 不错 
      就是还是会有重复,得查重
       
      本来是想在生成随机数的时候没有重复,也就是说每次从已经所生成的有序数中随机的抽取一个数 以保证每次所取得数是一个唯一的数  
      

  5.   


    create table random(id char(14) not null );
    insert into random  select trunc(dbms_random.value * 1000000) from dual connect by level <=1000000;
    SQL> select count(*) from random;  COUNT(*)
    ----------
       1000000SQL> commit;Commit complete.SQL> select count(distinct id) from random;COUNT(DISTINCTID)
    -----------------
               632209所以这个方法 对我的需求还是有些小的问题 ,主要我是 将这些“随机数”用作条码 ,也就得是唯一,必须保证这个一千亿里的数是唯一,且是无序(所谓的无规律)
      

  6.   

    dbms_random.value(0,1000000000) 产生1-10亿的随机数(这里把上限缩小了,因为还要加一个值)
    序列保证产生一个递增的不重复的整数两个值相加则产生一个 不重复的 随机数。
      

  7.   

    CREATE SEQUENCE test
    INCREMENT BY 1
    START WITH 0
    MAXVALUE 100000000000
    MINVALUE 0select to_char(test.nextval)||to_char( trunc(to_number(rpad('1',((dbms_random.value*12)-length(test.currval)),'0'))*dbms_random.value,0)) from dual
      

  8.   

    select to_char(test.nextval)||to_char( trunc(to_number(rpad('1',((dbms_random.value*12)-length(test.currval)),'0'))*dbms_random.value,0)) from dual
    --这样子会出现,条码的位数,一直增加,不建议这样子操作,如果你为了实现条码的编码--可以用序列加lpad的函数!--eg:
    SELECT lpad(1,15,'0') FROM dualSELECT lpad(test.nextval,15,'0') FROM dual
      

  9.   

    按楼主的需求进行分析,是1000亿个的数字的乱序排列。在这里计算下1000亿个数字所需要的内存空间:由于要保存的数字最大值是1000亿,所以每个数字至少要占用5个字节,如果采用标准数据类型,应当是8个字节。实际上占用的内容大小为:5000亿字节=465GB或者8000亿字节 = 745GB。这样大容量的数据放置在内容中进行计算是不现实的,这样大的数据量想要在很短的时间内处理完,也是不现实的。在这里提供一个不效率的算法:
    1. 在表中增加两列:
       seq number与barcode number
    2. 使用随机数更新seq列:
       update table set seq = dbms_random.value;
    3. 按照seq列进行排序,然后使用行号更新barcode列:
       update (select a.*,rownum rn from table a)
       set barcode = rn;
      

  10.   

    恩 您分析的很对 
        
          本来我是想先将这一千亿数据进行分段处理,
    利用mapreduce 进行分布式计算
      

  11.   

    这是我自己写的代码 ,写的比较的挫  
    对处理1百万数据的时候 就很慢 /*      
    drop table t_random purge;
    drop table random purge;
    drop sequence seq_t_r;
    drop sequence seq_r;create table random(id char(14) not null primary key,random char(14) not null);
    create  sequence seq_r  minvalue 1  nomaxvalue  start with 1  increment by 1  nocycle;  
    create trigger tri_r before insert on random for each row begin select seq_r.nextval into :new.id from dual; 
    end;
    /
    create table t_random(id number(14) not null primary key ,random char(14) not null,
    produceTime date,valid char(1))
    ; create sequence seq_t_r minvalue 1 nomaxvalue
     start with 1 increment by 1 nocycle
     ;create trigger tri_t_r before insert on t_random for each row
     begin select seq_t_r.nextval into :new.id from dual;
     end;
    /*/
    package com.hnu.myq.danbiao;import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;public class Random2 {
     private String driver = "oracle.jdbc.driver.OracleDriver";
     private String url = "jdbc:oracle:thin:@localhost:1521:orcl";


    private static String user = "random1";
    private static String password = "random1"; private  Connection conn = null;
    private static Statement stmt = null;
    private  static ResultSet rs = null; public Random2() {
    try {
    conn = getDBConnection();
    //conn.setAutoCommit(false);
    stmt = conn.createStatement();
    } catch (SQLException e) {
    e.printStackTrace();
    }
    }

    public  Connection getDBConnection() {
    try {
    Class.forName(driver);

    conn = DriverManager.getConnection(url, user, password);
    if (conn == null) {
    System.out.println("数据库连接出了问题!");
    return null;
    } else {
    //System.out.println("数据库连接成功!!");
    }
    } catch (Exception e) {
    }
    return conn;
    } /**
      * */
    public int queryAll() { // 查询数据库中表中总数
    int sum=0;
    String tableName = "random";
    String sq = "";

     sq  = "select count(*) from "+tableName+"";
     try {
    rs = stmt.executeQuery(sq);
    while(rs.next())
    {
     sum += rs.getInt(1);
    }
    } catch (SQLException e) {
    e.printStackTrace();
    }  
    return  sum;

    }
    public void TestRandom( ) {
    boolean firstWhileFlag = true;
    DateFormat formatDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 格式化时间
    long randomNumber = 0;
    String tableName ="random";
    int random ; 
        long k=1;
    long sum = queryAll();
    int r;
    if(0 == sum ){
    firstWhileFlag = false;
    System.out.println("数据库中没有数据了,程序正在退出....\n.............\n程序正常退出!!");
    }
        while(firstWhileFlag){
         random = (int)(Math.random()*10); 
         System.out.printf(" random:%5d",random);
         r = (int)(Math.random()*10);
        
    switch (random) {
    case 0:
    k = (random+r) % sum;
    break;
    case 1:
     k = (r +random*5) % sum;
    break;
    case 2:
    k = (random + r*3) % sum;
    break;
    case 3:
     k = (random +r*5) % sum;
    break;
    case 4:
    k = (random + r*4) % sum;
    break;
    case 5:
     k = (random +r*6) % sum;
    break;
    case 6:
    k = (random + r*7) % sum;
    break;
    case 7:
     k = (random + r*3) % sum;
    break;
    case 8:
    k = (random+r+3) % sum;
    break;
    case 9:
     k = (random+r*2) % sum;
    break;
      default:
    break;
          }
     String sq1="";
     String sq2 = "";
     String sq3="";
     System.out.printf("  k:%10d",k);
    if( 0 == k ){
    sq1 = "select * from "+tableName+" where rownum <=1 minus select * from "+tableName+" where rownum < =0";
    try {
         rs = stmt.executeQuery(sq1);
     if(rs.next())
     {
     randomNumber = rs.getInt("id");
       System.out.printf("    查到的数:%15d",randomNumber);
     }else {
    System.out.println("   ^^^当前没查到信息^^^"+"K值为:"+k+"  random为:"+random);
     }
     } catch (SQLException e) {
         e.printStackTrace();
     }
     sq2 = "insert into t_random values(0,'"+randomNumber+"'," +
       "to_date('"+formatDate.format(new Date())+"','yyyy-mm-ddhh24:mi:ss'),0) ";
      sq3  ="delete from "+tableName+" where id in (select id from "+tableName+" where rownum <=1" +
        " minus select id from random where rownum <=0 )";
        try {
     stmt.executeUpdate(sq2);
     stmt.executeUpdate(sq3);
     sum--;
     } catch (SQLException e) {
          e.printStackTrace();
     }  
         
    }else {
    //sq1 = "select * from "+tableName+" where rownum <='"+k+"' minus select * from "+tableName+" where rownum <= '"+(k-1)+"'";
    sq1 = "select * from (select id,rownum r from "+tableName+" where rownum <='"+k+"' )where r>'"+(k-1)+"' ";
    try {
         rs = stmt.executeQuery(sq1);
     if(rs.next())
     {
     randomNumber = rs.getInt("id");
         System.out.printf("    查到的数:%15d",randomNumber);
      sq2 = "insert into t_random values(0,'"+randomNumber+"',to_date('"+formatDate.format(new Date())+"','yyyy-mm-ddhh24:mi:ss'),0) ";
    //   sq3 ="delete from "+tableName+" where id in (select id from "+tableName+" where rownum <='"+k+"'" +
    //     " minus select id from "+tableName+" where rownum <='"+(k-1)+"' )";
      sq3 = "delete from "+tableName+" where id in (select id from (select id,rownum r from "+tableName+"  where rownum <='"+k+"')where r> '"+(k-1)+"' ) ";

      
      try {
         stmt.executeUpdate(sq2);
     stmt.executeUpdate(sq3);
     sum--;
     } catch (SQLException e) {
         e.printStackTrace();
     }  
       
     }else {
    System.out.println("^^^当前没从查到信息^^^"+"K值为:"+k+"  random为:"+random);
     }
     } catch (SQLException e) {
         e.printStackTrace();
     }
     

    System.out.printf("     数据库还有数据sum:%6d",sum);
    System.out.println();
    if(sum <=0){
     firstWhileFlag = false;
     }
    if(!firstWhileFlag){
    System.out.println("程序运行完,正常退出!!");
    }
    }
        
    }

    /**
     *@param randomSum 总共要产生的随机数,
     * */
    public void proRandom(long randomSum) {
    for(int i=0;i<randomSum;i++){
             String sq = "insert into random values(0,'"+(i)+"')";
             System.out.println("插入数据:"+i);
         try {
    stmt.execute(sq);
    } catch (SQLException e) {
    e.printStackTrace();
    }
          }
    }

    public static void main(String[] args) throws SQLException {
    Random2 pRandom = new Random2();
    double startTime2 = System.currentTimeMillis();
    //pRandom.proRandom(10000);
    pRandom.TestRandom();
    double endTime2 = System.currentTimeMillis();
    System.out.println("随机抽取数据时间:"+(endTime2 - startTime2));



    }}
      

  12.   

    恩 现在的问题是一个段的计算算法都还没有搞定  您在21楼说的想法我还是没怎么看懂update table set seq = dbms_random.value  
     这个update的时候如何确定这个seq的呢?
    还有  按照seq列进行排序  这个排序效率会怎么样?如果是每update一个seq就进行一次sort的话,那效率应该是蛮低,
        我还没试,而且我对oracle数据库了解的不多 
       咱们先不考虑这个分布式分段计算,也不考虑存储空间(硬件条件现在有一个集群,我可以使用的硬盘空间在2T左右) 
       就考虑如何在可观的时间效率上将这一千亿个数进行乱序排  
       
      

  13.   

    刚才回复错了 ,不知道是有bug还是 
    恩 现在的问题是一个段的计算算法都还没有搞定 您在21楼说的想法我还是没怎么看懂update table set seq = dbms_random.value   
     这个update的时候如何确定这个seq的呢?
    还有 按照seq列进行排序 这个排序效率会怎么样?如果是每update一个seq就进行一次sort的话,那效率应该是蛮低,
      我还没试,而且我对oracle数据库了解的不多  
      咱们先不考虑这个分布式分段计算,也不考虑存储空间(硬件条件现在有一个集群,我可以使用的硬盘空间在2T左右)  
      就考虑如何在可观的时间效率上将这一千亿个数进行乱序排   
      

  14.   


    首先,update时这个seq列是通过dbms_random.value生成的随机数来赋值。然后通过seq列排序后的行号rownum就是我们要得到的乱序条码号。这样可以解决dbms_random.value重复的问题。至于效率么,我想在同等数据量的情况下,这个算法应当还是较快的。
      

  15.   

    谢谢啊  
      恩 分段处理确实是很好的想法,我在实现的时候遇到一个这样的问题,比如我的表结构是:
        
       create table random(id char(14) not null primary key,random char(14) not null);
    create sequence seq_r minvalue 1 nomaxvalue start with 1 increment by 1 nocycle;   
    create trigger tri_r before insert on random for each row begin select seq_r.nextval into :new.id from dual;  
        假设当前要访问的表的random1,所产生的随机数是100,也就是要访问random1表的第100行,问题是如果快速的确定第100行????
          删除主键id后,将不连续
         当然我这想法是最笨的方法,就是每次都想抽取到一个数,抽取到后就从当前表中删除掉
      

  16.   

    random.value 保证了数据是乱序的,序列保证了数据的不重复性。
    至于12位,lpad和rpad 函数很容易将数据补全12位。
      

  17.   

    递归..存在就继续调用  dbms_random.value
      

  18.   

    做条码,为何不用  DateTime.Now.ToString("yyyyMMddHHmmss")这样的随机数呢