作为一种练习,我看到了将批量记录插入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
函数。我尝试了以下方法,看看它是否可以提高速度:
PRAGMA cache_size = 400000; PRAGMA synchronous = OFF; PRAGMA journal_mode = OFF;
...这些似乎没有比0.1s
差多得多的效果。
还有其他方法可以提高此处的插入速度吗?如果我们假设文件是“已解析”的,而不能直接从csv文件之类的文件中直接加载,那么理论上可以在1s内插入1M行吗?如果没有,这样做的局限性是什么?
感谢您使用当前的方法,插入一百万行将需要对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);