SQLite の INSERT は遅いのか?

MySQLとSQLite(PrinCo.)という記事経由で、生まれ変わるPHP - Zend Engine 2、SQLiteの実力は?(MYCOM PC WEB)という記事を読んだ。 MySQL と SQLite で INSERT 時の処理速度が公開されている。 1000件のレコードのINSERTを実行し、それぞれにどれぐらいの時間がかかっているかを示しているのだ。 MySQLが 0.4秒、SQLite が 16秒だというのだが、これはあまりにもひどすぎる。しかも、結論としてどうやら大量データの連続挿入はSQLiteの不得意な処理のようだ。と書かれている。1000件程度でこんなにかかるんだったら、10000件だったら160秒ぐらいかかる(単純すぎ。)って事? 実はこれにはからくりがあって、SQLite の処理は トランザクション の中でないと著しく遅いのだ。おそらく、これが原因なのではないかと思っている。 上記記事のベンチマーク結果を覆す事は出来ない(PHP5 と MySQL が、私の環境では使えていない)のだが、トランザクションを使った場合と、使わなかった場合の処理速度の違いを示す事は出来る。C言語で同じような処理を行うプログラムを作って、その処理時間を調べてみた。まずは、トランザクションを使った場合。
% /usr/bin/time -h ./instest 
        0.41s real              0.06s user              0.00s sys
すばらしい処理時間(0.4秒)だ。
次に使わなかった場合。
% /usr/bin/time -h ./instest 
        3m19.09s real           0.43s user              1.25s sys
私のプログラムがヘボイのか、記事の結果とあまりにも違いすぎる(3分ってどういう事?)のが気になる。しかし、ここでわかる事は SQLite での処理は、トランザクションが必要だろうという事だ。これは、SQLiteが、複数のプロセスからのアクセスがあっても データベースファイルが壊れないように、1件づつの処理で色々とやっているからだろう。以前調べた事だが、トランザクション中は、別のプロセスがファイルにアクセスしようとしてもロックされた状態になる。トランザクション中は書き放題なので速いのだろう。 最後に、今回の実験に利用したプログラムのソースコードを載せておく。

#include <stdio.h>
#include <sqlite.h>

#define INSERT_COUNT 1000

int main(int argc, char *argv[])
{
  sqlite *db;
  char *errmsg;
  int i;

  /* SQLite データベースを OPEN */
  db = sqlite_open("instest.db", 0755, &errmsg);
  if (!db) {
    printf("%s: %s\n", argv[0], errmsg);
    exit(-1);
  }

  /* BEGIN TRANSACTION */
#ifdef USE_TRANSACTION
  (void)sqlite_exec(db, "BEGIN", NULL, NULL, &errmsg);
#endif

  /* INSERT */
  for (i = 0; i < INSERT_COUNT; i++) {
    char *sql;

    sql = sqlite_mprintf("INSERT INTO test VALUES (%d)", i);
    (void)sqlite_exec(db, sql, NULL, NULL, &errmsg);
  }

  /* COMMIT TRANSACTION */
#ifdef USE_TRANSACTION
  (void)sqlite_exec(db, "COMMIT", NULL, NULL, &errmsg);
#endif

  sqlite_close(db);
}

Re: SQLite の INSERT は遅いのか?

トランザクション無しのSQLiteが遅いという話は探したら結構あるみたいですね。
しかし、トランザクションかけると随分と早いですね。型が無いとか、既存のRDBMSと異なる部分も多いみたいですが、その辺こなれてくると本当に便利そうですね、SQLite。

そしてその辺の使い方はPHPコミュニティが確立してくれることを勝手に期待。

Re: SQLite の INSERT は遅いのか?

型がないことのメリットっていまいち良くわかってなかったりするんですが。。。。。。
ライセンスや使いやすさを考えると、単体のアプリケーション作るには必需品になりそうですね。

Re: SQLite の INSERT は遅いのか?

記事に訂正文が追加されてますね。
やはりSQLiteの方がINSERT早いみたいです。

Re: SQLite の INSERT は遅いのか?

halt さん。情報ありがとうございます。
さっそく、訂正文を確認しました。たしかに MySQL よりも速いみたいですね。

SQLite の構造上、同時アクセスは不利ですが、ほとんどアクセスの無いサイトを作る場合とかには MySQL よりもこちらを使うほうが良いかもしれませんね。

Re: SQLite の INSERT は遅いのか?

こちらのエントリを参考にさせていただきました。おそらくcomitのたびにfsyncしまくっているのですが、ファイルシステム構成によってもかなり影響を受けるようです。

http://www.sqlite.org/speed.html のTest 1を再現してみるとこんな感じになります。
SUSE 9.1 ReiserFS: 35.390sec
SUSE 9.1 ReiserFS(trans): 0.241sec
Fedora Core 2 Ext3: 11.202sec
Fedora Core 2 Ext3(trans): 0.386sec

Re: SQLite の INSERT は遅いのか?

コメントありがとうございます。そして返事が遅くなり申し訳ございません。

なるほど、fsync ですね。データベースは内容を保証しなければなりませんから、毎回ファイルに書き込むと言う事なのでしょうね。

こちらこそ為になりました。

Re: SQLite の INSERT は遅いのか?

もしご存知でしたら教えてほしいのですが
SQLiteにMySQLのLOAD FILE のような一括インポートコマンドはあるでしょうか?
また早いでしょうか?
MySQLで大量データだとINSERTではなくLOAD FILEでTAB形式を取り込む場合が多いので。

Re: SQLite の INSERT は遅いのか?

matchori さん。返事が遅くなって申し訳ない。
一括インポートコマンドがあるかどうか、今はちょっとわかりません。時間が出来たら調べてみたいと思います。

もしお困りでしたら、どこかの(巨大)掲示板みたいなところで質問されたほうが良いかもしれません。ここはあんまりアクセスが無いので。

SQLiteをMovable Typeで使ってみる - Trackback

「Movable Typeのマイナー機能を使ってみる」シリーズ第二弾。第一弾は「Ogawa::Memoranda: mt-view.cgiを使ってみる。」。 あまり知られていないことですが、MT3.1の「テンプレートごとに管理可能なダイナミックPHPページ生成」機能はBerkeleyDBでは動作しません。3.1でこの機能を使いたい人はMySQLかPostgreSQLかSQLiteにとっとと移行する必要があります。 このうち、MySQL、PostgreSQLは三層Webアプリケーション構築においてはごくメジャー(かつ安価)なソリューションである一方、計算機に親しみ切れていない人々にとっては取っ付きの悪いのも事実です。そこで考えてみたいのは、やはりSQLiteっていうのは何なのかということです。 SQLite home page PHP5に標準でバンドルされるようになったのでご存知の方も多いと...

[mac]SQLite3をC言語で使う練習。 - Trackback

ちょうどよい記事を見つけてしまったので練習してみる。 元祖 サトシのブログ:「SQLite の INSERT は遅いのか?」 簡潔なテストコード。ちょっと拝借してSQLite3用に手直し。環境は、 iBook G4 Mac OSX 10.4.8 適当なフォルダに以下のファイルを作成。 instest.c #include

新しいコメントの投稿

このフィールドの内容は非公開にされ、公表されることはありません。
  • HTMLタグは使用できません
  • 行と段落は自動的に折り返されます。

書式オプションに関するより詳しい情報...

CAPTCHA
この質問はあなたが人間であるかどうかについて調べる為と、自動化したスパムを防ぐ為のものです。うまくいかない場合は電子メールでお問い合わせ下さい。
イメージ CAPTCHA
画像の中に見える文字を入力して下さい