为什么SQLite在JDBC上这么慢?

时间:2018-05-11 12:28:14

标签: java sqlite jdbc

读了很多东西,比如这里: SQLite queries much slower using JDBC than in Firefox SqliteManager plugin

但我不知道问题是什么。 案例是,我有一个SQLite数据库(来自Android平板电脑)和一个不太大的表(约50.000行) 如果我运行"从表中选择* "例如在Sqlite Manager中它需要0.11秒,正确。

但是......如果我在Java程序(使用SQLite JDBC)中执行它需要20分钟!开个玩笑。

有人(某处)说这取决于版本。 但我的问题是如何?

因为这个命令:" SELECT sqlite_version()"在每种情况下,在同一个.db文件中给出不同的结果:

  • 在一个非常古老的sqlite管理器中,它给出了3.6.19
  • 在Sqlite Studio 3.15
  • 并使用sqlite.org中的最新.exe,它给出了3.23.1 所以它不是数据库相关的东西,我认为它是使用的sqlite3.exe的版本。

我可以整天更换JDBC驱动程序(我做了几次),但我怎么知道我需要哪个?

任何有想法的人?我完全坚持了它。

编辑: 好的,所以JDBC jar来自这里:https://bitbucket.org/xerial/sqlite-jdbc/downloads/

我的代码非常基本,起初我只想测量速度。

        Class.forName("org.sqlite.JDBC");
        Connection c1 = DriverManager.getConnection("jdbc:sqlite:" + "c:\\database.db");

        PreparedStatement stmt1 = c1.prepareStatement("select * from table1;");
        ResultSet rs = stmt1.executeQuery();
        String script = "insert into table1 values ";
        while (rs.next()) {
            script += "(";
            script += rs.getInt(1) + ", '" + rs.getString(2) + "', '" + rs.getString(3) + "'";
            script += "),";
        }
        stmt1.close();
        c1.close();

executeQuery()行需要20分钟。

1 个答案:

答案 0 :(得分:0)

您正在创建一个包含50k行的String,这意味着您正在创建 50k * 5 String(每个连接都会创建一个新的String实例。什么会杀死你的表现。

while (rs.next()) {
    script += "(";
    script += rs.getInt(1) + ", '" + rs.getString(2) + "', '" + rs.getString(3) + "'";
    script += "),";
}

我注意到您没有执行String script,因此如果您只想创建String,请使用StringBuilder

StringBuilder script = new StringBuilder("insert into table1 values ");
    while (rs.next()) {
        script.append("(")
              .append(rs.getInt(1)).append(", '")
              .append(rs.getString(2)).append("', '")
              .append(rs.getString(3)).append("'")
          .append("),");
    }

script.setLength(script.length() - 1); //to remove the last comma.

String query = script.toString();

StringBuilder阻止为无创建的大量String实例。

如果您想在此之后插入这些值,请直接使用PreparedStatement而不是构建查询:

PreparedStatement psInsert = c1.prepareStatement("insert into table1 values (?,?,?)");
while (rs.next()) {
    psInsert.setInt(1, rs.getInt(1));
    psInsert.setString(2, rs.getString(2));
    psInsert.setString(2,rs.getString(3));

    psInsert.execute();
}

然后,如果要改进这一点,请使用批处理系统发送小块插入。使用Statement.addBatch()Statement.executeBatch()

 while (rs.next()) {
    psInsert.setInt(1, rs.getInt(1));
    psInsert.setString(2, rs.getString(2));
    psInsert.setString(2,rs.getString(3));

    psInsert.addBatch();
    if(batchSize++ > 100){ //Execute every 100 rows
        psInsert.executeBatch();
        batchSize = 0;
    }
}

if(batchSize > 0){ //execute the remainings data
      psInsert.executeBatch();
}

StringBuilder Benchmark

不是官方的,只是简单执行的持续时间

LocalTime start = LocalTime.now();
StringBuilder sb = new StringBuilder("Foo;");
for(int i = 0; i < 50_000; i++){
    sb.append("Row").append(i).append(";\n");
}
System.out.println(Duration.between(start, LocalTime.now()).toNanos());
String s = sb.toString();
System.out.println(s.substring(0, 50));
  

这需要15纳秒

LocalTime start = LocalTime.now();
String s = "Foo;";
for(int i = 0; i < 50_000; i++){
    s += "Row" + i + ";\n";
}
System.out.println(Duration.between(start, LocalTime.now()).toMillis());
System.out.println(s.substring(0, 50));
  

这需要> 6秒