在一个进程中,在使用Java的服务器端,我将创建一个SQLite数据库并导入大量数据(分为3个表中的1.200.000行)并让用户下载生成的数据库。
我的第一个方法是在内存中创建SQLite数据库,执行所有插入,最后将数据库保存到磁盘。它有效,但它真的很慢。最多需要42秒。
第一项改进是定义一项交易。如果我没有定义事务,SQLite会为每个插入创建一个,这很慢。对所有这些只进行一次交易,大约需要30秒。这对我们的情况来说还不够。
第三种方法是做同样的事情,但不是一个接一个地调用executeUpdate执行每个插入,而是创建一个包含所有插入的StringBuffer,并使用一次调用executeUpdate将它们全部发送到一起。这稍微快一点,但只有2或3秒。
当我虽然没有办法更快地完成它时,我意识到使用sqlite命令行工具,我可以执行“.import csv_file tablename”并且它更快地导入数据,所以我可以导出我的数据到CSV文件,然后使用该工具导入它们。但是,我更愿意不必从Java代码中调用任何命令行工具,但我没有找到任何方法使用JDBC驱动程序执行相同的导入。所以我的问题是:
您知道如何使用命令行工具从Java代码执行相同的CSV导入吗?
您是否有更好的方法来创建SQLite数据库并以有效的方式导入大量数据?
编辑:代码& SQLite架构:
我无法显示完整的架构定义,但有3个表创建如下:
CREATE VIRTUAL TABLE xxxxx USING rtree(...) with 5 attributes.
CREATE VIRTUAL TABLE xxxxx USING fts3 (...) with 1 attribute.
CREATE TABLE poidata(xxxxx) with 15 attributes.
表之间没有任何外键,除了PK之外没有任何索引。
关于代码,很简单。我在StringBuffer中生成所有插入,最后执行:
Statement st = this.getConnection().createStatement();
st.execute("begin transaction");
st.executeUpdate(sql.toString());
st.execute("end transaction");
st.executeUpdate("backup to " + destination.getAbsolutePath());
我目前正在使用Xerial SQLite JDBC驱动程序。
答案 0 :(得分:1)
经过一些优化后,现在生成数据库大约需要15秒。在所有的研究和测试之后,最重要的是:
对所有插入只使用一个事务,并且必须明确声明事务。如果未声明,则默认情况下会为每个插入创建一个新事务。
创建一个且只有一个PreparedStatement来执行所有插入并尽可能地重复使用它。