我有一个大约30000行数据的文件,我想将其加载到sqlite3数据库中。是否有比为每行数据生成插入语句更快的方法?
这些数据是以空格分隔的,并且直接映射到sqlite3表。是否有任何一种批量插入方法可以添加大量数据到数据库中?
如果没有内置功能,是否有人设计了一些巧妙的方式来完成此操作?
我应该先问一下,是否有从API中使用C++进行此操作的方法?
.import
命令。例如:$ cat demotab.txt
44 92
35 94
43 94
195 49
66 28
135 93
135 91
67 84
135 94
$ echo "create table mytable (col1 int, col2 int);" | sqlite3 foo.sqlite
$ echo ".import demotab.txt mytable" | sqlite3 foo.sqlite
$ sqlite3 foo.sqlite
-- Loading resources from /Users/ramanujan/.sqliterc
SQLite version 3.6.6.2
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select * from mytable;
col1 col2
44 92
35 94
43 94
195 49
66 28
135 93
135 91
67 84
135 94
echo
将其传递给交互式命令行解释器 sqlite3
。COPY FROM
:
http://www.postgresql.org/docs/8.1/static/sql-copy.html
在MySQL中,等效的命令是LOAD DATA LOCAL INFILE
:
http://dev.mysql.com/doc/refman/5.1/en/load-data.html
最后一件事:记得小心 .separator
的值。在进行大量插入时,这是非常常见的问题。sqlite> .show .separator
echo: off
explain: off
headers: on
mode: list
nullvalue: ""
output: stdout
separator: "\t"
width:
.import
之前,您应该明确设置分隔符为空格、制表符或逗号。我已经测试了一些在这里提出的 pragmas:
synchronous = OFF
journal_mode = WAL
journal_mode = OFF
locking_mode = EXCLUSIVE
synchronous = OFF
+ locking_mode = EXCLUSIVE
+ journal_mode = OFF
下面是不同事务中插入数量的结果数据:
增加批处理大小可以真正提升性能,而关闭日志、同步、获取独占锁将带来微不足道的收益。大约在 ~110k 附近的点显示了随机背景负载如何影响数据库性能。
另外值得一提的是,journal_mode=WAL
是一个很好的默认值替代方案。它确实提供了一些收益,但并不降低可靠性。
您也可以尝试微调一些参数以获得更快的速度。具体来说,您可能需要PRAGMA synchronous = OFF;
。
将 PRAGMA cache_size
增加至更大的数字。这将增加内存中缓存页面的数量。注意: cache_size
是每个连接的设置。
将所有插入操作都包装在单个事务中,而不是每行一个事务。
PRAGMA synchronous = OFF;
。cache_size
可以代替已弃用的 default_cache_size
。但是,cache_size
仅适用于单个连接。 - golmschenk回复:“是否有更快的方法来生成每行数据的插入语句?”
首先:通过利用Sqlite3的虚拟表API将其缩减为2个SQL语句,例如:
create virtual table vtYourDataset using yourModule;
-- Bulk insert
insert into yourTargetTable (x, y, z)
select x, y, z from vtYourDataset;
这里的想法是实现一个C接口,读取你的源数据集,并将其呈现为SQLite的虚拟表,然后一次性地从源表复制到目标表中。听起来比实际上要难,但我已经通过这种方式测量了巨大的速度提升。没有批量插入的方法,但是有一种方式可以将大块数据写入内存中,然后再提交到数据库。对于C/C++ API,只需执行以下操作:
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, NULL);
...(INSERT statements)
sqlite3_exec(db, "COMMIT TRANSACTION", NULL, NULL, NULL);
假设db是您的数据库指针。
BEGIN;
INSERT INTO table VALUES ();
INSERT INTO table VALUES ();
...
END;
INSERT INTO table VALUES (),(),();
。 - ZN13根据数据大小和可用的RAM量,将sqlite设置为使用全内存数据库而不是写入磁盘,可以获得最佳性能提升。
对于内存数据库,将文件名参数传递给sqlite3_open
时传递NULL,并确保适当定义TEMP_STORE。
(以上所有文本摘自我对一个与sqlite相关的问题的回答)
.echo ON
.read create_table_without_pk.sql
PRAGMA cache_size = 400000; PRAGMA synchronous = OFF; PRAGMA journal_mode = OFF; PRAGMA locking_mode = EXCLUSIVE; PRAGMA count_changes = OFF; PRAGMA temp_store = MEMORY; PRAGMA auto_vacuum = NONE;
.separator "\t" .import a_tab_seprated_table.txt mytable
BEGIN; .read add_indexes.sql COMMIT;
.exit
来源: http://erictheturtle.blogspot.be/2009/05/fastest-bulk-import-into-sqlite.html
一些额外信息:http://blog.quibb.org/2010/08/fast-bulk-inserts-into-sqlite/
这篇文章介绍了如何使用SQLite进行最快速的批量导入。通过使用SQLite的特定功能,例如跳过索引和触发器,以及事务控制,可以大大提高导入效率。另外,也可以使用其他方法,例如使用CSV文件和命令行工具等,来加速批量导入操作。