解惑:
在公司的机器上跑了30万的数据,建了一个test_sg_student(主键为UUID)和 test_bigintAsString_t (主键为19位的bigint),分别用10个线程和批处理进行插入,发现性能相差接近100倍,很明显是UUID做主键的表插入时间是最慢的,根据底层索引B+树来思考,其实答案也油然生成,UUID的无序和空间占的大小导致插入时候要耗费更多的时间去创建和维护索引
test_bigintAsString_t表
test_sg_student表
用prepareStatement的batch处理,语句经过预编译,将每1000个记录为一个batch提交,计算时间性能相差100多倍
test_bigintAsString_t表的插入:
test_sg_student表的插入:
在mysql进行一次全部数据的扫描,也发现uuid做主键的表性能极差,一次查询竟然达到了12秒之巨,哪怕是为UUID建立前缀索引,也仅仅是快了1秒左右,而对插入更是没什么用处
下面是进行检测插入的java代码,使用的是druid连接池
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/*
这是对UUID做主键的表进行插入时间消耗检测,只是为了检测,代码不足之处可以提出来~
*/
public class test {
public DruidManager druidManager = DruidManager.getInstance();
public void test() {
Connection con = null;
PreparedStatement ps = null;
AtomicInteger errori = new AtomicInteger(0);
AtomicInteger successi = new AtomicInteger(0);
String sqllanguages = "insert into test_sg_student(id,name,age,loves,cardnum) values(?,?,?,?,?)";
//ResultSet rs = null;
try {
con = druidManager.getConnection();
con.setAutoCommit(false);
ps = con.prepareStatement(sqllanguages);
while(i.get() < 10) {
for (int id = 0; id < 1000; id++) {
ps.setString(1, UUIDUtil.generateOriginalUUID());
ps.setString(2, "student" + id);
ps.setInt(3, 20);
ps.setString(4, "test");
ps.setString(5, "cardum");
ps.addBatch();
}
long starttime = System.currentTimeMillis();
ps.executeBatch();
con.commit();
long endtime = System.currentTimeMillis();
System.out.println("========================================");
System.out.println(Thread.currentThread().getName()+"add 1000个记录第"+successi .incrementAndGet()+"次");
System.out.println("此次花费时间:" + (endtime-starttime)/1000 + "秒!!");
System.out.println("---------------------------------------");
}
}catch (Exception e){
e.printStackTrace();
System.out.println("failed"+errori.incrementAndGet());
}finally {
try{
ps.close();
con.close();
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"线程完成");
}
}
public static void main(String[] args) throws Exception{
long starttime = System.currentTimeMillis();
test t = new test();
ExecutorService exes = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
for (int threadNum = 0 ;threadNum<10;threadNum++){
exes.submit(new Runnable() {
@Override
public void run() {
t.test();
}
});
}
exes.shutdown();
exes.awaitTermination(1, TimeUnit.HOURS);
//t.test();//单线程跑和多线程跑表现的性能比较接近
long endtime = System.currentTimeMillis();
System.out.println("程序花费时间:" + (endtime-starttime)/1000 + "秒!!");
}
}
程序的单线程表现结果在上面几张图
结论:尽量使用自增的,占内存小的字段作为主键