2006.09.22 Friday
O/R(ORM) マッピングの是非
オブジェクト指向言語を使ったことのあるプログラマなら一度は O/Rマッピングという言葉を聞いた事があるでしょう。
オブジェクトと RDBのレコード間とのインピーダンスミスマッチを解消する手段として用いられ, O/Rマッピングは様々な言語で色々な実装があります。
PHP なら PEAR::DB_DataObject, Java なら Hibernate 等。
O/Rマッピングで SQLレスプログラミング
プログラマには魅力的な響きかもしれません。
でも敢えてハッキリ言いましょう。
O/Rマッピングは悪です。
O/Rマッピングを覚えるくらいなら, SQL や RDBMS を勉強した方がよっぽど良いでしょう。
何故ならば, Webアプリケーションの負荷のほとんどは, データベース部分にあるからです。
オブジェクトと RDBのレコード間とのインピーダンスミスマッチを解消する手段として用いられ, O/Rマッピングは様々な言語で色々な実装があります。
PHP なら PEAR::DB_DataObject, Java なら Hibernate 等。
O/Rマッピングで SQLレスプログラミング
プログラマには魅力的な響きかもしれません。
でも敢えてハッキリ言いましょう。
O/Rマッピングは悪です。
O/Rマッピングを覚えるくらいなら, SQL や RDBMS を勉強した方がよっぽど良いでしょう。
何故ならば, Webアプリケーションの負荷のほとんどは, データベース部分にあるからです。
負荷のことを考慮せずに作成された Webアプリケーションは, 規模が大きくなると応答がどんどん重くなってきます。大抵の場合。
原因は十中八九データベース部分, 効率の悪い SQL でしょう。
見なくても分かります。
それはプログラマが, 表結合の仕組みやインデックスの使われ方等といった RDB の内部動作を理解しないまま SQL を記述しているから。
オブジェクト指向にわりと精通していて, コードを綺麗に記述している中堅の PG でも, 記述している SQL は素人同然という人は結構います。
SQL は Webアプリケーションの核と言っても過言ではありません。
O/Rマッピングはその SQL を自動的に生成し, 実行します。
一番大事な SQL が見えない部分で勝手に実行されるって, 怖くないですか?
本当に効率のいい SQL を実行しているんでしょうか?
テーブルを JOIN して参照する場面も多々あるでしょう。
O/Rマッピングツールは本当に最適な順番でテーブルを JOIN して SQL を実行してくれるのでしょうか?
そんな保証はどこにあるんでしょう?
ブラックボックスであるというのは便利な反面, いざ問題が起こった時に切り分けができなくなります。
でやたらと時間がかかってることが分かったけど, 中で何をやっているのかわからない。
結局は SQL を見ることになるのです。
でも SQL をどうやって直せば速く動くようになるのかが分からない・・・。
O/Rマッピングは SQL を見えなくするだけでなく, プログラマから SQL を, ひいてはデータベースに関して勉強する機会を奪っているのです。
私が O/Rマッピングを悪とする理由はここにあります。
そういったことを全てを分かった上で, 楽をするために O/Rマッピングツールを利用するのはアリだと思います。
負荷を無視した社内用の簡単なツール作成などの場合に限定されますが。
この記事を書こうと思ったきっかけは, WEB+DB PRESS Vol.34 の某記事にあります。
以下, その記事の内容に対してツッコミ。
細かくありません。重要なチューニングですよ。
そんなことはほとんどありません。
あったとしても, データベースの変更に伴う SQL の修正よりももっと多大な労力が他の部分に割かれることになるでしょう。
効率を求めた SQL はそんなに複雑な SQL になりません。至ってシンプルな SQL になるはずです。
そもそも何十行もの SQL文を見たことがありませんし, もしそのような SQL を書かなければならないのであれば, それは単純にテーブル設計が腐っているとしか思えません。
SQLレスだからコードの可読性が高まるのでしょうか?
紹介されている例は, 一つのプログラムファイルで DBアクセスから HTML出力まで何でもやっている大昔の PHPプログラムでしょう?
今時そんな例を取り上げて可読性云々という話をされても困ります。
そうだとしても, その代償は遥かに大きなものになると思います。
...その他もツッコミ所満載ですが, ツッコミ疲れたのでこの辺で。
O/Rマッピングは EJB が 2.0 だった頃からありました。
少なくとも私がバイトで初めて EJB 2.0 を触ったときは O/Rマッピングで SQLレスでした。
CMPエンティティBean を作成すると EJBコンテナが勝手にトランザクション管理までやってくれる, プログラマにとっては一見ありがたいものでした。
正直な所, 当時の私も EJB の SQLレス実装に共感していた部分があります。
でもそうやってコードを書いていざデータ投入してテストすると, 重くて使い物にならない代物ができてしまいました。
コンテナが発行する SQL が遅すぎてどうにもならなかったのです。
結局, 多くの部分を BMPエンティティBean に変更し, 直接 SQL を記述する羽目になりました。
その頃から比べると, O/Rマッピングツールが生成する SQL は効率が良くなっているかも知れません。
が, 完璧な翻訳ソフトが出来ないように, O/Rマッピングツールが生成する SQL にも効率には限界があるでしょう。
O/Rマッピングの利点はただ一つ。
「SQL を書かなくて済むから楽」
それだけです。
そしてその利点を得るために被るデメリットは計り知れません。
まずはデータベースについてきちんと勉強しましょうよ。
追記)
O/Rマッパーの話 にて, O/Rマッピングについてもっと深く掘り下げたエントリがあります。
技術者の方は見ておくと良いです。
賛否はどうあれ考えることが大事だと思いますので。
とのはてブコメントを頂きましたので, この二つのライブラリについてどんなことが出来るのかを軽く調べてみました。
Ruby の Active Record は SQL の断片が所々に出てきていて, SQL全体がどのように記述されていないか分からなくて気持ち悪いなぁ, という印象。
これだと RDBMS に応じた SQLのチューニングが出来ないんじゃないでしょうか。
今までの O/Rマッパーと大きな違いがないように思えます。
(それとも, 何か ActiveRecord ならではって機能がついているのでしょうか?)
S2Dao は SQL全体を記述できるようになっているようですね。
概要にも『SQLプログラマとJavaプログラマの分業した作業が可能』とありますし, S2Dao で Daoクラスのスケルトンを生成して, それより下の層で SQLプログラマが SQL をゴリゴリと記述するような感じで進められればいいのではと思います。
(PHPでの開発時には, 最終的には PHP担当と SQL担当を分業するこのやり方に落ち着きました。)
原因は十中八九データベース部分, 効率の悪い SQL でしょう。
見なくても分かります。
それはプログラマが, 表結合の仕組みやインデックスの使われ方等といった RDB の内部動作を理解しないまま SQL を記述しているから。
オブジェクト指向にわりと精通していて, コードを綺麗に記述している中堅の PG でも, 記述している SQL は素人同然という人は結構います。
SQL は Webアプリケーションの核と言っても過言ではありません。
O/Rマッピングはその SQL を自動的に生成し, 実行します。
一番大事な SQL が見えない部分で勝手に実行されるって, 怖くないですか?
本当に効率のいい SQL を実行しているんでしょうか?
テーブルを JOIN して参照する場面も多々あるでしょう。
O/Rマッピングツールは本当に最適な順番でテーブルを JOIN して SQL を実行してくれるのでしょうか?
そんな保証はどこにあるんでしょう?
ブラックボックスであるというのは便利な反面, いざ問題が起こった時に切り分けができなくなります。
$o->find();
でやたらと時間がかかってることが分かったけど, 中で何をやっているのかわからない。
結局は SQL を見ることになるのです。
でも SQL をどうやって直せば速く動くようになるのかが分からない・・・。
O/Rマッピングは SQL を見えなくするだけでなく, プログラマから SQL を, ひいてはデータベースに関して勉強する機会を奪っているのです。
私が O/Rマッピングを悪とする理由はここにあります。
そういったことを全てを分かった上で, 楽をするために O/Rマッピングツールを利用するのはアリだと思います。
負荷を無視した社内用の簡単なツール作成などの場合に限定されますが。
この記事を書こうと思ったきっかけは, WEB+DB PRESS Vol.34 の某記事にあります。
以下, その記事の内容に対してツッコミ。
直接SQLを書くことも細かなチューニングやデバッグ時には必要なことですが
細かくありません。重要なチューニングですよ。
途中でデータベースを変更したいといった場合にはどうでしょうか
そんなことはほとんどありません。
あったとしても, データベースの変更に伴う SQL の修正よりももっと多大な労力が他の部分に割かれることになるでしょう。
いかに効率よくデータを取得できるかというということの方が優先され, その結果, 何十行という非常に複雑な SQL文がプログラム内に貼り付けられることになるのです。
効率を求めた SQL はそんなに複雑な SQL になりません。至ってシンプルな SQL になるはずです。
そもそも何十行もの SQL文を見たことがありませんし, もしそのような SQL を書かなければならないのであれば, それは単純にテーブル設計が腐っているとしか思えません。
O/RマッピングツールはSQLレスなコードとなることによってコードの可読性を高め
SQLレスだからコードの可読性が高まるのでしょうか?
紹介されている例は, 一つのプログラムファイルで DBアクセスから HTML出力まで何でもやっている大昔の PHPプログラムでしょう?
今時そんな例を取り上げて可読性云々という話をされても困ります。
SQL文の生成をO/Rマッピングツールに委譲することにより, 特定のデータベース環境に依存しないアプリケーションを意識せずに開発できる
そうだとしても, その代償は遥かに大きなものになると思います。
...その他もツッコミ所満載ですが, ツッコミ疲れたのでこの辺で。
O/Rマッピングは EJB が 2.0 だった頃からありました。
少なくとも私がバイトで初めて EJB 2.0 を触ったときは O/Rマッピングで SQLレスでした。
CMPエンティティBean を作成すると EJBコンテナが勝手にトランザクション管理までやってくれる, プログラマにとっては一見ありがたいものでした。
正直な所, 当時の私も EJB の SQLレス実装に共感していた部分があります。
でもそうやってコードを書いていざデータ投入してテストすると, 重くて使い物にならない代物ができてしまいました。
コンテナが発行する SQL が遅すぎてどうにもならなかったのです。
結局, 多くの部分を BMPエンティティBean に変更し, 直接 SQL を記述する羽目になりました。
その頃から比べると, O/Rマッピングツールが生成する SQL は効率が良くなっているかも知れません。
が, 完璧な翻訳ソフトが出来ないように, O/Rマッピングツールが生成する SQL にも効率には限界があるでしょう。
O/Rマッピングの利点はただ一つ。
「SQL を書かなくて済むから楽」
それだけです。
そしてその利点を得るために被るデメリットは計り知れません。
まずはデータベースについてきちんと勉強しましょうよ。
追記)
O/Rマッパーの話 にて, O/Rマッピングについてもっと深く掘り下げたエントリがあります。
技術者の方は見ておくと良いです。
賛否はどうあれ考えることが大事だと思いますので。
その反省から出てきたORMライクなライブラリがS2DAOであり、ActiveRecordなんだな
とのはてブコメントを頂きましたので, この二つのライブラリについてどんなことが出来るのかを軽く調べてみました。
Ruby の Active Record は SQL の断片が所々に出てきていて, SQL全体がどのように記述されていないか分からなくて気持ち悪いなぁ, という印象。
これだと RDBMS に応じた SQLのチューニングが出来ないんじゃないでしょうか。
今までの O/Rマッパーと大きな違いがないように思えます。
(それとも, 何か ActiveRecord ならではって機能がついているのでしょうか?)
S2Dao は SQL全体を記述できるようになっているようですね。
概要にも『SQLプログラマとJavaプログラマの分業した作業が可能』とありますし, S2Dao で Daoクラスのスケルトンを生成して, それより下の層で SQLプログラマが SQL をゴリゴリと記述するような感じで進められればいいのではと思います。
(PHPでの開発時には, 最終的には PHP担当と SQL担当を分業するこのやり方に落ち着きました。)









