なら@はてなブログ

福岡で働くスマートフォンエンジニア(おっさん)のブログ。更新頻度がとにかく低いのが悩み。

SQLiteでINSERTが激しく遅い件

さて、表題そのまんまです。
で、残念ながら高度なチューニングなんかの話ではなく、おそらく基本的な話です。けど、知らないとハマるかも。


とあるAndroidアプリの開発で、テーブルに20万件ほどのレコードを登録しないといけなくなりました。
で、Androidアプリで使うDBはSQLiteなので、SQLiteでテーブルつくってINSERTをループさせる方法で実装。


くっそ遅い!!


INSERT終わるまで1時間以上かかるんですわ。


で、ちょっとググってみたところ、SQLiteのINSERTメソッド、内部でトランザクション管理してるみたいです。
なので、以下のようにやっちゃうと20万回トランザクションを開始→コミットってやってて、そのコストが激しくバカにならない。

SQLiteDatabase dbh;    // 適当にインスタンスを生成しておく

for (int i = 0 ; i < 200000 ; i++) {
    // 適当にINSERT
    dbh.insert(table, nullColumnHack, values);
}


まあ、ここまで書いた時点で解決策は出てますが、トランザクション管理を明示的にやります。

SQLiteDatabase dbh;

// トランザクション開始
dbh.beginTransaction();
for (int i = 0 ; i < 200000 ; i++) {
    // 適当にINSERT
    dbh.insert(table, nullColumnHack, values);
}
// コミットしてトランザクション終了
dbh.setTransactionSuccessful();
dbh.endTransaction();

件数が多いと、めっさ速くなります。
というか、そもそもが遅すぎただけなんですが。


Oracleさんとかだと、大量のundoためた状態でコミットするとけっこうな時間を取られますが、SQLiteは上記の20万件程度ならコミットも一瞬です。
内部実装ってどうなってんだろ? SQLiteは普通にファイルに保存してるはずだから、トランザクションコミットするたびにファイル開いて書き込んでFlushしてるのかなー?