2015年7月6日月曜日

DBT-2 で MySQL と他のRDBMSの性能比較をしている人に騙されないように注意

一応、立場的には第三者に戻った(MySQL/InnoDBの性能追求が仕事ではない)ので、忘れられない暗い過去にも触れてみようと思います。

未だに騙されている人が多いみたいなので、MySQL/InnoDBの名誉のために書き残さなければなりません。何度でも言いますが、性能比較は自分の目的とする処理をちゃんと比較しないとだめです。そうでなくては、騙されて本当は悪い性能のものを掴まされることになります。

DBT-2と言う(TPC-Cをベースにした)ベンチマークがありますが、数多のRDBMS(商用/OSS双方)に対して独自にTPC-Cベンチマークを実装・チューニングして比較した経験のある私から見て、怪しい結果しか出ないので、長年、基本無視のスタンスを取っています。

が、3年前にあろうことかMySQLの性能QAがDBT-2(nonsp:mysql)を利用していて、とある性能FIXに対して問題を指摘してきたのを契機にDBT-2のバグ(MySQL版にだけマイナスに働く)を調べて性能QAのチェックを改めてもらったことがあります。

その情報は、DBT-2の開発側にもフィードバックされたと記憶していますが、3年経った今もバグはそのままです。故意か過失かは不明ですが、DBT-2をMySQLを貶めるために嬉々として利用してきた人には悪意を感じてきました。

TPC-Cの仕様から見て間違っている箇所も何箇所かあるのですが、全RDBMSに共通な間違いはとりあえず触れません。

最も大きい問題の箇所は nonspでの、DELIVERY_1 クエリのあたりです。

DBT-2のnonspでは、
  • dbt2_sql_execute()でクエリを発行
  • dbt2_sql_fetchrow()で各行を取得
  • dbt2_sql_close_cursor()で終了
となっています。

deliveryトランザクションの最初のクエリは、
"SELECT no_o_id FROM new_order WHERE no_w_id = %d AND no_d_id = %d"
ですが、最初の最小の no_o_id しか必要じゃないのでdbt2_sql_fetchrow()が決め打ちで一回呼ばれて終了です。

さて、(方式の相性の)問題はMySQL版のdbt2_sql_execute()の実装がmysql_store_result()を含むことです。なので、件のクエリはMySQL版だけ全件取得されます。全体のスループットが高ければ高いほどその件数は増えるので、MySQL版だけスケールしない結果となります。(性能が上がるほど、見た目のスループットは下がることがある)

考えられる修正としては2通りあります。

1. SQLを明示的に結果を1行にする。

"SELECT COALESCE(MIN(no_o_id),0) FROM new_order WHERE no_w_id = %d AND no_d_id = %d"
※経験上COALESCE()とMIN()が使えなかったRDBMSは無いのでこれで問題はない。

2. mysql_store_result() をやめる。

しかしDBT-2としてはどちらも直す気は無いようです。

そもそも、MySQLをちゃんとチューニングできる人なら、件のSQLが重いことに気づきTPC-Cの仕様を確認して直すはずです。

なので、DBT-2はMySQLの性能チューニングに無知な人が作ったもである、もしくは故意にMySQLの性能を低く見せる意図があると言えると思います。

このような陰険な工作は、逆に味方も騙され油断し、進歩が止まってしまうのではないでしょうか?
私は、このような正々堂々と切磋琢磨しない人たちを
「過去の忘れられた歴史として葬るほど、MySQL/InnoDBの性能を進歩させればいい」
 それこそが正しい対抗策だと考えて前職・前前職で精進してきました。

しかし、今だにDBT-2でのRDBMS比較に触れる人がいると、当時名指しで現行犯で徹底批判しても良かったかなと思ったりします。(進歩のためにはそんな暇は無かったでしょうが。)

まぁ、とにかく一貫して言えるのは、「ベンチマークは自分でやるまで信じない」が安全なスタンスです。