java - 为什么 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 文件上给出不同的结果:
- 在一个非常古老的 sqlite 管理器中,它给出了 3.6.19
- 在 Sqlite Studio 3.15 中
- 并与来自 sqlite.org 的最新 .exe 一起提供 3.23.1 所以它不是与数据库相关的东西,我认为它是使用的 sqlite3.exe 的版本。
我可以整天更改 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 分钟。
解决方案
您正在创建一个String
50k 行,这意味着您正在创建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秒
推荐阅读
- haskell - 如何给 GHC 一个构造 QuantifiedConstraints 的提示?
- javascript - 无法对未安装的组件执行 React 状态更新
- compiler-errors - D中逗号表达式的结果
- xamarin.forms - 图像未在列表视图中呈现
- c - 尝试初始化“员工”结构时收到警告消息
- angular - 如何根据单击的文本启用、禁用按钮?
- json - 在 Laravel Postgresql 中查询 Json 对象数组时无法获取数据
- reactjs - 有没有办法在一个 useEffect 挂钩中加载FromLocalStorage 和 saveToLocalStorage?
- xpath - 如何使用 XPATH 表达式比较格式为“Sun, 20 Jun 2010 10:45:05 GMT”的两个日期?
- python-3.x - 使用带有 Pandas DataFrame 的 while 循环来增加变量,直到满足特定条件