最近のPostgreSQL, MySQL, SQLiteのパフォーマンスはどうかな?と言うことで非常に簡単なベンチマークをしてみました。
デフォルト状態のデータベースに郵便番号データ(12万件とちょっと)をINSERTしてみました。フラグを除く全てのフィールドをテキスト型として定義し、全てのフィールドを挿入しました。旧番号と現行番号にインデックスを付けています。スクリプトはPHPで記述し、DBが動作しているPC上からPHP 5.2.4で実行しました。1レコードが分割されている場合などは無視して挿入しているので12万2000レコードになりました。
PC
CPU: PentiumD 2.8GHz
Memory: 3GB
HDD: PATA
DBMS
MySQL: 5.0.45
PostgreSQL: 8.2.4
SQLite: 3.4.0 (PDO)
実行結果(12万行INSERTの実行時間)
InnoDb: 130.70663690567
MyISAM: 131.24672317505
Postgres: 159.47350597382
SQLite: 676.43534302711
MySQLもPostgreSQLもチューニングは一切無しで実行しています。
非同期クエリを利用するとPostgreSQLもInnoDb, MyISAMと同じくらいの速度になりました。
どのDBもペンチマーク中はディスク待ちの状態でCPU時間はあまり使っていませんでした。
MySQLとPostgresは概ね予想通りの結果でしたが、SQLiteが異常に遅いのでPDOを使わないで計測してみましたがあまり変わりませんでした。トランザクションかな?と思いBEGIN, COMMITを付けてみましたが変わりませんでした。
INSERTしたレコードをランダムにSELECTしてみました。番号はmt_rand関数で生成したのでほとんどがINDEXにヒットしないので、インデックスを利用した検索の最悪のケースのテストになります。単純にテーブルから検索をするだけです。永続的接続を利用しています。
Webサーバ:Apache 2.2.6
クライアント: ab -n 10000 -c 10 (別PCから実行。Athlon64 3500+/3GBメモリ)
パフォーマンス:リクエスト/秒
Postgres: 947.58
SQLite: 1096.00
MySQL(MyISAM): 1190.35
MySQL(InnoDb): 1245.85
概ね予想通りの結果ですが、SQLiteが思っていたより遅いです。PostgreSQLは接続のネゴシエーション処理が重いので非永続的接続を利用するとかなりパフォーマンスが落ちます。システム全体でDBへの接続数を上手に制御できていない場合はpgpoolを利用するとパフォーマンス(システム全体のスループット)が改善することがこの事からも分かります。
「Postgresでこんな数字でないよ」という方、pg_pconnectで試してみましょう。コネクションプーリングが無いと話になりません。