mysql插入数据为什么会变慢

  介绍

这篇文章将为大家详细讲解有关mysql插入数据为什么会变慢,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

mysql插入数据变慢的原因:1,由主码、外码,索引造成的插入效率降低;2,由于使用的循环不停执行这个方法来插入;3,未能及时释放查询结果。

《java教程》

,,,,最近的项目需要导入大量的数据,插入的过程中还需要边查询边插入。插入的数据量在100 w左右。一开始觉得100 w的数据量不大,于是就插啊插,吃了个饭,回来一看,在插入了50多w条数据后,每秒就只能插十条了. .觉得很奇怪,为啥越插越慢呢?,于是就开始分析插入的时间损耗,想到了如下的解决方案:(mysql使用的)

<强> 1。分析是否是由主码、外码,索引造成的插入效率降低

,,,,主码:由于主码是每张表必须有的,不能删除。而mysql会对主码自动建立一个索引,这个索引默认是Btree索引,因此每次插入数据要额外的对Btree进行一次插入。这个额外的插入时间复杂度约为log (n)。这个索引无法删除,因此无法优化。但是每次插入的时候,由于主码约束需要检查主码是否出现,这又需要log (n),能否减少这个开销呢?答案是肯定的。我们可以,这样数据库里会自动记录当前的自增值,保证不会插入重复的主码,也就避免了主码的重复性检查。

,,,,外码:由于我的项目的插入表中存在外码,因此每次插入时需要在另一张表检测外码存在性。这个约束是与业务逻辑相关的,不能随便删除。并且这个时间开销应当是与另一张表大小成正比的常数,不应当越插入越慢才对。所以排除。

,,,,索引:为了减少Btree插入的时间损耗,我们可以在,先将所有的数据插入。之后我们再向表里添加索引。该方法确实也降低了时间的开销。

经过以上的折腾,再进行测试,发现速度快了一点,但是到了50 w条后又开始慢了。看来问题的关键不在这里。于是继续查资料,又发现了个关键问题:

<强> 2。将单条插入改为批量插入(参考:点击打开链接)

,,,java中,由于的executeUpdate (sql)方法只是执行一条sql操作,就需要调用sql里的各种资源,如果使用的循环不停的执行这个方法来插入,无疑是开销很大的。因此,在mysql提供了一种解决方案:批量插入。也就是每次的一条sql不直接提交,而是先存在批任务集中,。在100 w的数据规模中,我将阈值设置为10000,即一次提交10000条sql。最后的结果挺好,插入的速度比之前快了20倍左右。批量插入代码如下:

公共静态孔隙insertRelease () {
  .getTime长=new开始日期()();
  字符串sql=安迦雝b_big_data(数、create_time、随机)值(?、SYSDATE ())“;;
  尝试{
  conn.setAutoCommit(假);
  PreparedStatement pst=conn.prepareStatement (sql);
  for (int i=1;我& lt;=100;我+ +){
  for (int k=1;k & lt;=10000;k + +) {
  pst。setLong (1 k *我);
  pst。setLong (2 k *我);
  pst.addBatch ();
  }
  pst.executeBatch ();
  conn.commit ();
  }
  pst.close ();
  conn.close ();
  }捕捉(SQLException e) {
  e.printStackTrace ();
  }
  .getTime长=new结束日期()();
  System.out.println(演员:“;+(结束-开始)/1000 +,ms");
  }

<强> 3。一条更新语句的值后面跟上多条的(?,?,?,?)

,,,,这个方法一开始我觉得和上面的差不多,但是在看了别人做的实验后,发现利用这个方法改进上面的批量插入,速度能快5倍。后来发现,mysql的导出sql文件中,那些插入语句也是这样写的,即更新table_name (a1, a2)值(xx, xx), (xx, xx), (xx, xx)…。也就是我们需要在后台自己进行一个字符串的拼接,注意由于字符串只是不停的往末尾插入,用StringBuffer能够更快的插入。下面是代码:

公共静态空隙插入(){//开时时间
  .getTime长=new开始日期()();//sql前缀
  字符串前缀=安迦雝b_big_data(数、create_time、随机)值“;
  尝试{//保存sql后缀
  StringBuffer后缀=new StringBuffer ();//设置事务为非自动提交
  conn.setAutoCommit(假);//声明圣=conn.createStatement ();//比起圣,pst会更好些
  PreparedStatement pst=conn.prepareStatement (“;”);//外层循环,总提交事务次数
  for (int i=1;我& lt;=100;我+ +){//第次提交步长
  for (int j=1;j & lt;=10000;j + +) {//构建sql后缀
  suffix.append (“(”;+ j *我+“,SYSDATE (),“+我* j
  * math . random () +“)“);
  }//构建完整的sql
  sql=前缀+后缀字符串。substring (0, suffix.length () - 1);//添加执行sql
  pst.addBatch (sql);//执行操作
  pst.executeBatch ();//提交事务
  conn.commit ();//清空上一次添加的数据
  后缀=new StringBuffer ();
  }//头等连接
  pst.close ();
  conn.close ();
  }捕捉(SQLException e) {
  e.printStackTrace ();
  }//结束时间
  .getTime长=new结束日期()();//耗时
  System.out.println(演员:“;+(结束-开始)/1000 +,ms");
  }

mysql插入数据为什么会变慢