なんだかよくわからない先入観で遅いだろうと決め付けていたが、 http://www.sqlite.org/cvstrac/wiki?p=SpeedComparison によると、 transaction でまとめて実行するとずいぶん早い。
Test 1: 1000 INSERTs
CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100));
INSERT INTO t1 VALUES(1,13153,'thirteen thousand one hundred fifty three');
INSERT INTO t1 VALUES(2,75560,'seventy five thousand five hundred sixty');
... 995 lines omitted
INSERT INTO t1 VALUES(998,66289,'sixty six thousand two hundred eighty nine');
INSERT INTO t1 VALUES(999,24322,'twenty four thousand three hundred twenty two');
INSERT INTO t1 VALUES(1000,94142,'ninety four thousand one hundred forty two');
SQLite 3.3.3 (sync): 3.823
SQLite 3.3.3 (nosync): 1.668
SQLite 2.8.17 (sync): 4.245
SQLite 2.8.17 (nosync): 1.743
PostgreSQL 8.1.2: 4.922
MySQL 5.0.18 (sync): 2.647
MySQL 5.0.18 (nosync): 0.329
FirebirdSQL 1.5.2: 0.320
Test 2: 25000 INSERTs in a transaction
BEGIN;
CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100));
INSERT INTO t2 VALUES(1,298361,'two hundred ninety eight thousand three hundred sixty one');
... 24997 lines omitted
INSERT INTO t2 VALUES(24999,447847,'four hundred forty seven thousand eight hundred forty seven');
INSERT INTO t2 VALUES(25000,473330,'four hundred seventy three thousand three hundred thirty');
COMMIT;
SQLite 3.3.3 (sync): 0.764
SQLite 3.3.3 (nosync): 0.748
SQLite 2.8.17 (sync): 0.698
SQLite 2.8.17 (nosync): 0.663
PostgreSQL 8.1.2: 16.454
MySQL 5.0.18 (sync): 7.833
MySQL 5.0.18 (nosync): 7.038
FirebirdSQL 1.5.2: 4.280
transaction ごとに fsync() を実行するようなので、何度も fsync() を呼ばすに一度で済ませられるからだろうか。
Test 1 では IO 待ちが完全にネックになっている模様。
実際に試してみた結果
$ time ./a.out real 0m10.812s user 0m0.068s sys 0m2.164s $ time ./a.out transaction COMMIT real 0m0.169s user 0m0.044s sys 0m0.032s
確かに早くなってる
ソース
コンパイルは gcc -lsqlite3 sample.c
#include <stdio.h>
#include <sqlite3.h>
#define COUNT 1000
int main(int argc, char *argv[]) {
sqlite3 *db;
char *errmsg;
int rc, i;
rc = sqlite3_open("dat.sqlite3", &db);
if (rc) {
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
rc = sqlite3_exec(db, "create table if not exists sample(id)", NULL, 0, &errmsg);
if (argv[1] != NULL)
sqlite3_exec(db, "BEGIN", NULL, NULL, &errmsg);
for (i = 0; i < COUNT; i++) {
char statement[100];
sprintf(statement, "insert into sample values(%d)", i);
rc = sqlite3_exec(db, statement, NULL, 0, &errmsg);
}
if (argv[1] != NULL) {
sqlite3_exec(db, "COMMIT", NULL, NULL, &errmsg);
printf("COMMIT");
}
rc = sqlite3_exec(db, "drop table sample", NULL, 0, &errmsg);
sqlite3_close(db);
}
エラー処理はほとんどしてない。
突っ込み待ってます><