首页 > 解决方案 > 为什么 SQLite 使用 JDBC 这么慢?

问题描述

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

但我不知道有什么问题。情况是,我有一个 SQLite 数据库(来自 Android 平板电脑)和一个不太大的表(其中约 50.000 行)如果我在 Sqlite Manager 中运行“select * from table ”,则需要 0.11 秒,正确。

但是...如果我在 Java 程序(使用 SQLite JDBC)中执行此操作,则需要 20 分钟!!!不开玩笑。

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

因为这个命令:“SELECT sqlite_version()”在每种情况下都会在同一个 .db 文件上给出不同的结果:

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

有人有什么想法吗?我完全被它困住了。

编辑:好的,所以 JDBC 罐子来自这里: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 分钟。

标签: javasqlitejdbc

解决方案


您正在创建一个String50k 行,这意味着您正在创建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直接使用 a 而不是构建查询:

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 基准测试

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

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秒


推荐阅读