是否在sqlite3中批量插入?

问题描述 投票:40回答:11

我有一个要加载到sqlite3数据库中的大约30000行数据的文件。是否有比为每行数据生成插入语句更快的方法?

数据以空格分隔,并直接映射到sqlite3表。是否存在用于将卷数据添加到数据库的任何批量插入方法?

没有人设计出某种非常不错的方法,如果它不是内置的吗?

我应该先问这个问题,是否有C ++的方法可以通过API做到这一点?

c++ sqlite insert bulk
11个回答
20
投票

您也可以尝试使用tweaking a few parameters以获得额外的速度。具体来说,您可能想要PRAGMA synchronous = OFF;


1
投票

我已经测试了答案中建议的一些pragmas

  • synchronous = OFF
  • journal_mode = WAL
  • journal_mode = OFF
  • locking_mode = EXCLUSIVE
  • synchronous = OFF +locking_mode = EXCLUSIVE+ journal_mode = OFF

这是我在一次交易中插入次数不同的数字:

增加批处理大小可以真正提高性能,同时关闭日志,同步,获得独占锁定将带来微不足道的收益。大约110k的点显示了随机后台负载如何影响数据库性能。

此外,值得一提的是,journal_mode=WAL是默认值的一个很好的选择。它可以带来一些好处,但不会降低可靠性。

C# Code.


0
投票

如果您只插入一次,我可能会给您带来一个肮脏的把戏。

这个想法很简单,首先插入内存数据库,然后备份,最后还原到原始数据库文件。

我在my blog处写了详细的步骤。 :)


57
投票
  • 将所有INSERT包装在一个事务中,即使只有一个用户,也要快得多。
  • 使用准备好的语句。

35
投票

您要使用.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 FROMhttp://www.postgresql.org/docs/8.1/static/sql-copy.html

在MySQL中为LOAD DATA LOCAL INFILEhttp://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之前,您应明确将分隔符设置为空格,制表符或逗号。


18
投票
  • 增加PRAGMA default_cache_size到更大的数量。这将增加缓存的页面数在内存中。

  • 将所有插入都包装到一个事务中,而不是每行一个事务。

  • 使用已编译的SQL语句进行插入。
  • 最后,如前所述,如果您不想完全遵守ACID,请设置PRAGMA synchronous = OFF;

10
投票

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
投票

无法批量插入,但是有写大块的方法记忆,然后将它们提交给数据库。对于C / C ++ API,只需执行:

sqlite3_exec(db,“ BEGIN TRANSACTION”,NULL,NULL,NULL);

...(INSERT语句)

sqlite3_exec(db,“ COMMIT TRANSACTION”,NULL,NULL,NULL);

假设db是您的数据库指针。


3
投票

一个不错的折衷方案是在BEGIN之间插入您的INSERTS;和END;关键字,即:

BEGIN;
INSERT INTO table VALUES ();
INSERT INTO table VALUES ();
...
END;

3
投票

取决于数据的大小和可用的RAM的数量,通过将sqlite设置为使用全内存数据库而不是写入磁盘,将会获得最佳性能提升之一。

对于内存数据库,将NULL作为文件名参数传递给sqlite3_openmake sure that TEMP_STORE is defined appropriately

(以上所有内容摘自我对separate sqlite-related question的回答)


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/

© www.soinside.com 2019 - 2024. All rights reserved.