SlideShare una empresa de Scribd logo
1 de 61
Descargar para leer sin conexión
O/R Mapper による
トラブルを未然に防ぐ
Makoto Kuwata <kwa@kuwata-lab.com>
http://www.kuwata-lab.com/
PostgreSQLカンファレンス 2014
ver 1.1.0
copyright © 2014 kuwata-lab.com all rights reserved
まえがき
現在、アプリケーション開発の現場では O/R Mapper (ORM) が普及しています。今後
も ORM を使った開発は、増えることはあっても減ることはないでしょう。
しかし ORM は、アプリケーション開発者にとっては便利でも、DB 管理者 (DBA) か
らみたらトラブルの種でもあります。それが特にパフォーマンスに関する問題であるこ
とが多いため、開発者と DBA が対立することも珍しくありません。
とはいえ、ORM による問題はすでに解決策が用意されている場合があります。本当の
問題は、すでに存在する解決策があまり知られていないことではないでしょうか。
そこで本発表では、ORM によってどのような問題が起こりやすいか、どう解決・予防
すればいいか、そして ORM とどう「折り合い」をつけるかを説明します。特に、よく
トラブルとなる「N+1 問題」については説明を多めにしています。
また本発表を通じて、開発者と DBA が「互いが互いを知らないままに批判しあう」と
いう状況を改善し、両者が協調できる「まだ見ぬ丘の向こう」を目指します。
copyright © 2014 kuwata-lab.com all rights reserved
まとめ
✓ ORMによるトラブルは (たいてい) 解決策がある
✓ 解決策を知れば嫌悪感は (許容半以内に) 抑えられる
✓ 我々のゴールは「プロジェクトやサービスの

