くりにっき

フルスタックキュアエンジニアです

mysql2-nested_hash_bindを作った

ISUCON合わせで作ったやつ第n弾です。*1

github.com

モチベーション

達人が教えるWebパフォーマンスチューニング 〜ISUCONから学ぶ高速化の実践:書籍案内|技術評論社(通称ISUCON本) を読んでた時に

SELECT
  `posts`.`id`,
  `posts`.`user_id`,
  `posts`.`body`,
  `users`.`account_name` AS `users.account_name`,
  `users`.`authority` AS `users.authority`,
  `users`.`del_flg` AS `users.del_flg`
FROM `posts`
INNER JOIN `users` ON `posts`.`user_id` = `users`.`id`

のようにカラム名ドットが含まれるSELECT文を https://github.com/jmoiron/sqlx に渡すと users の部分をいい感じにGoのstructに詰め替えてくれると書かれていたのですが、Rubyでも同じことをやりたくてモンキーパッチgemを作りました。

使い方

READMEが全てなんですが、 using Mysql2::NestedHashBind::QueryExtension を書いたスコープで Mysql2::Client#queryMysql2::Client#xquery にモンキーパッチを仕込みます。

require "mysql2-nested_hash_bind"

using Mysql2::NestedHashBind::QueryExtension

db = Mysql2::Client.new(
  host: ENV.fetch("MYSQL_HOST", "127.0.0.1"),
  port: ENV.fetch("MYSQL_PORT", "3306"),
  username: ENV.fetch("MYSQL_USERNAME"),
  database: ENV.fetch("MYSQL_DATABASE"),
  password: ENV.fetch("MYSQL_PASSWORD", ""),
  charset: "utf8mb4",
  database_timezone: :local,
  cast_booleans: true,
  symbolize_keys: true,
  reconnect: true,
)

rows = db.query(<<~SQL)
  SELECT
    `posts`.`id`,
    `posts`.`user_id`,
    `posts`.`body`,
    `users`.`account_name` AS `users.account_name`,
    `users`.`authority` AS `users.authority`,
    `users`.`del_flg` AS `users.del_flg`
  FROM `posts`
  INNER JOIN `users` ON `posts`.`user_id` = `users`.`id`
SQL

rows.first
#=> {:id=>1, :user_id=>445, :body=>"test", :users=>{:account_name=>"sue445", :authority=>false, :del_flg=>false}}

頑張りポイント

ISUCONで利用するということでパフォーマンスチューニングを頑張りました。

具体的には https://github.com/evanphx/benchmark-ipsベンチマークをとりつつ https://github.com/tmm1/stackprof でgemのボトルネックを調べてボトルネックになってた箇所を改善してます。

stackprofで見つかったボトルネックの1つに Symbol#to_s があったのでfreezeされたStringを返す Symbol#name を使おうとしたのですが、Symbol#name が使えるのがRuby 3.0以降だったのでこのgemもRuby 3.0以降でしか使えないようにしてます。

ベンチマークのコードとレポートは https://github.com/sue445/mysql2-nested_hash_bind/tree/main/benchmark に置いているのでどれくらいオーバーヘッドあるかはここを見てください。

*1:まだOSSにしてないものを含めたらこの手のツールを5〜6個作ってる気がするので何番目かなんて正直把握していない