MySQLとDrizzleのベンチマーク

先日インストールしたDrizzleの簡単な性能評価をしてみました.
速度はもちろんですが,どれくらいMySQLと互換性があるか調べたかったのです.

Drizzle自体は,先日インストールした通りです.
DrizzleをFreeBSDにインストールしてみた - なぜか数学者にはワイン好きが多い

MySQLは,普通にMySQLのサイトからFreeBSD用のMySQL 5.1をダウンロードして,
MySQL :: Download MySQL Community Server
BINARY-INSTALLに従ってインストールしました.

まずDrizzleを立ち上げます.

# drizzled --datadir=/tmp/drizzle.data/ -u tetu-s --console-enable --port=3306
InnoDB: The InnoDB memory heap is disabled
InnoDB: Neither mutexes nor rw_locks use GCC atomic builtins.
InnoDB: highest supported file format is Barracuda.
InnoDB: The log sequence number in ibdata files does not match
InnoDB: the log sequence number in the ib_logfiles!
InnoDB: Database was not shut down normally!
InnoDB: Starting crash recovery.
InnoDB: Reading tablespace information from the .ibd files...
InnoDB: Restoring possible half-written data pages from the doublewrite
InnoDB: buffer...
InnoDB: Last MySQL binlog file position 0 0, file name UNUSED
InnoDB Plugin 1.0.4 started; log sequence number 5179208
Listening on 0.0.0.0:3306
Listening on 0.0.0.0:4427
drizzled: Forcing close of thread 0 user: ''
drizzled: ready for connections.
Version: '2009.12.1251' Source distribution (drizzle)

そして別なターミナルでDrizzleクライアントを立ち上げて,テストに使うデータベース「test」を作ります.

> drizzle
Welcome to the Drizzle client..  Commands end with ; or \g.
Your Drizzle connection id is 3
Server version: 2009.12.1251 Source distribution (drizzle)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

drizzle> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
+--------------------+
1 row in set (0 sec)

drizzle> CREATE DATABASE test;
Query OK, 1 row affected (0.46 sec)

drizzle>

コマンドはmysqlクライアントと同じです,ここまでは.


次にMySQLを立ち上げます.

# /usr/local/mysql/bin/mysqld_safe --user=mysql
mysqld_safe Logging to '/usr/local/mysql/data/localhost.err'.
mysqld_safe Starting mysqld daemon with databases from /usr/local/mysql/data

そして同様に,テスト用のデータベース「test」を作ります.

# /usr/local/mysql/bin/mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.1.41 MySQL Community Server (GPL)

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
+--------------------+
2 rows in set (0.00 sec)

mysql> CREATE DATABASE test;
Query OK, 1 row affected (0.04 sec)

サーバの準備が出来たので,プログラムを作ります.
以前と同様に,
C++によるMySQLの高速アクセス予備実験 - なぜか数学者にはワイン好きが多い
c++mysql++を使います.

DrizzleはMySQLプロトコルをサポートしているので,プログラムは改造無しで一つで大丈夫と信じて,OpenMPでスレッド対応にした以下のものだけを使います.

#include <omp.h>
#include <stdlib.h>
#include <mysql++.h>
using namespace std;
using namespace mysqlpp;
static const int MAX_ROW=20000; // DBにINSERTする行数
void Abort(string e)
{
  cout<<e<<endl;
  exit(1);
}

int database_reset(Connection &db_conn)
{
  Query query = db_conn.query();
  query<<"DROP TABLE IF EXISTS bench"; // テーブルがあったら消して作り直す
  if(query.execute()==false) Abort(query.error());
  query<<"CREATE TABLE bench (mykey INT NOT NULL, value VARCHAR(255) NOT NULL, PRIMARY KEY (mykey)) ENGINE = INNODB;";
  if(query.execute()==false) Abort(query.error());
  return(0);
}
int generate_data_table(vector<string> &table)
{
  for(int key=0;key<MAX_ROW;++key)
  {
    string val="val:";
    for(int j=0;j<rand()%200+1;++j) // 最大で200文字のデータと仮定
    {
      val+= (char)(48+rand()%10); // アスキーコードで0から9の数字の文字を作る
    }
    table.at(key)=val;
  }
  return(0);
}
int insert_data_table(vector<Connection> &db_conn, vector<string> &table)
{
#pragma omp parallel for  // OpenMP対応
  for(int key=0;key<MAX_ROW;++key)
  {
    ostringstream ost;
    Query query = db_conn.at(omp_get_thread_num()).query(); // 各スレッド用のコネクションを使う
    query<<"INSERT INTO bench (mykey, value) VALUES ("<<key<<",'"<<table.at(key)<<"')";
    ost<<"cannot insert test data("<<key<<","<<table.at(key)<<")";
    if(query.execute()==false) Abort(ost.str());
  }
  return(0);
}
int main()
{
  srand(0); // 同じ乱数を生成するために同じシードを使う
  vector<string> table(MAX_ROW);
  vector<Connection> conn(false);
  conn.resize(atoi(getenv("OMP_NUM_THREADS")));  // 同時スレッド数の数だけコネクションを準備
  for(int i=0;i<conn.size();++i)
  {
    if(conn[i].connect("test", "127.0.0.1", "nobody", "")!=true)
    {
      Abort("cannot connect db");
    }
  }
  database_reset(conn[0]); // テーブルの初期化は一回でいいので
  generate_data_table(table);
  insert_data_table(conn, table);
  return(0);
}

このプログラムのコンパイルは,FreeBSDではこんな感じです.

> c++ mysql-test.cc -fopenmp -I/usr/local/mysql/include -I/usr/local/include/mysql++/ -L/usr/local/mysql/lib -L/usr/local/lib -lmysqlpp

まずMySQLで実行してみます.

> setenv OMP_NUM_THREADS 1                                                      
> time ./a.out
0.504u 0.376s 0:17.12 5.0%      34+1189k 0+0io 0pf+0w
> setenv OMP_NUM_THREADS 10                                                      
> time ./a.out
0.624u 0.327s 0:08.29 11.3%     32+1136k 0+0io 0pf+0w

次,Drizzle行きます.

> setenv OMP_NUM_THREADS 1 
> time ./a.out
0.536u 0.345s 0:17.08 5.0%      26+928k 0+0io 0pf+0w
> setenv OMP_NUM_THREADS 10
> time ./a.out
0.560u 0.373s 0:07.27 12.7%     29+1031k 0+0io 0pf+0w

速度的には,ほぼ同じという結果が得られました.
どちらもスレッド数が1では約17秒,スレッド数が10では約7〜8秒でした.
特にDrizzleが高速だったということは無いですが,逆に言うと,Drizzleが既にMySQL相当の速度が出たと考えるべきでしょうか.
DBにinsertした内容は同一でした.
ただし,mysqldumpでDrizzleのダンプを取ろうとするとエラーが出てしまって,drizzledumpというプログラムを使って比べました.