【发布时间】:2015-01-09 19:56:50
【问题描述】:
在一个过程中,在使用 Java 的服务器端,我必须创建一个 SQLite 数据库并导入大量数据(1.200.000 行分为 3 个表)并让用户下载生成的数据库。
我的第一种方法是在内存中创建 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 驱动程序。
【问题讨论】:
-
1.显示您的 Java 代码。 2. 显示您的 SQLite 架构。
-
谢谢,我已经更新了答案。
-
嗯...有时我不明白一些stackoverflow贡献者...为什么这个问题有反对票?我想知道改进它的原因。谢谢!
-
我不明白为什么这也有反对票
-
使用一个准备好的语句在每个表中插入一行。