问题需求:要得到一千亿的随机数(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数据库了解不多 请坛子里的高手 帮帮忙 啊 我是没得救了 弄了好几天都没点思路
或者有其他方法能实现上面说的要求也行 的
现在考虑将一千亿的数先直接生成,然后用一个方法从里面去抽取,是有随机性。
我目前的实现是 采用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楼的方法,通过connect来执行千亿次即可。select trunc(dbms_random.value * 100000000000) from dual connect by level <=100000000000;
select trunc(dbms_random.value * 1000000) AS 随机数
from dual connect by level <=1000000;
恩 这个 不错
就是还是会有重复,得查重
本来是想在生成随机数的时候没有重复,也就是说每次从已经所生成的有序数中随机的抽取一个数 以保证每次所取得数是一个唯一的数
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所以这个方法 对我的需求还是有些小的问题 ,主要我是 将这些“随机数”用作条码 ,也就得是唯一,必须保证这个一千亿里的数是唯一,且是无序(所谓的无规律)
序列保证产生一个递增的不重复的整数两个值相加则产生一个 不重复的 随机数。
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
--这样子会出现,条码的位数,一直增加,不建议这样子操作,如果你为了实现条码的编码--可以用序列加lpad的函数!--eg:
SELECT lpad(1,15,'0') FROM dualSELECT lpad(test.nextval,15,'0') FROM dual
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;
本来我是想先将这一千亿数据进行分段处理,
利用mapreduce 进行分布式计算
对处理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));
}}
这个update的时候如何确定这个seq的呢?
还有 按照seq列进行排序 这个排序效率会怎么样?如果是每update一个seq就进行一次sort的话,那效率应该是蛮低,
我还没试,而且我对oracle数据库了解的不多
咱们先不考虑这个分布式分段计算,也不考虑存储空间(硬件条件现在有一个集群,我可以使用的硬盘空间在2T左右)
就考虑如何在可观的时间效率上将这一千亿个数进行乱序排
恩 现在的问题是一个段的计算算法都还没有搞定 您在21楼说的想法我还是没怎么看懂update table set seq = dbms_random.value
这个update的时候如何确定这个seq的呢?
还有 按照seq列进行排序 这个排序效率会怎么样?如果是每update一个seq就进行一次sort的话,那效率应该是蛮低,
我还没试,而且我对oracle数据库了解的不多
咱们先不考虑这个分布式分段计算,也不考虑存储空间(硬件条件现在有一个集群,我可以使用的硬盘空间在2T左右)
就考虑如何在可观的时间效率上将这一千亿个数进行乱序排
首先,update时这个seq列是通过dbms_random.value生成的随机数来赋值。然后通过seq列排序后的行号rownum就是我们要得到的乱序条码号。这样可以解决dbms_random.value重复的问题。至于效率么,我想在同等数据量的情况下,这个算法应当还是较快的。
恩 分段处理确实是很好的想法,我在实现的时候遇到一个这样的问题,比如我的表结构是:
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后,将不连续
当然我这想法是最笨的方法,就是每次都想抽取到一个数,抽取到后就从当前表中删除掉
至于12位,lpad和rpad 函数很容易将数据补全12位。