SQLite中的大容量插入性能

问题描述 投票:0回答:1

作为一种练习,我看到了将批量记录插入SQLite的速度。数据集大约50MB,包含1M行。这是我目前拥有的:

sqlite3 *db;
int rc = sqlite3_open("MyDB.db", &db);
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, NULL);
char* sql_buffer = malloc(200 * sizeof(char));
for (int i=0; item=row[i]; i ++) {
    snprintf(sql_buffer, 200, "insert into myTable (id, format, size) VALUES (%d, '%s', %d)", item.id, item.format, item.size);
    rc = sqlite3_exec(db, sql_buffer, NULL, NULL, NULL);
}
sqlite3_exec(db, "COMMIT TRANSACTION", NULL, NULL, NULL);

进行上述1M插入,需要3.39s。大约90%的时间是SQLite插入,而10%的时间是snprintf函数。我尝试了以下方法,看看它是否可以提高速度:

  • 每10K,50K,100K之后而不是在结尾(1M)进行插入
  • 写到内存而不是文件。
  • 更改各种编译指示,例如:PRAGMA cache_size = 400000; PRAGMA synchronous = OFF; PRAGMA journal_mode = OFF; ...

这些似乎没有比0.1s差多得多的效果。

还有其他方法可以提高此处的插入速度吗?如果我们假设文件是​​“已解析”的,而不能直接从csv文件之类的文件中直接加载,那么理论上可以在1s内插入1M行吗?如果没有,这样做的局限性是什么?

c sqlite
1个回答
1
投票

感谢您使用当前的方法,插入一百万行将需要对SQLite执行一百万次单独的往返插入。相反,您可以尝试使用以下两种方法之一。对于最新版本的SQLite:

INSERT INTO myTable (id, format, size)
VALUES
    (%d, '%s', %d),
    (%d, '%s', %d),
    (%d, '%s', %d),
    ... (more rows)

对于早期版本的SQLite,您可以使用INSERT INTO ... SELECT构造:

INSERT INTO myTable (id, format, size)
SELECT %d, '%s', %d UNION ALL
SELECT %d, '%s', %d UNION ALL
... (more rows)

这里的基本思想是,您可以尝试使用所有数据对SQLite进行single插入调用,而不是一次插入一行。

不是C语言人,但是这是从C代码构建插入字符串的方法:

const int MAX_BUF = 1000;  // make this as large as is needed
char* sql_buffer = malloc(MAX_BUF * sizeof(char));
int length = 0;
length += snprintf(sql_buffer+length, MAX_BUF-length, "INSERT INTO myTable (id, format, size) VALUES");
for (int i=0; item=row[i]; i++) {
    length += snprintf(sql_buffer+length, MAX_BUF-length, " (%d, '%s', %d)", item.id, item.format, item.size);
}

rc = sqlite3_exec(db, sql_buffer, NULL, NULL, NULL);
© www.soinside.com 2019 - 2024. All rights reserved.