なんだかよくわからない先入観で遅いだろうと決め付けていたが、 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

http://www.sqlite.org/cvstrac/wiki?p=SpeedComparison

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);
}

エラー処理はほとんどしてない。

突っ込み待ってます><