mysqlドライバの改良と軽量o/rマッパーの紹介
DESCRIPTION
MySQL/Ruby は広く使われていますが、個人的にいくつか問題点を感じています。その問題点を改良し、ついでに機能を強化した補助的な拡張ライブラリを作成しましたので、それを紹介します。またCGIで使える軽量なO/Rマッパーを自作したので、そちらの紹介も行ないます。TRANSCRIPT
copyright(c) 2008 kuwata-lab.com all rights reserved.
MySQLドライバの改良と軽量O/Rマッパーの紹介
makoto kuwatahttp://www.kuwata-lab.com/
札幌Ruby会議01 LightningTalk
1
copyright(c) 2008 kuwata-lab.com all rights reserved.
MySQLドライバの改良第 1 部
2
copyright(c) 2008 kuwata-lab.com all rights reserved.
MySQL/Ruby について
‣ MySQL/Ruby • Ruby用のMySQLドライバ
• 作者: とみたまさひろ氏
• Rails をはじめ、世界中で使われている
• http://www.tmtm.org/mysql/ruby/
3
copyright(c) 2008 kuwata-lab.com all rights reserved.
問題点
‣ Mysql::Result#fetch() が文字列の配列• データ型を変換してくれない
‣ Mysql::Stmt#fetch() のデータ型変換が変• 3.14 が 3.14000010490417 に
• timestamp が Time でなく Mysql::Time に
4
copyright(c) 2008 kuwata-lab.com all rights reserved.
motto-mysql
‣ motto-mysql • MySQL/Ruby の問題点を解消し、機能を強化する補助ライブラリ
• http://motto-mysql.rubyforge.org/http://github.com/kwatch/motto-mysql
• インストール: $ which mysql_config /usr/local/mysql/bin/mysql_config $ sudo gem install motto-mysql
5
copyright(c) 2008 kuwata-lab.com all rights reserved.
問題点の解決
‣ Mysql::Result • #fetch_as_hash()/array()
• #fetch_all_as_hashes()/arrays()
‣ Mysql::Stmt • #fetch_as_hash()/array()
• #fetch_all_as_hashes()/arrays()
データ型を変換して fetch する
3.14 が 3.14 に、timestamp が Time に
6
copyright(c) 2008 kuwata-lab.com all rights reserved.
機能の強化
‣ MySQL::Result#fetch_as(klass)、MySQL::Result#fetch_all_as(klass) • klass のオブジェクトを生成し、そのインスタンス変数にデータを格納して返す
• Hash で fetch してからオブジェクトに詰め替えるというムダをなくす
7
copyright(c) 2008 kuwata-lab.com all rights reserved.
サンプルコードrequire 'mysql'require 'motto_mysql'conn = Mysql.connect('host', 'user', 'pass', 'db')sql = 'select * from users'result = conn.query(sql)p result.fetch_as(User) #=> User objectresult.fetch_all_as(User) do |user| p user #=> User objectend
8
copyright(c) 2008 kuwata-lab.com all rights reserved.
ベンチマーク
Result#fetch_all_as(klass)
Result#fetch_all_as_hashes()
Result#fetch_all_as_arrays()
Resutl#each_hash (変換+new)
Result#each_hash (変換あり)
Result#each_hash (変換なし)
Result#each (変換+new)
Result#each (変換あり)
Result#each (変換なし)
0 5 10 15 20
3.83
5.12
6.99
5.30
7.66
10.45
3.57
5.00
4.74
1.08
1.08
1.09
1.08
1.09
1.11
1.07
1.08
1.08
4.79
4.84
4.86
4.80
4.87
4.90
4.76
4.82
4.80
DB systime usertime
Hashでfetch + データ変換 + Object.new はコストが高い
全部をドライバで行えば, usertime が 1/2, 全体で 2/3に
(sec)
9
copyright(c) 2008 kuwata-lab.com all rights reserved.
続・ベンチマーク
Python2.5.2+MySQLdb(tuple)
Python2.5.2+MySQLdb(dict)
Java1.5+MySQL Connector5.1.5
Result#fetch_all_as(klass)
Resutl#each_hash (変換+new)
Result#each (変換+new)
0 5 10 15 20
6.99
10.45
4.74
6.28
9.05
5.97
1.09
1.11
1.08
0.80
1.28
1.27
4.86
4.90
4.80
5.34
4.87
4.81
DB systime usertime
(sec)
DBからのfetchに限定すれば、Javaは別に速くはない
10
copyright(c) 2008 kuwata-lab.com all rights reserved.
その他
‣ integer(1) は boolean と見なされ、true/false が返る
‣ '0000-00-00 00:00:00' が Time や Date に変換できない (ArgumentError)
‣ Ruby on Rails 対応は今後の課題
11
copyright(c) 2008 kuwata-lab.com all rights reserved.
軽量O/Rマッパーの紹介第 2 部
12
copyright(c) 2008 kuwata-lab.com all rights reserved.
Kwery
‣ Kwery … 軽量貧弱な O/R マッパー• 最重要目標: CGIで使えること
• Model class を定義してもしなくてもよい
• Join-less を推奨
• MySQL と motto-mysql をサポート
• http://github.com/kwatch/kwery/
13
copyright(c) 2008 kuwata-lab.com all rights reserved.
サンプルコード:モデル定義class User include Kwery::Model create_table('users') do |t| t.integer(:id) {|c| c.primary_key.serial } t.string(:name) {|c| c.not_null.unique } t.timestamp(:created_at) {|c| c.default(:current_timestamp) } endend # User.to_sql で SQL 文を生成
create table文をほぼ直訳したDSL
14
copyright(c) 2008 kuwata-lab.com all rights reserved.
サンプルコード:検索# Queryオブジェクトを生成conn = Mysql.connect('host', 'user', 'pass', 'db')q = Kwery::Query.new(conn)
# モデルクラスだとそのインスンタスが、# テーブル名だと Hash が返されるuser = q.get(User, :id, 7)
# where 句や order_by 句は method chain で指定users = q.get_all(User) {|c| c.where('age >', 20).order_by(:name) }
15
copyright(c) 2008 kuwata-lab.com all rights reserved.
サンプルコード: Join
users = q.get_all(User) #=> select * from usersq.bind_references_to(users, Group, 'team_id', 'team') #=> select * from groups where id in (...)
‣ Join-less programming (注: 造語です)
• select * from users, groups where user.group_id = groups.id; のかわりにselect * from users; select * from groups where id in (...); を使う
• 1 + N を 2 で済ませる
16
copyright(c) 2008 kuwata-lab.com all rights reserved.
続きは Web で!http://www.github.com/kwatch/kwery/
17
copyright(c) 2008 kuwata-lab.com all rights reserved.
thank you
18