勝手に前夜祭やったったー

年の瀬ですね。明日明後日からは12月ですね。12月と言えばAdvent Calendarですね!
今年も数多くの技術系Advent Calendarが立ち上がっています。
自分も来年こそはAdvent Calendarデビューしたいと思います。
12月からガラリと環境が変わるので余裕がない><

ということで、MySQL Casual Advent Calendar勝手に前夜祭とかやっちゃうよ!
公式はコチラ => MySQL Casual Advent Calendar
などと勢いで書き始めてみましたが、ベンチがまだとれてない(′・ω・`)
ぐ、ぐぬぬ。。。
正直、レコード数だったり、テーブル設計なんかも迷ってる状態だったりします。
と言い訳をしつつ、ベンチは追記させて頂きます。

実力がないなりに敷居を下げてみよう大作戦!
まぁ、こっちの方が何かカジュアルに書けるんじゃないか説()
という名目で書いてみようと思います。

みなさん、SQL書いてますか?ORMとか使ってたりしませんよね?
今回のお題ですが、以前に次のSQLでSLOW QUERYが出てしまったというお話です。

UPDATE tbl SET col = col + ? [COND]

初めて真っ当にRDBMSを触ったのがOracleだったんですが、かなり使ってたSQL
加算するだけだよね?ちなみにSLOW QUERY吐いた環境はPerlRedhat系です。

SLOW QUERYの内容を見るとプレースホルダが文字列に!
ここであー、アレだな!と思い出した記事がありました。
@kazuhoさんのサイボウズラボ時代に書かれていた記事です。
MySQL の高速化プチBK

とはいえ、環境的にDBIをそのまま使う習慣がなく、某ORMを使う他もなく
3点のベンチをとってみることにしました(※後述、下記のベンチにバグがあった)

  1. SQL_INTEGERを付けない
  2. SQL_INTEGERを付ける
  3. 加算せずにプレースホルダだけにする

結果は2は1よりも高速だったが、3は両者の30倍程度に高速(バグのせい)
という結果となりました。はて、どうしてこんなことになるのだろうか?
考えてみましたが、プレースホルダの置換/加算にMySQLが時間がかかっている?
そんな結果にちょっと納得もいかないまま月日が流れていました(1年以上。。。)

そして、今回こそはその原因を探るべく、再度、調査を行おう!
思いを胸に過去のベンチを見たわけですが、
ベンチをとったコードを見直してみてアレ?と思ってしまいました。

『加算せずにプレースホルダだけにする』
やはり、この条件に大きなミスがあったのです。
はわわ。。。SELECTしただけで、fetchせずに定数を突っ込んでいた><
ついったで相談させて頂いた@kitayama_tさん、@riywoさんに申し訳が><
とはいえ、MySQLに定数を突っ込むだけならそれだけ高速という意味でもある?

この辺がベンチを取り切れないというか、公開に慎重になった理由でもあります。
現在、とれているベンチでは以下の順で高速かな?

  1. 定数を突っ込む(SELECTなし == 評価外)
  2. SQL_INTEGERを付ける
  3. SQL_INTEGERを付けない
  4. SELECTしてプログラム側で加算した値をプレースホルダに突っ込む
正規表現で数値であることを担保した上で

の順となっています(仕事データなので外に出せない><)
ちなみにSQLite@同一マシン(Win機)ではそこまでの差は出ませんでした。
というよりもMySQLと比べてパフォーマンスが出なかったというところですね。

特にオチも根拠もない感じになってしまいましたが、
大抵のプロジェクトではサーバ台数と言う点で
AP > DB かと思います。
であれば、DBにかける負荷をAPで吸収するのは当然ですね。

コードを書く人間からすればSQL一発で出来るのが最適化でしょうが、
局所最適化に過ぎず、(機械も含めた)全体最適化でないとダメだなと実感しました。
インフラチームに余計な負荷かけるのもアレですしね!

こんな単純だと思っていたSQLでもSLOW QUERYを吐いてくれたことで
更新系の処理はできる限りシンプルに、不精せずにAPの数を活かす。
という教訓を得ることが出来ました。

ベンチにバグがあったおかげ?で思った以上にカジュアルな内容になりましたが、
勝手に前夜祭というタイトルとしてはちょうどよかったのかな?とも思います。
それでは皆様、よいAdvent Calendarライフを!

追記:
何だか、0時過ぎて書いたけど、11/29になってた。
(゚ー゚ ).。oO(誰か0日目とか書いてくれないかな)