成功」であることを思い出す (対立することではない)
発表の背景
copyright © 2014 kuwata-lab.com all rights reserved
背景:ORMによるトラブルが多発
✓ ORMが生成するSQLがクソ
いわゆる「ぐるぐる系SQL」
✓ SQLをろくに勉強しないアプリ開発者
そのくせOOPやデザインパターンを得意げに語る ;(
✓ 開発効率を上げるためのORMなのに話が違う!
ある面では効率が上がっても、別の問題を引き起こしている
copyright © 2014 kuwata-lab.com all rights reserved
どこかでみた風景
実はオブジェクト指向って
しっくりこないんです…
SQLの書けないやつなぞ
エンジニアとして三流!
今はORMもKVSもある!
SQLよりOOPのほうが重要!
Staticおじさんww
老害wwwww
OOP信者
自分の得意分野に入り浸って、それ以外の分野に飛び込めない人たちっているよね…
copyright © 2014 kuwata-lab.com all rights reserved
背景:DBAがORMを知らなすぎる
✓ ORMのことをろくに知らずに批判している人
が多すぎ
✓ 「SQLをろくに知らない開発者」

vs 「ORMをろくに知らないDBA」
✓ ORMを知らない→トラブルが解決できない→
「ORMなんかクソ!」
copyright © 2014 kuwata-lab.com all rights reserved
わかってない人によるORM批判その1
(ORMは) テーブルから全行をスキャンし、
クライアントアプリケーションへ
ネットワーク越しに転送する
“
”『nabokov7; rehash : O/Rマッパーはなぜ悪か』
http://nabokov.blog.jp/archives/1529263.html
ちゃんとDB側で絞りこんでから
転送してますよぉ!
copyright © 2014 kuwata-lab.com all rights reserved
わかってない人によるORM批判その2
たとえば、SQL を書くことでフィルタリ
ングを DB で実行していたのに、O/R を
使うことでフィルタリングは、そのプロ
グラミング言語がやることになります。
“
”
where句もhaving句も
DB側でやってますよぉ!
https://twitter.com/kazu_yamamoto/status/280872190805680129
copyright © 2014 kuwata-lab.com all rights reserved
なぜORMを嫌うのか?
✓ 理由:

ORMがトラブルを引き起こすから?
✓ 本当の理由:

ORMによるトラブルが解決できないから!
トラブルの解決方法を知れば
そこまで嫌うことはないはず
copyright © 2014 kuwata-lab.com all rights reserved
理想と現実の間には、妥協点が存在する
・アプリ開発者がSQLを勉強してくれる
・ORMの吐くSQLにDBAが反吐を吐く
・ORMによるトラブルの芽を早期に潰す
【理想】
【現実】
copyright © 2014 kuwata-lab.com all rights reserved
本発表の目的は、DBAの皆さんに…
✓ ORMでよくあるトラブルとその予防策を知っ
てもらう
嫌悪感の本当の原因は、ORMがトラブルを起こすからではなく、
トラブルが解決できない (=解決策を知らない) から
✓ そのためにORMの仕組みを知ってもらう
解決方法を知らないのは、DBAがORMを知らなすぎるから
✓ 「O/R Mapperなんか使うな!」とは違う問
題解決方法があることを知ってもらう
「問題があるから禁止」は問題の解決になっていない
O/R Mapperの基礎知識
copyright © 2014 kuwata-lab.com all rights reserved
ORMの役目は、大きく3つ
• • •
SQL
RecordSet
SQLを組み立てて発行
スキーマを作成・変更
トラブルはここで発生
(今日はここのお話)
レコードセットを
オブジェクトに変換
Database Application
copyright © 2014 kuwata-lab.com all rights reserved
Prepared Statementじゃだめなの?
✓ 要件:実行時に検索条件を変えたい
✓ Prepared Statementではwhere句への追加
などが行えない
性別: 男性 女性
年齢: ∼ 歳歳
無指定
検索条件
copyright © 2014 kuwata-lab.com all rights reserved
SQLを動的に組み立てる:文字列結合
var cond = [], args = [];
if ( params.gender == "M"
|| params.gender == "F") {
cond.push("gender = ?");
args.push(params.gender);
}
if (params.max_age) {
cond.push("age <= ?");
args.push(params.max_age);
}
var sql = "select * from users";
if (cond.length) {
sql += " where " + cond.join(" and ");
}
sql += " order by name";
とても面倒なうえに、SQL Injectionを誘発しやすい
copyright © 2014 kuwata-lab.com all rights reserved
SQLを動的に組み立てる:ORM
SQLテンプレート方式
専用のテンプレートエンジンを
使って、SQLを生成する
select	 *	 from	 students

where

/**	 if	 (gender)	 {	 **/

gender	 =	 :gender

/**	 }	 **/

order	 by	 name
クエリオブジェクト方式
SQLを表現するデータを作成し、
それをSQL文字列に変換する
{	 table:	 "students",

	 	 where:	 [["gender=","F"]],

	 	 orderby:	 ["name"]	 }
select	 *	 from	 students

where	 gender	 =	 'F'

order	 by	 name
copyright © 2014 kuwata-lab.com all rights reserved
SQLテンプレート方式
select *
from students
/** if (gender || max_age) { **/
where true
/** if (gender) { **/
and gender = :gender
/** } **/
/** if (max_age) { **/
and age <= :max_age
/** } **/
/** } **/
order by name
文字列結合よりは読みやすい、SQL Injectionも誘発しない
この「true」はSQLのoptimizerが
除去してくれる (PostgreSQL)
copyright © 2014 kuwata-lab.com all rights reserved
SQLテンプレート方式
select *
from students
/** if (gender || max_age) { **/
where true
/** if (gender) { **/
and gender = :gender
/** } **/
/** if (max_age) { **/
and age <= :max_age
/** } **/
/** } **/
order by name
不要な "and" や "while" をORMが
自動的に取り除いてくれる
SQLを解釈できるORMなら、より簡潔に書けることも
copyright © 2014 kuwata-lab.com all rights reserved
SQLテンプレート方式
select st.* from students st
where
/** if (gender) { **/
st.gender = :gender
/** } **/
---------------------
select st.*, cl.* from students st
join classes cl on st.class_id = cl.id
where
/** if (gender) { **/
st.gender = :gender
/** } **/
それぞれで条件式が重複している
(DRYではない)
似たようなSQLを複数書く必要があり、DRYではない
所属クラスが
いらない場合のSQL
所属クラスが
必要な場合のSQL
copyright © 2014 kuwata-lab.com all rights reserved
クエリオブジェクト方式
var	 query	 =	 {table:	 "students",

	 	 	 	 	 	 	 	 	 	 	 	 	 where:	 [],	 orderBy:	 []};

//

if	 (params.gender)

	 	 	 query.where.push(["gender=",	 params.gender]);

if	 (params.max_age)

	 	 	 query.where.push(["age<=",	 params.max_age]);

query.orderBy.push("name");

//

var	 sql	 =	 generateSQL(query);
オブジェクトに各種条件を追加し、最後にSQLへ変換
where や order by を

データとして操作できる
copyright © 2014 kuwata-lab.com all rights reserved
クエリオブジェクト方式
var	 query	 =	 new	 Query(Student);

//

if	 (params.gender)

	 	 	 query.where("gender",	 params.gender);

if	 (params.max_age)

	 	 	 query.where("age<=",	 params.max_age);

query.orderBy("name");

//

var	 sql	 =	 query.generateSQL();
通常は専用のクエリクラスを使うので、簡潔に書ける
copyright © 2014 kuwata-lab.com all rights reserved
クエリオブジェクト方式
var	 query	 =	 new	 Query(Student);

//

if	 (params.gender)

	 	 	 query.where(Student.gender	 ==	 params.gender);

if	 (params.max_age)

	 	 	 query.where(Student.age	 <=	 params.age);

query.orderBy(Student.name);

//

var	 sql	 =	 query.generateSQL();
よくできた言語とよくできたORMなら「式」を指定可能
演算子オーバーライドや
AST変換を活用
copyright © 2014 kuwata-lab.com all rights reserved
クエリオブジェクト方式
==
x nil
x is nullx == nil 評価 変換
構文解析ではないことに注意!
("==" の評価結果がtrue/falseではなく構文木)
(ソースコード) (構文木) (SQL)
「x = null」ではなく
「x is null」になってくれる!
演算子オーバライドを利用した、構文木生成の仕組み
copyright © 2014 kuwata-lab.com all rights reserved
余談:LINQの実態はクエリオブジェクト
//	 SQLのようだが実はC#

from	 st	 in	 Student

where	 st.gender	 ==	 "F"

order	 by	 st.name

select	 st;

LINQ:変換前
//	 だいたいこんな感じ

From(Student)

.Where(x	 =>	 

	 	 	 	 	 	 	 x.gender	 ==	 "F")

.OrderBy(Student.name)

.ToArray();
LINQ:変換後
copyright © 2014 kuwata-lab.com all rights reserved
特徴:SQLテンプレート方式
✓ 仕組みがわかりやすい
ORMの学習コストが低い、トラブルに対処しやすい
✓ SQLが予想しやすい
つまりチューニングしやすい
✓ SQLの欠点はそのまま
DRYにする仕組みがない、'=' と 'is' の使い分けが必要、など
✓ SQL Injectionはほぼ発生しない
文字列結合をするコードを書かなくて済むため
copyright © 2014 kuwata-lab.com all rights reserved
特徴:クエリオブジェクト方式
✓ 仕組みが複雑
ORMの学習コストが高い、トラブル対応がしにくい
✓ どんなSQLになるかを確認する必要がある
予想外のSQLが生成されることも
✓ SQLではできないことができる
詳細は『なぜORMが必要か?』でggr
✓ SQL Injectionはほぼ発生しない
構文木(or 類似した構造)を作ってからSQLに変換するため
copyright © 2014 kuwata-lab.com all rights reserved
ORMのアーキテクチャは「PoEAA」を読め
Object-Relational Structural Patterns
• Identity Field
• Foreign Key Mapping
• Association Table Mapping
• Dependent Mapping
• EmbeddedValue
• Serialized LOB
• Single Table Inheritance
• Class Table Inheritance
• Concrete Table Inheritance
• Inheritance Mappers
Data Source Architectural Patterns
• Table Data Gateway
• Row Data Gateway
• Active Record
• Data Mapper
Object-Relational Behavioral Patterns
• Unit of Work
• Identity Map
• Lazy Load
Object-Relational Metadata Mapping
Patterns
• Metadata Mapping
• Query Object
• Repository
(注)PoEAA …『Pattern of Enterprise Application Architecture』(Martin Fowler, 2002)
ORMでよくあるトラブルと
その対策
copyright © 2014 kuwata-lab.com all rights reserved
ORMでよくあるトラブル
✓ N+1 問題
深刻度:極
✓ クエリ発行箇所が特定できない問題
深刻度:大
✓ インデックスつけ忘れ問題
深刻度:中
✓ select * 問題
深刻度:小
copyright © 2014 kuwata-lab.com all rights reserved
ORMでよくあるトラブル
✓ N+1 問題
深刻度:極
✓ クエリ発行箇所が特定できない問題
深刻度:大
✓ インデックスつけ忘れ問題
深刻度:中
✓ select * 問題
深刻度:小
copyright © 2014 kuwata-lab.com all rights reserved
「N+1 問題」 とは?
一覧を取得するSQLを発行してから、

各要素ごとに個別のSQLを発行してしまうこと
いわゆる「ぐるぐる系SQL」のこと。パフォーマンスが極端に落ちる
users	 =	 User.all()

for	 user	 in	 users

	 	 	 print	 user.group.name

end

select * from groups where id = :id をN回発行
select * from users を1回発行
(注)実態をより正確に表すなら「1+N問題」と呼ぶべき
(注)
copyright © 2014 kuwata-lab.com all rights reserved
ORM側の対策:eager loading
一覧を取得するときに、関連する要素もまとめて取
得するよう指定する
実装は、join だったり id in (…) だったり、まちまち
users	 =	 User.includes("group").all()

for	 user	 in	 users

	 	 	 print	 user.group.name

end

select文は発行されない
select * from users を1回発行してから、
select * from groups where id in (…) を
1回発行する
(参考)『3 ways to do eager loading (preloading) in Rails 3 & 4 』
http://blog.arkency.com/2013/12/rails4-preloading/
copyright © 2014 kuwata-lab.com all rights reserved
ORM側の対策:strategic eager loading
オブジェクトの関連が必要になったら、親となるコ
ンテナに通知し、コンテナがまとめて取得する
子であるオブジェクトが個別に取得するのを止める
users	 =	 User.includes("group").all()

for	 user	 in	 users

	 	 	 print	 user.group.name

end

groups テーブルへのアクセスが必要になると、
親となるコンテナである users へ通知され、
users がまとめて groups テーブルにアクセスする
明示的な指定が必要ない
(参考)『Why DataMapper? (Section: Strategic Eager Loading)
http://datamapper.org/why.html
copyright © 2014 kuwata-lab.com all rights reserved
ORM側の対策:bytecode manipulation
bytecodeを解析してeager loadingが必要な箇所
を判定し、それを行うコードを自動的に埋め込む
bytecode操作のかわりにAST変換やpreprocessorでもよい
List<User>	 users	 =	 query(User).all();

for	 (User	 user:	 users)	 {

	 	 System.out.print(user.group.name);

}
ループの中で関連を取得している
ことを検出し、ループ前にまとめ
て取得するようbytecodeを変更
(参考)『スケーラブルラピッドプロトタイピングのためのJIT-ORM 』
http://www.ipa.go.jp/files/000007122.pdf
copyright © 2014 kuwata-lab.com all rights reserved
insert文における「N+1 問題」
1件ずつinsert文を発行するのをやめて、

bulk insert機能を使って一括作成する
もちろん、大量すぎる場合は copy 文
//	 Bad:1件ずつinsert

for	 s	 in	 names

	 	 u	 =	 User.new(name:	 s)

	 	 u.save()

end
//	 Good:まとめてinsert

users	 =	 names.map	 {|s|

	 	 User.new(name:	 s)

}

User.import(users)
copyright © 2014 kuwata-lab.com all rights reserved
update文における「N+1 問題」
1件ずつupdate文を発行するのをやめて、

条件で指定した集合をまとめて更新する
jQueryにおける $("..条件..").attr(key, value) と同じ
//	 Bad:1件ずつの更新

users	 =	 

	 	 	 db.query(User).all()

for	 u	 in	 users:

	 	 	 u.value	 =	 u.value+1

db.commit()
//	 Good:まとめて更新

db.query(User)	 

	 	 .update({

	 	 	 	 	 "value":	 User.value+1

	 	 	 })

db.commit()
これは「値」(数値) これは「式」(構文木) (注)
(注)まとめて更新するには、「値」ではなく「式」(構文木) を指定できる
必要があり、そのためには演算子オーバーライドなどが使えると便利。
copyright © 2014 kuwata-lab.com all rights reserved
DBAが取るべき予防策
✓ N+1問題について開発側と話しあっておく
使用するORMでの解決方法を事前に確認しておく、

また親-子だけでなく親-子-孫の場合も解決できるか要確認
✓ 「N+1問題だけは許さんぞ!」と、開発側に

しつこく言い続けてプレッシャーをかける
N+1問題の名前は知ってても深刻さを分かってない開発者が多い
「N+1問題?何ですかそれ?」
と開発者が言おうものなら「喝!」
copyright © 2014 kuwata-lab.com all rights reserved
ORMでよくあるトラブル
✓ N+1 問題
深刻度:極
✓ クエリ発行箇所が特定できない問題
深刻度:大
✓ インデックスつけ忘れ問題
深刻度:中
✓ select * 問題
深刻度:小
copyright © 2014 kuwata-lab.com all rights reserved
「クエリ発行箇所が特定できない問題」とは?
スロークエリが検出されても、それがプログラムの
どこで発行されたかが分からず手が打てない問題
DBAにとっては、とてもフラストレーションのたまる事案
User.where(gender:	 "F")

	 	 	 	 .where(deleted:	 nil)

	 	 	 	 .order_by("name")

	 	 	 	 .all()
select	 *	 from	 users

where	 gender	 =	 "F"

	 	 and	 deleted	 is	 null

order	 by	 name
こっち方向は特定できるけど
こっち方向が特定できない ;(
copyright © 2014 kuwata-lab.com all rights reserved
ORM側の対策:SQL ID、クエリID
コメントを使って、SQLごとに一意なIDをつける
1つのSQLが複数個所から呼ばれることがあるので、クエリごとにIDをつ
けるのが望ましい (注)
--	 [sql:fg9xk]

select	 *

from	 users

/**	 if	 (gender)	 {	 **/

where	 gender	 =	 :gender

/**	 }	 **/
User.where(gender:	 "F")

	 	 	 	 .where(deleted:	 nil)

	 	 	 	 .order_by("name")

	 	 	 	 .comment("[q:yxe4m]")

	 	 	 	 .all()
多くのORMで未サポート ;(
(注) IDのかわりに、呼び出し元のファイル名と行番号でもよい
copyright © 2014 kuwata-lab.com all rights reserved
DBAが取るべき予防策
✓ SQL IDが付けられるなら、付けてもらう
✓ 呼び出し元のファイル名と行番号がわかるなら、
SQLコメントやログに記録してもらう
✓ Slow QueryがどのAPIで発行されたかを特定
できるような仕組みを用意する
要は、SQLだけでは特定できないなら別の方向から絞り込む
copyright © 2014 kuwata-lab.com all rights reserved
ORMでよくあるトラブル
✓ N+1 問題
深刻度:極
✓ クエリ発行箇所が特定できない問題
深刻度:大
✓ インデックスつけ忘れ問題
深刻度:中
✓ select * 問題
深刻度:小
copyright © 2014 kuwata-lab.com all rights reserved
「インデックスつけ忘れ問題」とは?
そのままの意味
ORMでなくても発生する問題だが、発行されるSQLが具体的でないと
explainを実行できないため、ORMだとより発生しやすいといえる
User.where(gender:	 "F")

	 	 	 	 .where(deleted_at:	 nil)

	 	 	 	 .order_by("created_at")

	 	 	 	 .all()
実行しないとどんなSQLが分かりにくい
→ explain で調べにくい
  → index つけ忘れに気付かない
copyright © 2014 kuwata-lab.com all rights reserved
ORM側の対策:スキーマ定義で指定
カラムごとにインデックス作成を指定する
複合インデックスも指定できることが多い
class	 User(Base):

	 	 id	 	 	 	 =	 Column(Integer,	 primary_key=True)

	 	 name	 	 =	 Column(String(255),	 nullable=False,	 index=True)

	 	 email	 =	 Column(String(255),	 nullable=True,	 index=True)
カラムごとにインデックス作成を

指定できるので忘れにくい
(SQLはこれができないので忘れやすい)
残念ながら、本質的な解決策がない ;(
copyright © 2014 kuwata-lab.com all rights reserved
DBAが取るべき予防策
✓ インデックスが必要そうなカラムをリストアッ
プし、重点的にチェック
・where で使いそう … 名前, コード, メアド, 生年月日, etc
・order by で使いそう … 名前, 作成日時, 更新日時, etc
・join で使いそう … 外部キー, 多対多の中間テーブル, etc
✓ 大きいテストデータを用意してあげる
小さいデータで開発しているから気付かない、

大きいデータを用意してあげれば遅いことに気付きやすい
copyright © 2014 kuwata-lab.com all rights reserved
ORMでよくあるトラブル
✓ N+1 問題
深刻度:極
✓ クエリ発行箇所が特定できない問題
深刻度:大
✓ インデックスつけ忘れ問題
深刻度:中
✓ select * 問題
深刻度:小
copyright © 2014 kuwata-lab.com all rights reserved
「select * 問題」とは?
ORMが、使わないカラムもすべて select * で取得
してしまう問題。
特にBlobや長いtextでは重大な問題
articles	 =	 db.query(Article)

for	 x	 in	 articles:

	 	 	 print(x.id,	 x.title)

ここでは記事のIDとタイトルしか
必要ないのに、記事の本文まで取
得してしまう →負荷増大
(注)たいていのORMではカラム名を指定できるはずだが、外部キー経由で
取得した関連オブジェクトのカラムまでは指定できない。
copyright © 2014 kuwata-lab.com all rights reserved
ORM側の対策:遅延フェッチ
Blobや長いtextは、デフォルトではselect時に

除外するよう、ORMのスキーマで指定する
明示的に指定した場合のみ取得する
class	 Article(Base):

	 	 id	 	 	 	 =	 Column(Integer,	 primary_key=True)

	 	 title	 =	 Column(String,	 nullable=False,	 index=True)

	 	 body	 	 =	 deferred(Column(Text,	 nullable=False)

デフォルトでは select 文で
取得する対象にしない
copyright © 2014 kuwata-lab.com all rights reserved
DBAが取るべき予防策
✓ Blobや長いtextは、別テーブルに分離する
かわりに N+1 問題が発生する可能性があるので注意すること
✓ 必要なカラムだけを指定したビューを作る
外部キーで参照しているテーブルまでは変えられないので注意
✓ カラム名の細かい指定はある程度あきらめる
パフォーマンス劣化が深刻でなければ許容する
ORMと折り合いをつける
• • • •
ための、DBAの心構え
copyright © 2014 kuwata-lab.com all rights reserved
心構えその1:相手を知る
✓ ORMの仕組みを知る
知っていればトラブルに対処しやすい、開発者に提案しやすい

例:ぐるぐる系SQLが現れた!

× だからORMは止めよう!

◎ eager loadingを使うよう提案しよう!
✓ アプリ開発を知る
DBの知識だけで物事を考えない、トラブル対応しようとしない
copyright © 2014 kuwata-lab.com all rights reserved
心構えその2:先手を打つ
✓ 問題が起きるまえに対策を講じる
問題が起きてからどうするか?より、問題を起こさないためには
どうするか? (「ORMを使わない」というのはなしで ;)
✓ 開発初期から開発チームに助言する(特にN+1問題)
開発終盤になってから文句を言っても手遅れ
copyright © 2014 kuwata-lab.com all rights reserved
心構えその3:教えてあげる
✓ 開発者がSQLを知らないなら教えてあげる
一見面倒だが、それで重大なトラブルが減らせるなら安上がり
✓ 開発者からのSQLの相談に乗ってあげる
一見面倒だが、下手にORMだけでやられてトラブるより安上がり
copyright © 2014 kuwata-lab.com all rights reserved
心構えその4:心を広く持つ
✓ 最高速度を求めない
必要な速度が出ればそれでよしとする
✓ 最高品質を求めない
必要なサービス品質が提供できればよしとする
copyright © 2014 kuwata-lab.com all rights reserved
心構えその5:金を積む
✓ 「SQLのできる開発者」は金を出せば手に入る
札束で頬をひっぱたけばスキルのある開発者を囲えることは、

GREEやDeNAやLINEが証明してくれました
✓ 金を惜しんでるなら文句を言うべきではない
月20万30万そこそこの人材に多くを求めすぎない (※)
(※)たいていのアプリ開発者にとって、SQLは「多く」に含まれることに注意
まとめ
copyright © 2014 kuwata-lab.com all rights reserved
まとめ
✓ ORMによるトラブルは (たいてい) 解決策がある
✓ 解決策を知れば嫌悪感は (許容半以内に) 抑えられる
✓ 我々のゴールは「プロジェクトやサービスの

成功」であることを思い出す (対立することではない)
copyright © 2014 kuwata-lab.com all rights reserved
Q&A:個人的にお勧めなO/Rマッパーは?
✓ DataMapper (ruby) http://datamapper.org/
Strategic Eager Loadingのような秀逸なアイデアを生み出している
✓ Sequel (ruby) http://sequel.jeremyevans.net/
使いやすさと簡潔さがよく考えられている印象
✓ SQLAlchemy (python) http://www.sqlalchemy.org/
教科書 (PoEAA) に忠実に作られている印象
✓ 自作!自作マジお勧め!
職人が自分の道具作って何が悪い!車輪の再発明なぞ知らんがな!
ActiveRecord?あれはあんまり…
copyright © 2014 kuwata-lab.com all rights reserved
この資料を読んだ人はこんな資料も読んでます
✓ O/R Mapperを支える技術
http://rubykaigi.org/2011/ja/schedule/details/18S08
✓ なぜO/Rマッパーが重要か?
http://www.slideshare.net/kwatch/sqlor
✓ ORM is an anti-pattern
http://seldo.com/weblog/2011/06/15/orm_is_an_antipattern
✓ ORMのパフォーマンス最適化
http://www.infoq.com/jp/articles/optimizing-orm-performance
✓ Patterns Implemented by SQLAlchemy
http://techspot.zzzeek.org/2012/02/07/patterns-implemented-by-sqlalchemy/
ORMごときに振り回される
段階はとっとと卒業して、
より高度で本質的な問題に
エネルギーを使いましょう

Más contenido relacionado

La actualidad más candente

Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Taku Miyakawa
 
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)NTT DATA Technology & Innovation
 
ストリーム処理を支えるキューイングシステムの選び方
ストリーム処理を支えるキューイングシステムの選び方ストリーム処理を支えるキューイングシステムの選び方
ストリーム処理を支えるキューイングシステムの選び方Yoshiyasu SAEKI
 
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織Takafumi ONAKA
 
[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティス
[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティス[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティス
[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティスAmazon Web Services Japan
 
初心者向けMongoDBのキホン!
初心者向けMongoDBのキホン!初心者向けMongoDBのキホン!
初心者向けMongoDBのキホン!Tetsutaro Watanabe
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)Takuto Wada
 
MQ入門
MQ入門MQ入門
MQ入門HIRA
 
Webアプリを並行開発する際のマイグレーション戦略
Webアプリを並行開発する際のマイグレーション戦略Webアプリを並行開発する際のマイグレーション戦略
Webアプリを並行開発する際のマイグレーション戦略Takayuki Shimizukawa
 
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャーKubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャーToru Makabe
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション土岐 孝平
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021Hiroshi Tokumaru
 
DockerとPodmanの比較
DockerとPodmanの比較DockerとPodmanの比較
DockerとPodmanの比較Akihiro Suda
 
ゲームエンジニアのためのデータベース設計
ゲームエンジニアのためのデータベース設計ゲームエンジニアのためのデータベース設計
ゲームエンジニアのためのデータベース設計sairoutine
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪Takuto Wada
 
AWSのログ管理ベストプラクティス
AWSのログ管理ベストプラクティスAWSのログ管理ベストプラクティス
AWSのログ管理ベストプラクティスAkihiro Kuwano
 
マイクロサービス 4つの分割アプローチ
マイクロサービス 4つの分割アプローチマイクロサービス 4つの分割アプローチ
マイクロサービス 4つの分割アプローチ増田 亨
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Akihiro Suda
 
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?kwatch
 

La actualidad más candente (20)

Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
 
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
 
ストリーム処理を支えるキューイングシステムの選び方
ストリーム処理を支えるキューイングシステムの選び方ストリーム処理を支えるキューイングシステムの選び方
ストリーム処理を支えるキューイングシステムの選び方
 
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
 
[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティス
[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティス[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティス
[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティス
 
初心者向けMongoDBのキホン!
初心者向けMongoDBのキホン!初心者向けMongoDBのキホン!
初心者向けMongoDBのキホン!
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
 
MQ入門
MQ入門MQ入門
MQ入門
 
Webアプリを並行開発する際のマイグレーション戦略
Webアプリを並行開発する際のマイグレーション戦略Webアプリを並行開発する際のマイグレーション戦略
Webアプリを並行開発する際のマイグレーション戦略
 
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャーKubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021
 
ヤフー社内でやってるMySQLチューニングセミナー大公開
ヤフー社内でやってるMySQLチューニングセミナー大公開ヤフー社内でやってるMySQLチューニングセミナー大公開
ヤフー社内でやってるMySQLチューニングセミナー大公開
 
DockerとPodmanの比較
DockerとPodmanの比較DockerとPodmanの比較
DockerとPodmanの比較
 
ゲームエンジニアのためのデータベース設計
ゲームエンジニアのためのデータベース設計ゲームエンジニアのためのデータベース設計
ゲームエンジニアのためのデータベース設計
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
AWSのログ管理ベストプラクティス
AWSのログ管理ベストプラクティスAWSのログ管理ベストプラクティス
AWSのログ管理ベストプラクティス
 
マイクロサービス 4つの分割アプローチ
マイクロサービス 4つの分割アプローチマイクロサービス 4つの分割アプローチ
マイクロサービス 4つの分割アプローチ
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
 
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
 

Similar a O/Rマッパーによるトラブルを未然に防ぐ

よろしい、ならばMicro-ORMだ
よろしい、ならばMicro-ORMだよろしい、ならばMicro-ORMだ
よろしい、ならばMicro-ORMだNarami Kiyokura
 
PacemakerのMaster/Slave構成の基本と事例紹介(DRBD、PostgreSQLレプリケーション) @Open Source Confer...
PacemakerのMaster/Slave構成の基本と事例紹介(DRBD、PostgreSQLレプリケーション) @Open Source Confer...PacemakerのMaster/Slave構成の基本と事例紹介(DRBD、PostgreSQLレプリケーション) @Open Source Confer...
PacemakerのMaster/Slave構成の基本と事例紹介(DRBD、PostgreSQLレプリケーション) @Open Source Confer...Tatsuya Watanabe
 
Add PLEASE clause to Oracle Database
Add PLEASE clause to Oracle DatabaseAdd PLEASE clause to Oracle Database
Add PLEASE clause to Oracle DatabaseNoriyoshi Shinoda
 
20131209_buildinsidermeetup
20131209_buildinsidermeetup20131209_buildinsidermeetup
20131209_buildinsidermeetupkumake
 
できる!サーバレスアーキテクチャ
できる!サーバレスアーキテクチャできる!サーバレスアーキテクチャ
できる!サーバレスアーキテクチャazuma satoshi
 
Apache Spark超入門 (Hadoop / Spark Conference Japan 2016 講演資料)
Apache Spark超入門 (Hadoop / Spark Conference Japan 2016 講演資料)Apache Spark超入門 (Hadoop / Spark Conference Japan 2016 講演資料)
Apache Spark超入門 (Hadoop / Spark Conference Japan 2016 講演資料)NTT DATA OSS Professional Services
 
D22 目覚めよDBエンジニア 〜世界最速カラムナーデータベースは本物だ!〜 by Koji Shinkubo
D22 目覚めよDBエンジニア 〜世界最速カラムナーデータベースは本物だ!〜 by Koji ShinkuboD22 目覚めよDBエンジニア 〜世界最速カラムナーデータベースは本物だ!〜 by Koji Shinkubo
D22 目覚めよDBエンジニア 〜世界最速カラムナーデータベースは本物だ!〜 by Koji ShinkuboInsight Technology, Inc.
 
20130203 OSS-DB Exam Silver 技術解説無料セミナー
20130203 OSS-DB Exam Silver 技術解説無料セミナー20130203 OSS-DB Exam Silver 技術解説無料セミナー
20130203 OSS-DB Exam Silver 技術解説無料セミナーKazuko Itoda
 
G-Tech2015 Hadoop/Sparkを中核としたビッグデータ基盤_20151006
G-Tech2015 Hadoop/Sparkを中核としたビッグデータ基盤_20151006G-Tech2015 Hadoop/Sparkを中核としたビッグデータ基盤_20151006
G-Tech2015 Hadoop/Sparkを中核としたビッグデータ基盤_20151006Cloudera Japan
 
基幹業務もHadoop(EMR)で!!のその後
基幹業務もHadoop(EMR)で!!のその後基幹業務もHadoop(EMR)で!!のその後
基幹業務もHadoop(EMR)で!!のその後Keigo Suda
 
Oracle Cloud Platform - クラクドにおける 新たなデータベース開発
Oracle Cloud Platform - クラクドにおける新たなデータベース開発Oracle Cloud Platform - クラクドにおける新たなデータベース開発
Oracle Cloud Platform - クラクドにおける 新たなデータベース開発オラクルエンジニア通信
 
[db tech showcase Sapporo 2015] C15:商用RDBをOSSへ Oracle to Postgres 徹底解説 by 株式会...
[db tech showcase Sapporo 2015] C15:商用RDBをOSSへ Oracle to Postgres 徹底解説 by 株式会...[db tech showcase Sapporo 2015] C15:商用RDBをOSSへ Oracle to Postgres 徹底解説 by 株式会...
[db tech showcase Sapporo 2015] C15:商用RDBをOSSへ Oracle to Postgres 徹底解説 by 株式会...Insight Technology, Inc.
 
ついに解禁!Amazon Aurora徹底検証!
ついに解禁!Amazon Aurora徹底検証!ついに解禁!Amazon Aurora徹底検証!
ついに解禁!Amazon Aurora徹底検証!Terui Masashi
 
3年間の情報漏洩事件からみるデータ保護対策の勘所 ~ データ・セキュリティ、考え方とその仕組み
3年間の情報漏洩事件からみるデータ保護対策の勘所 ~ データ・セキュリティ、考え方とその仕組み3年間の情報漏洩事件からみるデータ保護対策の勘所 ~ データ・セキュリティ、考え方とその仕組み
3年間の情報漏洩事件からみるデータ保護対策の勘所 ~ データ・セキュリティ、考え方とその仕組みオラクルエンジニア通信
 
組み込みDb empressのご紹介
組み込みDb empressのご紹介組み込みDb empressのご紹介
組み込みDb empressのご紹介ITDORAKU
 

Similar a O/Rマッパーによるトラブルを未然に防ぐ (20)

よろしい、ならばMicro-ORMだ
よろしい、ならばMicro-ORMだよろしい、ならばMicro-ORMだ
よろしい、ならばMicro-ORMだ
 
PacemakerのMaster/Slave構成の基本と事例紹介(DRBD、PostgreSQLレプリケーション) @Open Source Confer...
PacemakerのMaster/Slave構成の基本と事例紹介(DRBD、PostgreSQLレプリケーション) @Open Source Confer...PacemakerのMaster/Slave構成の基本と事例紹介(DRBD、PostgreSQLレプリケーション) @Open Source Confer...
PacemakerのMaster/Slave構成の基本と事例紹介(DRBD、PostgreSQLレプリケーション) @Open Source Confer...
 
Add PLEASE clause to Oracle Database
Add PLEASE clause to Oracle DatabaseAdd PLEASE clause to Oracle Database
Add PLEASE clause to Oracle Database
 
20131209_buildinsidermeetup
20131209_buildinsidermeetup20131209_buildinsidermeetup
20131209_buildinsidermeetup
 
Oracle Spatial 概要説明資料
Oracle Spatial 概要説明資料Oracle Spatial 概要説明資料
Oracle Spatial 概要説明資料
 
できる!サーバレスアーキテクチャ
できる!サーバレスアーキテクチャできる!サーバレスアーキテクチャ
できる!サーバレスアーキテクチャ
 
超高速な機械学習を Oracle Database で実現!
超高速な機械学習を Oracle Database で実現!超高速な機械学習を Oracle Database で実現!
超高速な機械学習を Oracle Database で実現!
 
NTT DATA と PostgreSQL が挑んだ総力戦
NTT DATA と PostgreSQL が挑んだ総力戦NTT DATA と PostgreSQL が挑んだ総力戦
NTT DATA と PostgreSQL が挑んだ総力戦
 
Apache Spark超入門 (Hadoop / Spark Conference Japan 2016 講演資料)
Apache Spark超入門 (Hadoop / Spark Conference Japan 2016 講演資料)Apache Spark超入門 (Hadoop / Spark Conference Japan 2016 講演資料)
Apache Spark超入門 (Hadoop / Spark Conference Japan 2016 講演資料)
 
D22 目覚めよDBエンジニア 〜世界最速カラムナーデータベースは本物だ!〜 by Koji Shinkubo
D22 目覚めよDBエンジニア 〜世界最速カラムナーデータベースは本物だ!〜 by Koji ShinkuboD22 目覚めよDBエンジニア 〜世界最速カラムナーデータベースは本物だ!〜 by Koji Shinkubo
D22 目覚めよDBエンジニア 〜世界最速カラムナーデータベースは本物だ!〜 by Koji Shinkubo
 
20130203 oss-db-lpi
20130203 oss-db-lpi20130203 oss-db-lpi
20130203 oss-db-lpi
 
20130203 OSS-DB Exam Silver 技術解説無料セミナー
20130203 OSS-DB Exam Silver 技術解説無料セミナー20130203 OSS-DB Exam Silver 技術解説無料セミナー
20130203 OSS-DB Exam Silver 技術解説無料セミナー
 
PostgreSQL9.3新機能紹介
PostgreSQL9.3新機能紹介PostgreSQL9.3新機能紹介
PostgreSQL9.3新機能紹介
 
G-Tech2015 Hadoop/Sparkを中核としたビッグデータ基盤_20151006
G-Tech2015 Hadoop/Sparkを中核としたビッグデータ基盤_20151006G-Tech2015 Hadoop/Sparkを中核としたビッグデータ基盤_20151006
G-Tech2015 Hadoop/Sparkを中核としたビッグデータ基盤_20151006
 
基幹業務もHadoop(EMR)で!!のその後
基幹業務もHadoop(EMR)で!!のその後基幹業務もHadoop(EMR)で!!のその後
基幹業務もHadoop(EMR)で!!のその後
 
Oracle Cloud Platform - クラクドにおける 新たなデータベース開発
Oracle Cloud Platform - クラクドにおける新たなデータベース開発Oracle Cloud Platform - クラクドにおける新たなデータベース開発
Oracle Cloud Platform - クラクドにおける 新たなデータベース開発
 
[db tech showcase Sapporo 2015] C15:商用RDBをOSSへ Oracle to Postgres 徹底解説 by 株式会...
[db tech showcase Sapporo 2015] C15:商用RDBをOSSへ Oracle to Postgres 徹底解説 by 株式会...[db tech showcase Sapporo 2015] C15:商用RDBをOSSへ Oracle to Postgres 徹底解説 by 株式会...
[db tech showcase Sapporo 2015] C15:商用RDBをOSSへ Oracle to Postgres 徹底解説 by 株式会...
 
ついに解禁!Amazon Aurora徹底検証!
ついに解禁!Amazon Aurora徹底検証!ついに解禁!Amazon Aurora徹底検証!
ついに解禁!Amazon Aurora徹底検証!
 
3年間の情報漏洩事件からみるデータ保護対策の勘所 ~ データ・セキュリティ、考え方とその仕組み
3年間の情報漏洩事件からみるデータ保護対策の勘所 ~ データ・セキュリティ、考え方とその仕組み3年間の情報漏洩事件からみるデータ保護対策の勘所 ~ データ・セキュリティ、考え方とその仕組み
3年間の情報漏洩事件からみるデータ保護対策の勘所 ~ データ・セキュリティ、考え方とその仕組み
 
組み込みDb empressのご紹介
組み込みDb empressのご紹介組み込みDb empressのご紹介
組み込みDb empressのご紹介
 

Más de kwatch

How to make the fastest Router in Python
How to make the fastest Router in PythonHow to make the fastest Router in Python
How to make the fastest Router in Pythonkwatch
 
Migr8.rb チュートリアル
Migr8.rb チュートリアルMigr8.rb チュートリアル
Migr8.rb チュートリアルkwatch
 
なんでもID
なんでもIDなんでもID
なんでもIDkwatch
 
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方kwatch
 
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方kwatch
 
正規表現リテラルは本当に必要なのか?
正規表現リテラルは本当に必要なのか?正規表現リテラルは本当に必要なのか?
正規表現リテラルは本当に必要なのか?kwatch
 
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)kwatch
 
DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!kwatch
 
PHPとJavaScriptにおけるオブジェクト指向を比較する
PHPとJavaScriptにおけるオブジェクト指向を比較するPHPとJavaScriptにおけるオブジェクト指向を比較する
PHPとJavaScriptにおけるオブジェクト指向を比較するkwatch
 
Fantastic DSL in Python
Fantastic DSL in PythonFantastic DSL in Python
Fantastic DSL in Pythonkwatch
 
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策kwatch
 
PHP5.5新機能「ジェネレータ」初心者入門
PHP5.5新機能「ジェネレータ」初心者入門PHP5.5新機能「ジェネレータ」初心者入門
PHP5.5新機能「ジェネレータ」初心者入門kwatch
 
Pretty Good Branch Strategy for Git/Mercurial
Pretty Good Branch Strategy for Git/MercurialPretty Good Branch Strategy for Git/Mercurial
Pretty Good Branch Strategy for Git/Mercurialkwatch
 
Oktest - a new style testing library for Python -
Oktest - a new style testing library for Python -Oktest - a new style testing library for Python -
Oktest - a new style testing library for Python -kwatch
 
文字列結合のベンチマークをいろんな処理系でやってみた
文字列結合のベンチマークをいろんな処理系でやってみた文字列結合のベンチマークをいろんな処理系でやってみた
文字列結合のベンチマークをいろんな処理系でやってみたkwatch
 
I have something to say about the buzz word "From Java to Ruby"
I have something to say about the buzz word "From Java to Ruby"I have something to say about the buzz word "From Java to Ruby"
I have something to say about the buzz word "From Java to Ruby"kwatch
 
Cより速いRubyプログラム
Cより速いRubyプログラムCより速いRubyプログラム
Cより速いRubyプログラムkwatch
 
Javaより速いLL用テンプレートエンジン
Javaより速いLL用テンプレートエンジンJavaより速いLL用テンプレートエンジン
Javaより速いLL用テンプレートエンジンkwatch
 
Underlaying Technology of Modern O/R Mapper
Underlaying Technology of Modern O/R MapperUnderlaying Technology of Modern O/R Mapper
Underlaying Technology of Modern O/R Mapperkwatch
 
How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -
How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -
How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -kwatch
 

Más de kwatch (20)

How to make the fastest Router in Python
How to make the fastest Router in PythonHow to make the fastest Router in Python
How to make the fastest Router in Python
 
Migr8.rb チュートリアル
Migr8.rb チュートリアルMigr8.rb チュートリアル
Migr8.rb チュートリアル
 
なんでもID
なんでもIDなんでもID
なんでもID
 
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
 
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
 
正規表現リテラルは本当に必要なのか?
正規表現リテラルは本当に必要なのか?正規表現リテラルは本当に必要なのか?
正規表現リテラルは本当に必要なのか?
 
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
 
DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!
 
PHPとJavaScriptにおけるオブジェクト指向を比較する
PHPとJavaScriptにおけるオブジェクト指向を比較するPHPとJavaScriptにおけるオブジェクト指向を比較する
PHPとJavaScriptにおけるオブジェクト指向を比較する
 
Fantastic DSL in Python
Fantastic DSL in PythonFantastic DSL in Python
Fantastic DSL in Python
 
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
 
PHP5.5新機能「ジェネレータ」初心者入門
PHP5.5新機能「ジェネレータ」初心者入門PHP5.5新機能「ジェネレータ」初心者入門
PHP5.5新機能「ジェネレータ」初心者入門
 
Pretty Good Branch Strategy for Git/Mercurial
Pretty Good Branch Strategy for Git/MercurialPretty Good Branch Strategy for Git/Mercurial
Pretty Good Branch Strategy for Git/Mercurial
 
Oktest - a new style testing library for Python -
Oktest - a new style testing library for Python -Oktest - a new style testing library for Python -
Oktest - a new style testing library for Python -
 
文字列結合のベンチマークをいろんな処理系でやってみた
文字列結合のベンチマークをいろんな処理系でやってみた文字列結合のベンチマークをいろんな処理系でやってみた
文字列結合のベンチマークをいろんな処理系でやってみた
 
I have something to say about the buzz word "From Java to Ruby"
I have something to say about the buzz word "From Java to Ruby"I have something to say about the buzz word "From Java to Ruby"
I have something to say about the buzz word "From Java to Ruby"
 
Cより速いRubyプログラム
Cより速いRubyプログラムCより速いRubyプログラム
Cより速いRubyプログラム
 
Javaより速いLL用テンプレートエンジン
Javaより速いLL用テンプレートエンジンJavaより速いLL用テンプレートエンジン
Javaより速いLL用テンプレートエンジン
 
Underlaying Technology of Modern O/R Mapper
Underlaying Technology of Modern O/R MapperUnderlaying Technology of Modern O/R Mapper
Underlaying Technology of Modern O/R Mapper
 
How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -
How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -
How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -
 

O/Rマッパーによるトラブルを未然に防ぐ

  • 1. O/R Mapper による トラブルを未然に防ぐ Makoto Kuwata <kwa@kuwata-lab.com> http://www.kuwata-lab.com/ PostgreSQLカンファレンス 2014 ver 1.1.0
  • 2. copyright © 2014 kuwata-lab.com all rights reserved まえがき 現在、アプリケーション開発の現場では O/R Mapper (ORM) が普及しています。今後 も ORM を使った開発は、増えることはあっても減ることはないでしょう。 しかし ORM は、アプリケーション開発者にとっては便利でも、DB 管理者 (DBA) か らみたらトラブルの種でもあります。それが特にパフォーマンスに関する問題であるこ とが多いため、開発者と DBA が対立することも珍しくありません。 とはいえ、ORM による問題はすでに解決策が用意されている場合があります。本当の 問題は、すでに存在する解決策があまり知られていないことではないでしょうか。 そこで本発表では、ORM によってどのような問題が起こりやすいか、どう解決・予防 すればいいか、そして ORM とどう「折り合い」をつけるかを説明します。特に、よく トラブルとなる「N+1 問題」については説明を多めにしています。 また本発表を通じて、開発者と DBA が「互いが互いを知らないままに批判しあう」と いう状況を改善し、両者が協調できる「まだ見ぬ丘の向こう」を目指します。
  • 3. copyright © 2014 kuwata-lab.com all rights reserved まとめ ✓ ORMによるトラブルは (たいてい) 解決策がある ✓ 解決策を知れば嫌悪感は (許容半以内に) 抑えられる ✓ 我々のゴールは「プロジェクトやサービスの
 成功」であることを思い出す (対立することではない)
  • 5. copyright © 2014 kuwata-lab.com all rights reserved 背景:ORMによるトラブルが多発 ✓ ORMが生成するSQLがクソ いわゆる「ぐるぐる系SQL」 ✓ SQLをろくに勉強しないアプリ開発者 そのくせOOPやデザインパターンを得意げに語る ;( ✓ 開発効率を上げるためのORMなのに話が違う! ある面では効率が上がっても、別の問題を引き起こしている
  • 6. copyright © 2014 kuwata-lab.com all rights reserved どこかでみた風景 実はオブジェクト指向って しっくりこないんです… SQLの書けないやつなぞ エンジニアとして三流! 今はORMもKVSもある! SQLよりOOPのほうが重要! Staticおじさんww 老害wwwww OOP信者 自分の得意分野に入り浸って、それ以外の分野に飛び込めない人たちっているよね…
  • 7. copyright © 2014 kuwata-lab.com all rights reserved 背景:DBAがORMを知らなすぎる ✓ ORMのことをろくに知らずに批判している人 が多すぎ ✓ 「SQLをろくに知らない開発者」
 vs 「ORMをろくに知らないDBA」 ✓ ORMを知らない→トラブルが解決できない→ 「ORMなんかクソ!」
  • 8. copyright © 2014 kuwata-lab.com all rights reserved わかってない人によるORM批判その1 (ORMは) テーブルから全行をスキャンし、 クライアントアプリケーションへ ネットワーク越しに転送する “ ”『nabokov7; rehash : O/Rマッパーはなぜ悪か』 http://nabokov.blog.jp/archives/1529263.html ちゃんとDB側で絞りこんでから 転送してますよぉ!
  • 9. copyright © 2014 kuwata-lab.com all rights reserved わかってない人によるORM批判その2 たとえば、SQL を書くことでフィルタリ ングを DB で実行していたのに、O/R を 使うことでフィルタリングは、そのプロ グラミング言語がやることになります。 “ ” where句もhaving句も DB側でやってますよぉ! https://twitter.com/kazu_yamamoto/status/280872190805680129
  • 10. copyright © 2014 kuwata-lab.com all rights reserved なぜORMを嫌うのか? ✓ 理由:
 ORMがトラブルを引き起こすから? ✓ 本当の理由:
 ORMによるトラブルが解決できないから! トラブルの解決方法を知れば そこまで嫌うことはないはず
  • 11. copyright © 2014 kuwata-lab.com all rights reserved 理想と現実の間には、妥協点が存在する ・アプリ開発者がSQLを勉強してくれる ・ORMの吐くSQLにDBAが反吐を吐く ・ORMによるトラブルの芽を早期に潰す 【理想】 【現実】
  • 12. copyright © 2014 kuwata-lab.com all rights reserved 本発表の目的は、DBAの皆さんに… ✓ ORMでよくあるトラブルとその予防策を知っ てもらう 嫌悪感の本当の原因は、ORMがトラブルを起こすからではなく、 トラブルが解決できない (=解決策を知らない) から ✓ そのためにORMの仕組みを知ってもらう 解決方法を知らないのは、DBAがORMを知らなすぎるから ✓ 「O/R Mapperなんか使うな!」とは違う問 題解決方法があることを知ってもらう 「問題があるから禁止」は問題の解決になっていない
  • 14. copyright © 2014 kuwata-lab.com all rights reserved ORMの役目は、大きく3つ • • • SQL RecordSet SQLを組み立てて発行 スキーマを作成・変更 トラブルはここで発生 (今日はここのお話) レコードセットを オブジェクトに変換 Database Application
  • 15. copyright © 2014 kuwata-lab.com all rights reserved Prepared Statementじゃだめなの? ✓ 要件:実行時に検索条件を変えたい ✓ Prepared Statementではwhere句への追加 などが行えない 性別: 男性 女性 年齢: ∼ 歳歳 無指定 検索条件
  • 16. copyright © 2014 kuwata-lab.com all rights reserved SQLを動的に組み立てる:文字列結合 var cond = [], args = []; if ( params.gender == "M" || params.gender == "F") { cond.push("gender = ?"); args.push(params.gender); } if (params.max_age) { cond.push("age <= ?"); args.push(params.max_age); } var sql = "select * from users"; if (cond.length) { sql += " where " + cond.join(" and "); } sql += " order by name"; とても面倒なうえに、SQL Injectionを誘発しやすい
  • 17. copyright © 2014 kuwata-lab.com all rights reserved SQLを動的に組み立てる:ORM SQLテンプレート方式 専用のテンプレートエンジンを 使って、SQLを生成する select * from students where /** if (gender) { **/ gender = :gender /** } **/ order by name クエリオブジェクト方式 SQLを表現するデータを作成し、 それをSQL文字列に変換する { table: "students", where: [["gender=","F"]], orderby: ["name"] } select * from students where gender = 'F' order by name
  • 18. copyright © 2014 kuwata-lab.com all rights reserved SQLテンプレート方式 select * from students /** if (gender || max_age) { **/ where true /** if (gender) { **/ and gender = :gender /** } **/ /** if (max_age) { **/ and age <= :max_age /** } **/ /** } **/ order by name 文字列結合よりは読みやすい、SQL Injectionも誘発しない この「true」はSQLのoptimizerが 除去してくれる (PostgreSQL)
  • 19. copyright © 2014 kuwata-lab.com all rights reserved SQLテンプレート方式 select * from students /** if (gender || max_age) { **/ where true /** if (gender) { **/ and gender = :gender /** } **/ /** if (max_age) { **/ and age <= :max_age /** } **/ /** } **/ order by name 不要な "and" や "while" をORMが 自動的に取り除いてくれる SQLを解釈できるORMなら、より簡潔に書けることも
  • 20. copyright © 2014 kuwata-lab.com all rights reserved SQLテンプレート方式 select st.* from students st where /** if (gender) { **/ st.gender = :gender /** } **/ --------------------- select st.*, cl.* from students st join classes cl on st.class_id = cl.id where /** if (gender) { **/ st.gender = :gender /** } **/ それぞれで条件式が重複している (DRYではない) 似たようなSQLを複数書く必要があり、DRYではない 所属クラスが いらない場合のSQL 所属クラスが 必要な場合のSQL
  • 21. copyright © 2014 kuwata-lab.com all rights reserved クエリオブジェクト方式 var query = {table: "students", where: [], orderBy: []}; // if (params.gender) query.where.push(["gender=", params.gender]); if (params.max_age) query.where.push(["age<=", params.max_age]); query.orderBy.push("name"); // var sql = generateSQL(query); オブジェクトに各種条件を追加し、最後にSQLへ変換 where や order by を
 データとして操作できる
  • 22. copyright © 2014 kuwata-lab.com all rights reserved クエリオブジェクト方式 var query = new Query(Student); // if (params.gender) query.where("gender", params.gender); if (params.max_age) query.where("age<=", params.max_age); query.orderBy("name"); // var sql = query.generateSQL(); 通常は専用のクエリクラスを使うので、簡潔に書ける
  • 23. copyright © 2014 kuwata-lab.com all rights reserved クエリオブジェクト方式 var query = new Query(Student); // if (params.gender) query.where(Student.gender == params.gender); if (params.max_age) query.where(Student.age <= params.age); query.orderBy(Student.name); // var sql = query.generateSQL(); よくできた言語とよくできたORMなら「式」を指定可能 演算子オーバーライドや AST変換を活用
  • 24. copyright © 2014 kuwata-lab.com all rights reserved クエリオブジェクト方式 == x nil x is nullx == nil 評価 変換 構文解析ではないことに注意! ("==" の評価結果がtrue/falseではなく構文木) (ソースコード) (構文木) (SQL) 「x = null」ではなく 「x is null」になってくれる! 演算子オーバライドを利用した、構文木生成の仕組み
  • 25. copyright © 2014 kuwata-lab.com all rights reserved 余談:LINQの実態はクエリオブジェクト // SQLのようだが実はC# from st in Student where st.gender == "F" order by st.name select st; LINQ:変換前 // だいたいこんな感じ From(Student) .Where(x => x.gender == "F") .OrderBy(Student.name) .ToArray(); LINQ:変換後
  • 26. copyright © 2014 kuwata-lab.com all rights reserved 特徴:SQLテンプレート方式 ✓ 仕組みがわかりやすい ORMの学習コストが低い、トラブルに対処しやすい ✓ SQLが予想しやすい つまりチューニングしやすい ✓ SQLの欠点はそのまま DRYにする仕組みがない、'=' と 'is' の使い分けが必要、など ✓ SQL Injectionはほぼ発生しない 文字列結合をするコードを書かなくて済むため
  • 27. copyright © 2014 kuwata-lab.com all rights reserved 特徴:クエリオブジェクト方式 ✓ 仕組みが複雑 ORMの学習コストが高い、トラブル対応がしにくい ✓ どんなSQLになるかを確認する必要がある 予想外のSQLが生成されることも ✓ SQLではできないことができる 詳細は『なぜORMが必要か?』でggr ✓ SQL Injectionはほぼ発生しない 構文木(or 類似した構造)を作ってからSQLに変換するため
  • 28. copyright © 2014 kuwata-lab.com all rights reserved ORMのアーキテクチャは「PoEAA」を読め Object-Relational Structural Patterns • Identity Field • Foreign Key Mapping • Association Table Mapping • Dependent Mapping • EmbeddedValue • Serialized LOB • Single Table Inheritance • Class Table Inheritance • Concrete Table Inheritance • Inheritance Mappers Data Source Architectural Patterns • Table Data Gateway • Row Data Gateway • Active Record • Data Mapper Object-Relational Behavioral Patterns • Unit of Work • Identity Map • Lazy Load Object-Relational Metadata Mapping Patterns • Metadata Mapping • Query Object • Repository (注)PoEAA …『Pattern of Enterprise Application Architecture』(Martin Fowler, 2002)
  • 30. copyright © 2014 kuwata-lab.com all rights reserved ORMでよくあるトラブル ✓ N+1 問題 深刻度:極 ✓ クエリ発行箇所が特定できない問題 深刻度:大 ✓ インデックスつけ忘れ問題 深刻度:中 ✓ select * 問題 深刻度:小
  • 31. copyright © 2014 kuwata-lab.com all rights reserved ORMでよくあるトラブル ✓ N+1 問題 深刻度:極 ✓ クエリ発行箇所が特定できない問題 深刻度:大 ✓ インデックスつけ忘れ問題 深刻度:中 ✓ select * 問題 深刻度:小
  • 32. copyright © 2014 kuwata-lab.com all rights reserved 「N+1 問題」 とは? 一覧を取得するSQLを発行してから、
 各要素ごとに個別のSQLを発行してしまうこと いわゆる「ぐるぐる系SQL」のこと。パフォーマンスが極端に落ちる users = User.all() for user in users print user.group.name end select * from groups where id = :id をN回発行 select * from users を1回発行 (注)実態をより正確に表すなら「1+N問題」と呼ぶべき (注)
  • 33. copyright © 2014 kuwata-lab.com all rights reserved ORM側の対策:eager loading 一覧を取得するときに、関連する要素もまとめて取 得するよう指定する 実装は、join だったり id in (…) だったり、まちまち users = User.includes("group").all() for user in users print user.group.name end select文は発行されない select * from users を1回発行してから、 select * from groups where id in (…) を 1回発行する (参考)『3 ways to do eager loading (preloading) in Rails 3 & 4 』 http://blog.arkency.com/2013/12/rails4-preloading/
  • 34. copyright © 2014 kuwata-lab.com all rights reserved ORM側の対策:strategic eager loading オブジェクトの関連が必要になったら、親となるコ ンテナに通知し、コンテナがまとめて取得する 子であるオブジェクトが個別に取得するのを止める users = User.includes("group").all() for user in users print user.group.name end groups テーブルへのアクセスが必要になると、 親となるコンテナである users へ通知され、 users がまとめて groups テーブルにアクセスする 明示的な指定が必要ない (参考)『Why DataMapper? (Section: Strategic Eager Loading) http://datamapper.org/why.html
  • 35. copyright © 2014 kuwata-lab.com all rights reserved ORM側の対策:bytecode manipulation bytecodeを解析してeager loadingが必要な箇所 を判定し、それを行うコードを自動的に埋め込む bytecode操作のかわりにAST変換やpreprocessorでもよい List<User> users = query(User).all(); for (User user: users) { System.out.print(user.group.name); } ループの中で関連を取得している ことを検出し、ループ前にまとめ て取得するようbytecodeを変更 (参考)『スケーラブルラピッドプロトタイピングのためのJIT-ORM 』 http://www.ipa.go.jp/files/000007122.pdf
  • 36. copyright © 2014 kuwata-lab.com all rights reserved insert文における「N+1 問題」 1件ずつinsert文を発行するのをやめて、
 bulk insert機能を使って一括作成する もちろん、大量すぎる場合は copy 文 // Bad:1件ずつinsert for s in names u = User.new(name: s) u.save() end // Good:まとめてinsert users = names.map {|s| User.new(name: s) } User.import(users)
  • 37. copyright © 2014 kuwata-lab.com all rights reserved update文における「N+1 問題」 1件ずつupdate文を発行するのをやめて、
 条件で指定した集合をまとめて更新する jQueryにおける $("..条件..").attr(key, value) と同じ // Bad:1件ずつの更新 users = db.query(User).all() for u in users: u.value = u.value+1 db.commit() // Good:まとめて更新 db.query(User) .update({ "value": User.value+1 }) db.commit() これは「値」(数値) これは「式」(構文木) (注) (注)まとめて更新するには、「値」ではなく「式」(構文木) を指定できる 必要があり、そのためには演算子オーバーライドなどが使えると便利。
  • 38. copyright © 2014 kuwata-lab.com all rights reserved DBAが取るべき予防策 ✓ N+1問題について開発側と話しあっておく 使用するORMでの解決方法を事前に確認しておく、
 また親-子だけでなく親-子-孫の場合も解決できるか要確認 ✓ 「N+1問題だけは許さんぞ!」と、開発側に
 しつこく言い続けてプレッシャーをかける N+1問題の名前は知ってても深刻さを分かってない開発者が多い 「N+1問題?何ですかそれ?」 と開発者が言おうものなら「喝!」
  • 39. copyright © 2014 kuwata-lab.com all rights reserved ORMでよくあるトラブル ✓ N+1 問題 深刻度:極 ✓ クエリ発行箇所が特定できない問題 深刻度:大 ✓ インデックスつけ忘れ問題 深刻度:中 ✓ select * 問題 深刻度:小
  • 40. copyright © 2014 kuwata-lab.com all rights reserved 「クエリ発行箇所が特定できない問題」とは? スロークエリが検出されても、それがプログラムの どこで発行されたかが分からず手が打てない問題 DBAにとっては、とてもフラストレーションのたまる事案 User.where(gender: "F") .where(deleted: nil) .order_by("name") .all() select * from users where gender = "F" and deleted is null order by name こっち方向は特定できるけど こっち方向が特定できない ;(
  • 41. copyright © 2014 kuwata-lab.com all rights reserved ORM側の対策:SQL ID、クエリID コメントを使って、SQLごとに一意なIDをつける 1つのSQLが複数個所から呼ばれることがあるので、クエリごとにIDをつ けるのが望ましい (注) -- [sql:fg9xk] select * from users /** if (gender) { **/ where gender = :gender /** } **/ User.where(gender: "F") .where(deleted: nil) .order_by("name") .comment("[q:yxe4m]") .all() 多くのORMで未サポート ;( (注) IDのかわりに、呼び出し元のファイル名と行番号でもよい
  • 42. copyright © 2014 kuwata-lab.com all rights reserved DBAが取るべき予防策 ✓ SQL IDが付けられるなら、付けてもらう ✓ 呼び出し元のファイル名と行番号がわかるなら、 SQLコメントやログに記録してもらう ✓ Slow QueryがどのAPIで発行されたかを特定 できるような仕組みを用意する 要は、SQLだけでは特定できないなら別の方向から絞り込む
  • 43. copyright © 2014 kuwata-lab.com all rights reserved ORMでよくあるトラブル ✓ N+1 問題 深刻度:極 ✓ クエリ発行箇所が特定できない問題 深刻度:大 ✓ インデックスつけ忘れ問題 深刻度:中 ✓ select * 問題 深刻度:小
  • 44. copyright © 2014 kuwata-lab.com all rights reserved 「インデックスつけ忘れ問題」とは? そのままの意味 ORMでなくても発生する問題だが、発行されるSQLが具体的でないと explainを実行できないため、ORMだとより発生しやすいといえる User.where(gender: "F") .where(deleted_at: nil) .order_by("created_at") .all() 実行しないとどんなSQLが分かりにくい → explain で調べにくい   → index つけ忘れに気付かない
  • 45. copyright © 2014 kuwata-lab.com all rights reserved ORM側の対策:スキーマ定義で指定 カラムごとにインデックス作成を指定する 複合インデックスも指定できることが多い class User(Base): id = Column(Integer, primary_key=True) name = Column(String(255), nullable=False, index=True) email = Column(String(255), nullable=True, index=True) カラムごとにインデックス作成を
 指定できるので忘れにくい (SQLはこれができないので忘れやすい) 残念ながら、本質的な解決策がない ;(
  • 46. copyright © 2014 kuwata-lab.com all rights reserved DBAが取るべき予防策 ✓ インデックスが必要そうなカラムをリストアッ プし、重点的にチェック ・where で使いそう … 名前, コード, メアド, 生年月日, etc ・order by で使いそう … 名前, 作成日時, 更新日時, etc ・join で使いそう … 外部キー, 多対多の中間テーブル, etc ✓ 大きいテストデータを用意してあげる 小さいデータで開発しているから気付かない、
 大きいデータを用意してあげれば遅いことに気付きやすい
  • 47. copyright © 2014 kuwata-lab.com all rights reserved ORMでよくあるトラブル ✓ N+1 問題 深刻度:極 ✓ クエリ発行箇所が特定できない問題 深刻度:大 ✓ インデックスつけ忘れ問題 深刻度:中 ✓ select * 問題 深刻度:小
  • 48. copyright © 2014 kuwata-lab.com all rights reserved 「select * 問題」とは? ORMが、使わないカラムもすべて select * で取得 してしまう問題。 特にBlobや長いtextでは重大な問題 articles = db.query(Article) for x in articles: print(x.id, x.title) ここでは記事のIDとタイトルしか 必要ないのに、記事の本文まで取 得してしまう →負荷増大 (注)たいていのORMではカラム名を指定できるはずだが、外部キー経由で 取得した関連オブジェクトのカラムまでは指定できない。
  • 49. copyright © 2014 kuwata-lab.com all rights reserved ORM側の対策:遅延フェッチ Blobや長いtextは、デフォルトではselect時に
 除外するよう、ORMのスキーマで指定する 明示的に指定した場合のみ取得する class Article(Base): id = Column(Integer, primary_key=True) title = Column(String, nullable=False, index=True) body = deferred(Column(Text, nullable=False) デフォルトでは select 文で 取得する対象にしない
  • 50. copyright © 2014 kuwata-lab.com all rights reserved DBAが取るべき予防策 ✓ Blobや長いtextは、別テーブルに分離する かわりに N+1 問題が発生する可能性があるので注意すること ✓ 必要なカラムだけを指定したビューを作る 外部キーで参照しているテーブルまでは変えられないので注意 ✓ カラム名の細かい指定はある程度あきらめる パフォーマンス劣化が深刻でなければ許容する
  • 51. ORMと折り合いをつける • • • • ための、DBAの心構え
  • 52. copyright © 2014 kuwata-lab.com all rights reserved 心構えその1:相手を知る ✓ ORMの仕組みを知る 知っていればトラブルに対処しやすい、開発者に提案しやすい
 例:ぐるぐる系SQLが現れた!
 × だからORMは止めよう!
 ◎ eager loadingを使うよう提案しよう! ✓ アプリ開発を知る DBの知識だけで物事を考えない、トラブル対応しようとしない
  • 53. copyright © 2014 kuwata-lab.com all rights reserved 心構えその2:先手を打つ ✓ 問題が起きるまえに対策を講じる 問題が起きてからどうするか?より、問題を起こさないためには どうするか? (「ORMを使わない」というのはなしで ;) ✓ 開発初期から開発チームに助言する(特にN+1問題) 開発終盤になってから文句を言っても手遅れ
  • 54. copyright © 2014 kuwata-lab.com all rights reserved 心構えその3:教えてあげる ✓ 開発者がSQLを知らないなら教えてあげる 一見面倒だが、それで重大なトラブルが減らせるなら安上がり ✓ 開発者からのSQLの相談に乗ってあげる 一見面倒だが、下手にORMだけでやられてトラブるより安上がり
  • 55. copyright © 2014 kuwata-lab.com all rights reserved 心構えその4:心を広く持つ ✓ 最高速度を求めない 必要な速度が出ればそれでよしとする ✓ 最高品質を求めない 必要なサービス品質が提供できればよしとする
  • 56. copyright © 2014 kuwata-lab.com all rights reserved 心構えその5:金を積む ✓ 「SQLのできる開発者」は金を出せば手に入る 札束で頬をひっぱたけばスキルのある開発者を囲えることは、
 GREEやDeNAやLINEが証明してくれました ✓ 金を惜しんでるなら文句を言うべきではない 月20万30万そこそこの人材に多くを求めすぎない (※) (※)たいていのアプリ開発者にとって、SQLは「多く」に含まれることに注意
  • 58. copyright © 2014 kuwata-lab.com all rights reserved まとめ ✓ ORMによるトラブルは (たいてい) 解決策がある ✓ 解決策を知れば嫌悪感は (許容半以内に) 抑えられる ✓ 我々のゴールは「プロジェクトやサービスの
 成功」であることを思い出す (対立することではない)
  • 59. copyright © 2014 kuwata-lab.com all rights reserved Q&A:個人的にお勧めなO/Rマッパーは? ✓ DataMapper (ruby) http://datamapper.org/ Strategic Eager Loadingのような秀逸なアイデアを生み出している ✓ Sequel (ruby) http://sequel.jeremyevans.net/ 使いやすさと簡潔さがよく考えられている印象 ✓ SQLAlchemy (python) http://www.sqlalchemy.org/ 教科書 (PoEAA) に忠実に作られている印象 ✓ 自作!自作マジお勧め! 職人が自分の道具作って何が悪い!車輪の再発明なぞ知らんがな! ActiveRecord?あれはあんまり…
  • 60. copyright © 2014 kuwata-lab.com all rights reserved この資料を読んだ人はこんな資料も読んでます ✓ O/R Mapperを支える技術 http://rubykaigi.org/2011/ja/schedule/details/18S08 ✓ なぜO/Rマッパーが重要か? http://www.slideshare.net/kwatch/sqlor ✓ ORM is an anti-pattern http://seldo.com/weblog/2011/06/15/orm_is_an_antipattern ✓ ORMのパフォーマンス最適化 http://www.infoq.com/jp/articles/optimizing-orm-performance ✓ Patterns Implemented by SQLAlchemy http://techspot.zzzeek.org/2012/02/07/patterns-implemented-by-sqlalchemy/