日期:2014-05-20  浏览次数:20829 次

大数据量解决方案测试
按理论来讲:如果一个表数据量太大的时候,查询速度会较慢;但如果把数据水平分割为多个表,采用多线程查询;最后将结果返回,速度应该提高很多。
带着这个问题,我今天专门做了个测试,但实际情况与我预料相差甚远,多线程竟然慢了一倍!

我的表里有720万数据,我查询语句如下:select * from usertable where username = 'mayanyun1000000';如果在一张表中只需4秒;如果分成多表查询,速度慢了一倍;

我使用一张表的时候代码如下:


public class TestSelectOneThread {

public static void main(String[] args) throws Exception{
long start = System.currentTimeMillis();
Connection con = ConnectionFactory.getConnection();
PreparedStatement ps = con.prepareStatement("select * from usertable where username = 'mayanyun1000000'");
ResultSet rs = ps.executeQuery();
while(rs.next()){
System.out.println(rs.getInt(1));
System.out.println(rs.getString(2));
System.out.println(rs.getString(3));
}
long end = System.currentTimeMillis();
System.out.println("共用时间:" + (end - start) + "微秒");
}
}

我把数据分为 7 个表;

代码如下:

public class TestSelectMoreThread {

public static void main(String[] args) throws Exception{

long start = System.currentTimeMillis();

Connection con = ConnectionFactory.getConnection();

List list = new ArrayList();

SelectThread[] threads = new SelectThread[7];

for(int i = 0 ; i < threads.length ;i++){
String sql = "select * from usertable"+(i+1)+" where username = 'mayanyun1000000'";
System.out.println(sql);
threads[i] = new SelectThread();
threads[i].setSql(sql);
threads[i].start();
}

while(true){
boolean b = false;
for(int i = 0 ; i < threads.length ;i++){
if(threads[i].status == 1){
b = true;
}else{
b = false;
break;
}
}

if(b){
break;
}
}

for(int i = 0 ; i < threads.length ; i ++){
list.addAll(threads[i].getResult());
}

System.out.println(list);
long end = System.currentTimeMillis();
System.out.println("共用时间:" + (end - start) + "微秒");
}


用到的线程类如下:public class SelectThread extends Thread{

public int status = 0 ; //1 为执行完毕,0为未执行完毕

private String sql;

private List<User> result = new ArrayList<User>();

public void run(){
try{
Connection con = ConnectionFactory.getConnection();

PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
while(rs.next()){
User user = new User();
user.setId(rs.getInt(1));
user.setUsername(rs.getString(2));
user.setPassword(rs.getString(3));

result.add(user);
}

status = 1;

}catch (Exception e) {
}
}



public List<User> getResult() {
return result;
}


public void setSql(String sql) {
this.sql = sql;
}
}

怪了,难道是我的代码有问题?还是这样分表查询性能就不如不分表?还请高人指教!

------解决方案--------------------
我没研究过大数据解决方案,但是看过几篇论文。我看别人处理这种问题多采用的是数据库集群。
我分析了一下,单线程的时候他就直接去挨着找就行了(当然里面有hash值,不可能直接找)。
多线程的时候,他还得按你的要求找到特定的位置再来找,这就麻烦了。
------解决方案--------------------
你要理解几个感念
1你这表的username 建了索引,如果username 重复的概率很小的话,只需要扫描很小部分的数据块,所以数据量再大速度也不慢,所以并不是数据量是10倍,查询时间就是10倍,数据量是1/10,查询时间就是1/10
2你没有采用绑定变量,所以数据库每次对你这个sql语句进行硬分析,也是要花时间的,你改成绑定变量试试,第二次以后如果条件一样,时间会少很多
3多线程要cpu是多核的才行,否则还是单线程,只是每个线程轮流执行
------解决方案--------------------
哎,你完全没有必要自己去写这些程序
oracle中提供了分区以及并行执行的功能
分区对于查询带来的性能提升主要是基于分区消除,即查询的时候不考虑一些分区,因为oracle是区间分区或者hash分区或者队列分区,索引每个区的数据都是可以预知的,因此在使用where从句时可以根据分区键进行分区消除(即查询时候不扫描一些分区)。