Comments
ぼくは、2006年頃に、大手プロバイダが運営するSNSサイトをHibernateを用いて構築し、実用的な性能は確保できておりました。。
その経験からですが、ORマッピングフレームワークを使うことが、イコール性能の悪いSQL文の発行と決めつけるのは、間違ってると思います。
Hibernateに関して言えば、オブジェクトと、DB構造の対応付けについて、細かく制御することができ、ある程度Hibernateの設定で発行するSQLを制御することができます。
また、どうしても性能の改善が必要な場合には、部分的にフレームワークが発行するSQL文の最適化を行う為の枠組みも開発者は利用する事ができます。
全てのプロジェクトに於いて、ORマッピングフレームワークが有効とは言えないと思いますが、頭ごなしにORマッピングフレームワークを否定される上記の記事は、よろしくないかと思います。
データを集合として扱う場合⇒SQL or ストアド
でOK?
おっしゃる通り, O/Rマッピングツールを安易に使用することが危険, ということがこの記事で言いたかったことです。
O/Rマッピングそのものの考え方自体は私も肯定しますし, 実際のコーディングでも DAO の層は設けます。
本文でも述べていますが, 世のツールは開発効率の良さ, 便利さだけのいい面が取り沙汰されて, 裏にあるデータベースのパフォーマンスについて一切触れられていない所を懸念しています。
データベースについてきっちり考えているのであれば問題ないかと。
自社フレームワークでDataAccessObjectパターンを使っています。
DAOに関しては「ORマッピングしましょう」と詠っています。
つまりオブジェクトとRDBMSのインピーダンスマッチをDAOで必死に埋めましょう、と。
HibernateなどのORマッピングツールを使用するのではなく、ビジネスロジックから
永続データへのアクセスロジックを分離して層を分けたというイメージです。
クラス内では、各テーブルを結合して検索したり、それをオブジェクトに詰めて
返したりと、お手製のORマッピングをゴリゴリ書く事になり、
当然の事ながらSQL文の質は非常に重要になってきます。
ビジネスロジックがRDBMSの実装に依存しない事は私は素晴らしい事だと
思っていて、そのためにORマッピングという考え方が必要になってくると
思っています。
この記事は「O/Rマッピングが悪い」という事ではなく「O/Rマッピングツールを
安易に適用する事はリスキー」と読み替えていますが、そういう認識で
宜しいでしょうか?それともO/Rマッピングという概念自体が悪なのでしょうか?
コメントありがとうございます。
“面倒なコト”を極力無くそうとする思想自体は私も大賛成ですし, プログラマとしてそうあるべきだと思います。
このエントリで私が言いたいのは, O/Rマッピングを妄信的に信じるような今の風潮が(特にプログラミング初心者にとっては)よくないということです。
O/Rマッピングツールでアプリケーションを効率よく作成したものの, データ量が増えるにつれて使い物にならなくなるパターンは往々にしてあると思います。
そして結局, 原因調査と対応にコストを割くことになります。
O/Rマッピングの DBの層を考えなくてもいいから楽チンだよ, というキャッチフレーズだけが一人歩きして, パフォーマンスについてはないがしろにされている所に危機感を感じているのです。
>『怠惰な者は寝椅子の上で回転し続ける』ので、このような啓発は重要なんだと思います。
これに関しては全く同意ですし, そうすることで色々な技術が進歩してきました。また, これからも進歩するのでしょう。
エントリでは O/Rマッピングそのものを“悪”としてしまいましたが, こういった思想の面では大いに賛同します。
ただ, 現時点での O/Rマッピングツールには, 便利さの代償として対価を支払っているという注意喚起は必要なのではないでしょうか。
CPUやメモリが十分に高速になって, データベースの数百万/数千万レコードの演算や集計が瞬時に行えるようになれば O/Rマッピングは十分に使えるものです。
でも O/Rマッピングを使うにあたり, 今のリソースには限りがあります。
昔のプログラマがメモリの節約で悩んだようなことが, データベース部分でも求められることがあるでしょう。
その部分を意識して O/Rマッピングを使っているかどうか, ということが大事だと思います。
> あと蛇足ですが、RoRをわざわざ使う好き者にSQLの分からん奴など居ないとおもいます。
ここで言っている SQL は SQL そのものではなくて, この SQL を発行したら RDBMS内部ではどのようにデータが結合されて結果が返されるのか, という内部の動作までの理解を含んでいます。
単に GROUP BY や副問い合わせを使って結果を出すということではなく, そのクエリが内部的にどのように動作してコストがどのくらいかかるのかという所まで考慮したものです。
個人的に反論。
この記事を読むと「アーキテクチャの差をしっかり吸収できないからCじゃなくてアセンブラを使おうよ」という議論にも聞こえます。
そもそも思想が全く異なるのであって、『チューニングなんかうざいんじゃあ』とぶち切れた怠惰なプログラマ共が作り上げたのがR/Oマッピングです。
そんな彼らにとってこの記事は褒め言葉にすぎないと思います。
なんたって彼らはCPUのコストを度外視して、ただ表面の美しさのためのみにevalを多用する人種ですから。
そしてそんな彼らが確かに一定の成果を収めているという事実は、一つの方向性を示していると思います。
確かに信頼性の必要な場面では、綿密な設計や適切なチューニングが求められるわけですが、そんなのみんな知っています。そのための『適材適所』なんです。
時代は間違いなくプログラマがプログラミングを放棄する方向へと向かっていきます。そしてそれは正しい方向です。だって面倒ですから。そんな時代への橋渡しの一つがR/Oマッピングではないでしょうか。
確かにR/Oの実装は醜い。そう長く続く概念ではないでしょう。でもR/Oが死ぬ日はRDBが潰えるときだと思います。そして俺達はR/Oを糧にして前進するんです。
「確かにEmbeddedにはasは必要だろう。
でも俺達は重くったってrubyを使うんだ。」
でも『怠惰な者は寝椅子の上で回転し続ける』ので、このような啓発は重要なんだと思います。
あと蛇足ですが、RoRをわざわざ使う好き者にSQLの分からん奴など居ないとおもいます。
まあ色々あって、個人の内職を研究の出発点にしたという感じ。
まだあんまし成果出てないけど。
こちらも近況とか聞きたいし、近々セッティングしますか。
捨てアドさらしたので、よければメール下さいな。
誰だか分かっておりますですよ。
O/Rマッピングの研究ということは, あの管理画面自動生成ツールがきっかけなんでしょうか?
> クラスからSQLが自動生成されるというのは、確かに現場を知らぬ人間の絵空事なんだよねぇ。
研究者の立場からもそのように感じているってことは, やっぱり“真のSQL”自動生成ってのはかなり難しいんでしょうね。
> JOIN のセットを予め定義してクラスを生成しておき、
> それに対して SQL の差し替えを可能にする...という方向で設計中。
ここら辺の話, 詳しく聞いてみたいですね。
近況も含めて一度, 飲みにでも行きたい感じですねぇ。
(って誰かわかるかしら?)
実は現在、そのO/Rマッピングをネタに研究しております。
クラスからSQLが自動生成されるというのは、確かに
現場を知らぬ人間の絵空事なんだよねぇ。
JOIN をメソッド呼び出しで実現してしまう手法も嫌。
JOIN のセットを予め定義してクラスを生成しておき、
それに対して SQL の差し替えを可能にする...という
方向で設計中。
(まだ差し替えはできない。他にも課題は多し)
リレーショナルモデルを過去の遺物として決め付ける現在の流行のやり方は、
結局歴史の繰り返しのような気がするな。
理想としては、SELECT文からクラスを自動生成できると良いねぇ。