我有一个大约30000行数据的文件,我想加载到sqlite3数据库中。有没有比为每行数据生成插入语句更快的方法?
数据以空格分隔,并直接映射到sqlite3表。是否有任何类型的批量插入方法用于向数据库添加卷数据?
如果它没有内置,有没有人设计出一些非常好的方法呢?
我应该先问一下,是否有一种C ++方法可以从API中完成它?
答案 0 :(得分:55)
答案 1 :(得分:34)
您想使用.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
请注意,此批量加载命令不是SQL,而是SQLite的自定义功能。因此它有一个奇怪的语法,因为我们通过echo
将它传递给交互式命令行解释器sqlite3
。
在PostgreSQL中,等价物为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
之前,您应该将分隔符显式设置为空格,制表符或逗号。
答案 2 :(得分:19)
您还可以尝试tweaking a few parameters以获得额外的速度。具体来说,您可能需要PRAGMA synchronous = OFF;
。
答案 3 :(得分:18)
增加PRAGMA default_cache_size
更大的数字。这将
增加缓存的页数
在记忆中。
将所有插入包装到单个事务中,而不是每行一个事务。
PRAGMA synchronous = OFF;
。答案 4 :(得分:9)
RE:“有没有更快的方法为每行数据生成插入语句?”
首先:通过使用Sqlite3的Virtual table 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,然后您一次性从源到目标表执行SQL复制。这听起来比实际更难,我用这种方式测量了巨大的速度。
第二:利用此处提供的其他建议,即编译指示设置和使用交易。
第三:也许看看你是否可以取消目标表上的一些索引。这样,sqlite将为每个插入的行添加更少的索引
答案 5 :(得分:5)
无法批量插入,但是 有一种方法可以编写大块 记忆,然后将它们提交给 数据库。对于C / C ++ API,只需执行:
sqlite3_exec(db,“BEGIN TRANSACTION”, NULL,NULL,NULL);
...(INSERT语句)
sqlite3_exec(db,“COMMIT TRANSACTION”,NULL,NULL,NULL);
假设db是您的数据库指针。
答案 6 :(得分:3)
一个很好的妥协是将你的INSERTS包装在BEGIN之间;和结束;关键字即:
BEGIN;
INSERT INTO table VALUES ();
INSERT INTO table VALUES ();
...
END;
答案 7 :(得分:3)
我已经测试了答案中提出的一些pragmas:
synchronous = OFF
journal_mode = WAL
journal_mode = OFF
locking_mode = EXCLUSIVE
synchronous = OFF
+ locking_mode = EXCLUSIVE
+ journal_mode = OFF
这是我在一次交易中插入次数不同的数字:
增加批处理大小可以真正提高性能,同时关闭日志,同步,获得独占锁定将带来微不足道的收益。大约110k的点显示了随机后台负载如何影响数据库性能。
值得一提的是,journal_mode=WAL
是默认值的一个很好的选择。它可以带来一些好处,但不会降低可靠性。
答案 8 :(得分:2)
根据数据的大小和可用的RAM量,通过将sqlite设置为使用全内存数据库而不是写入磁盘,可以获得最佳性能提升之一。
对于内存数据库,将NULL作为文件名参数传递给sqlite3_open
和make sure that TEMP_STORE is defined appropriately
(以上所有文字均摘自我自己对separate sqlite-related question的答案)
答案 9 :(得分:1)
我发现这是一次性导入的良好组合。
.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/
答案 10 :(得分:0)
答案 11 :(得分:0)
我使用此方法进行批量插入:
colnames = ['col1', 'col2', 'col3']
nrcols = len(colnames)
qmarks = ",".join(["?" for i in range(nrcols)])
stmt = "INSERT INTO tablename VALUES(" + qmarks + ")"
vals = [[val11, val12, val13], [val21, val22, val23], ..., [valn1, valn2, valn3]]
conn.executemany(stmt, vals)
colnames must be in the order of the column names in the table
vals is a list of db rows
each row must have the same length, and
contain the values in the correct order
Note that we use executemany, not execute