「SQLite性能評価その3」の続きです。 今回はインメモリデータベースの性能を評価してみました。
測定環境は前回と同じです。
コードは、前回のCase2~Case5の
sqlite3_open("testdb.sq3", &Db);
を、
sqlite3_open(":memory:", &Db);
に置き換えるだけです。
それぞれCase2(Memory)~Case5(Memory)と呼ぶことにします。
測定結果は以下のようになりました。
データベースのopen、closeや、CREATE TABLEの時間は含めていません。
ファイルを使った前回の測定結果とも比べてみます。
Case4とCase5のsqlite3_bind_xxxを使ったデータ追加はインメモリデータベースでも効果が高いようです。
「SQLiteの性能評価その5」に続きます。
「SQLite性能評価その2」の続きです。 テーブルに100000件追加する処理だけでも、Case2の他にいろいろな書き方があるので、試してみました。
sqlite3_execの代わりにsqlite3_prepareとsqlite3_stepを使ってみました。これをCase3とします。
// Case3 struct sqlite3* Db; struct sqlite3_stmt* Statement; char Buffer[256]; sqlite3_open("testdb.sq3", &Db); sqlite3_prepare(Db, "CREATE TABLE test1(name TEXT,value INTEGER)", -1, &Statement, NULL); while (sqlite3_step(Statement) == SQLITE_BUSY); sqlite3_finalize(Statement); // 処理時間測定開始 sqlite3_prepare(Db, "BEGIN", -1, &Statement, NULL); while (sqlite3_step(Statement) == SQLITE_BUSY); sqlite3_finalize(Statement); for (int i = 0; i < 100000; ++i) { char* Sql = sqlite3_snprintf(sizeof(Buffer), Buffer, "INSERT INTO test1 VALUES('%q',%d)", StringList[i].c_str(), ValueList[i]); sqlite3_prepare(Db, Sql, -1, &Statement, NULL); while (sqlite3_step(Statement) == SQLITE_BUSY); sqlite3_finalize(Statement); } sqlite3_prepare(Db, "COMMIT", -1, &Statement, NULL); while (sqlite3_step(Statement) == SQLITE_BUSY); sqlite3_finalize(Statement); // 処理時間測定終了 sqlite3_close(Db);
「sqlite3_prepare の真価」で紹介されている方法を使ってみました。 これをCase4とします。
// Case4 struct sqlite3* Db; struct sqlite3_stmt* Statement; sqlite3_open("testdb.sq3", &Db); sqlite3_prepare(Db, "CREATE TABLE test1(name TEXT,value INTEGER)", -1, &Statement, NULL); while (sqlite3_step(Statement) == SQLITE_BUSY); sqlite3_finalize(Statement); // 処理時間測定開始 sqlite3_prepare(Db, "BEGIN", -1, &Statement, NULL); while (sqlite3_step(Statement) == SQLITE_BUSY); sqlite3_finalize(Statement); sqlite3_prepare(Db, "INSERT INTO test1 VALUES(?,?)", -1, &Statement, NULL); for (int i = 0; i < 100000; ++i) { sqlite3_reset(Statement); sqlite3_bind_text(Statement, 1, StringList[i].c_str(), static_cast<int>(StringList[i].size()), SQLITE_TRANSIENT); sqlite3_bind_int(Statement, 2, ValueList[i]); while (sqlite3_step(Statement) == SQLITE_BUSY); } sqlite3_finalize(Statement); sqlite3_prepare(Db, "COMMIT", -1, &Statement, NULL); while (sqlite3_step(Statement) == SQLITE_BUSY); sqlite3_finalize(Statement); // 処理時間測定終了 sqlite3_close(Db);
Case4のsqlite3_prepareをsqlite3_prepare_v2に変えてみました。これをCase5とします。
// Case5 struct sqlite3* Db; struct sqlite3_stmt* Statement; sqlite3_open("testdb.sq3", &Db); sqlite3_prepare_v2(Db, "CREATE TABLE test1(name TEXT,value INTEGER)", -1, &Statement, NULL); while (sqlite3_step(Statement) == SQLITE_BUSY); sqlite3_finalize(Statement); // 処理時間測定開始 sqlite3_prepare_v2(Db, "BEGIN", -1, &Statement, NULL); while (sqlite3_step(Statement) == SQLITE_BUSY); sqlite3_finalize(Statement); sqlite3_prepare_v2(Db, "INSERT INTO test1 VALUES(?,?)", -1, &Statement, NULL); for (int i = 0; i < 100000; ++i) { sqlite3_reset(Statement); sqlite3_bind_text(Statement, 1, StringList[i].c_str(), static_cast<int>(StringList[i].size()), SQLITE_TRANSIENT); sqlite3_bind_int(Statement, 2, ValueList[i]); while (sqlite3_step(Statement) == SQLITE_BUSY); } sqlite3_finalize(Statement); sqlite3_prepare_v2(Db, "COMMIT", -1, &Statement, NULL); while (sqlite3_step(Statement) == SQLITE_BUSY); sqlite3_finalize(Statement); // 処理時間測定終了 sqlite3_close(Db);
測定結果は以下のようになりました。
分かったこと。
「SQLiteの性能評価その4」に続きます。
Windowsで(Pure)C++とWin32でGUIアプリを作るとき、GUIライブラリがあると楽です。
私は昔はGUIライブラリとしてMFCを使っていました。
しかし、MFCは、Visual C++の各バージョンに依存していて、Visual C++のバージョンを新しくするだけで問題が起こることもありました。これはちょっと勘弁して欲しかったので、もうちょっとポータビリティが高いWTLというライブラリを使うことにしました。
WTLの公式サイトによると、 2007/6/10にWTL 8.0がリリースされています。古くて枯れているというライブラリではありません。結構新しいです。
日本語化パックも配布されています。
日本語パックをインストールすると、アプリケーションウィザードと最初に生成されるリソースファイルなどが日本語化されます。
Visual C++ 2005 Expressでも使えるそうです。
Expressは、MFCが使えないので、GUIライブラリとしてはWTLが最有力候補でしょう。
しかし、WTLはドキュメントが少ないため、慣れるまではあまり楽ではありません。
私は「ATL/WTL」を一番参考にしていますが、
ここもリファレンスがあるわけではないので、細かい使い方は手探りです。
MFCと関数名が似ているので、MFCのマニュアルも結構参考になりますが、
どうしても分からないときは、WIN32API名を元にWTLのコードをgrep検索して見つけています。
こんな使い方になってしまうので、MFCやWIN32APIを多少知っていないと使いこなせないライブラリです。
使うときはそれなりの覚悟が必要です。
ちゃんとドキュメントが揃っていれば結構良いライブラリだと思うんですけどね。
「SQLite性能評価その1」の続きです。
SQLiteは、ファイル名を":memory:"とすると、インメモリデータベースを構築します。
このとき、前回のCase1とCase2の処理時間を測ってみました。
測定環境は前回と同じです。
コードは、前回のCase1とCase2の以下の部分を、
sqlite3_open("testdb.sq3", &Db);
以下のように置き換えるだけです。
sqlite3_open(":memory:", &Db);
それぞれCase1(Memory)、Case2(Memory)と呼ぶことにします。
測定結果は以下のようになりました。
データベースのopen、closeや、CREATE TABLEの時間は含めていません。
ほとんど差はありません。インメモリデータベースの場合は、トランザクション処理を明示的に指定しなくても問題はないようです。
Case2だけ前回との違いも比べてみました。
25%減です。
ファイルアクセスがなくなったのに思ったより速くなりません。
というより、ファイルアクセスありでも速い、と言うべきなんでしょう。
「SQLiteの性能評価その3」に続きます。
SQLiteの性能を少し見てみたいと思い、
テーブルに100000件のデータを追加した時の処理時間を測ってみました。
テーブルには以下のように文字列と整数の2列を用意しました。
CREATE TABLE test1(name TEXT,value INTEGER)
nameの方は、ランダムなアルファベットで構成される20文字の文字列で、valueの方も乱数としました。
測定環境は以下の通りです。
コンパイラ | Visual C++.NET 2003デフォルトコンパイラ |
OS | Windows XP Professional SP2 |
CPU | AMD Athlon 64 3700+ |
メモリ | 2GB |
HDD | Seagate ST3300622AS |
プロジェクト設定 | デフォルトRelease構成 |
SQLiteバージョン | 3.4.2 (not define THREADSAFE) |
SQLiteは、「SQLiteの使い方(Visual C++.NET 2003)」で 紹介した方法で静的ライブラリにして、アプリケーションからC Interfaceで呼び出すようにしました。
SQLiteは、大量のINSERTを実行する場合は、最初にトランザクションを明示的に開始しておかないとパフォーマンスがとても悪くなるというデータベースです。
(「生まれ変わるPHP - Zend Engine 2、SQLiteの実力は?」に参考情報があります)
まずこれを確認してみました。
トランザクションを開始しない方をCase1とします。 コードは以下のようになります。
// Case1 struct sqlite3* Db; char Buffer[256]; sqlite3_open("testdb.sq3", &Db); sqlite3_exec(Db, "CREATE TABLE test1(name TEXT,value INTEGER)", NULL, NULL, NULL); // 処理時間測定開始 for (int i = 0; i < 100000; ++i) { char* Sql = sqlite3_snprintf(sizeof(Buffer), Buffer, "INSERT INTO test1 VALUES('%q',%d)", StringList[i].c_str(), ValueList[i]); sqlite3_exec(Db, Sql, NULL, NULL, NULL); } // 処理時間測定終了 sqlite3_close(Db);
トランザクションを明示的に開始する方をCase2とします。 コードは以下のようになります。
// Case2 struct sqlite3* Db; char Buffer[256]; sqlite3_open("testdb.sq3", &Db); sqlite3_exec(Db, "CREATE TABLE test1(name TEXT,value INTEGER)", NULL, NULL, NULL); // 処理時間測定開始 sqlite3_exec(Db, "BEGIN", NULL, NULL, NULL); for (int i = 0; i < 100000; ++i) { char* Sql = sqlite3_snprintf(sizeof(Buffer), Buffer, "INSERT INTO test1 VALUES('%q',%d)", StringList[i].c_str(), ValueList[i]); sqlite3_exec(Db, Sql, NULL, NULL, NULL); } sqlite3_exec(Db, "COMMIT", NULL, NULL, NULL); // 処理時間測定終了 sqlite3_close(Db);
測定結果は以下のようになりました。
データベースのopen、closeや、CREATE TABLEの時間は含めていません。
Case2が見えなくなるくらい違いがあります。Case1の処理時間はCase2の約1500倍。ここまでとは・・・。
「SQLiteの性能評価その2」に続きます。
最近、SQLiteというデータベースライブラリの存在を知りました。
シンプルな機能なので扱いやすいデータベースです。中小規模のアプリケーション向けですね。
ライセンスもパブリックドメインなので言うことなし。
スタンドアロンなアプリケーション向けのデータベースとしては、たぶんこれが最有力候補でしょう。
C言語によるソースコードが提供されていますので、C/C++アプリケーションであれば、
アプリケーションに埋め込んで使うことができます。
本日は、アプリケーションに埋め込んで使うための静的ライブラリの作り方を紹介します。
必要なもの
手順
たくさん警告が出ますが、エラーが出なければたぶんOKです。
お手軽データベースライフをお楽しみください。