Java中最高效的多线程数据库插入

时间:2017-05-04 20:07:16

标签: java database performance sqlite jdbc

我们必须将大量数据从HDD(~50GB)读入我们的数据库,但是由于org.sqlite.core.NativeDB.reset[native]内部的线程锁定,我们的多线程程序非常慢(约2小时~10GB)(见线程采样器。)

我们相对快速地读取数据并使用insert方法执行预准备语句。但是,只有我们收集了500.000个数据集,我们才将所有这些语句提交到我们的数据库。目前,我们使用JDBC作为sqlite数据库的接口。

如果你总共使用一个线程,到目前为止一切正常。但是如果你想使用多个线程,你不会看到很多性能/速度增加,因为只有一个线程可以在时间运行,而不是并行运行。 我们已经重用了preparedStatement,并且所有线程都使用Database类的一个实例来防止文件锁定(与数据库有一个连接)。

不幸的是,我们不知道如何进一步改进我们的插入方法。是否有人能够提供一些提示/解决方案或如何不使用此NativeDB.reset方法? 我们不必使用SQLite,但我们想使用Java。

ThreadMonitor(线程命名为1,2,...,15)

Thread Sampler

Resource Usage

private String INSERT = "INSERT INTO urls (url) VALUES (?);";

public void insert(String urlFromFile) {
  try {
    preparedStatement.setString(1, urlFromFile);
    preparedStatement.executeUpdate();
  } catch (SQLException e) {
    e.printStackTrace();
  }

}

根据@Andreas的建议更新了插入方法,但它仍然抛出了一些例外

public void insert(String urlFromFile) {
try {
  preparedStatement.setString(1, urlFromFile);
  preparedStatement.addBatch();
  ++callCounter;
  if (callCounter%500000 == 0 && callCounter>0){
    preparedStatement.executeBatch();
    commit();
    System.out.println("Exec");
  }
} catch (SQLException e) {
  e.printStackTrace();
}

}

java.lang.ArrayIndexOutOfBoundsException: 9
at org.sqlite.core.CorePreparedStatement.batch(CorePreparedStatement.java:121)
at org.sqlite.jdbc3.JDBC3PreparedStatement.setString(JDBC3PreparedStatement.java:421)
at UrlDatabase.insert(UrlDatabase.java:85)

2 个答案:

答案 0 :(得分:1)

大多数数据库都有某种批量插入功能,但它没有标准,AFAIK。

例如,Postrgresql具有COPY,而MySql具有LOAD DATA。 我不认为SQLite有这个功能 - 可能值得切换到一个数据库。

答案 1 :(得分:0)

SQLite has no write concurrency

加载大量数据的最快方法是使用单个线程(和单个事务)将所有内容插入到数据库中(而不是使用WAL)。