[Seasar-user:16120] Re: [S2JDBC] innerJoin と leftOuterJoin で同じ Entity を指定したい

Koichi Kobayashi [E-MAIL ADDRESS DELETED]
2008年 10月 27日 (月) 05:30:19 JST


小林 (koichik) です.

Date:    Mon, 27 Oct 2008 03:24:46 +0900
From:    Shotaro Tsubouchi <[E-MAIL ADDRESS DELETED]>
To:      [E-MAIL ADDRESS DELETED]
Subject: [Seasar-user:16117] Re: [S2JDBC] innerJoin と leftOuterJoin で同じ Entity を指定したい

> 等価ではありますが、パフォーマンス面を考えると、
> 意図は明確なのかもしれませんが、副問い合わせという選択は微妙に思えます。
> (最近のRDB事情に詳しくないので、的を得てない言及だったらごめんなさい。)

古い RDBMS っていうか古い Oracle だと,EXISTS は
インデックスさえ使われれば速かったですよ.
事実上結合しないので.
っていうか,inner join とか使えるようになったのは
Oracle だと (たしか) 9iR2 からで,結構新しいです.

> フェッチしない結合を WHERE で扱えている、というのは、
> これは、タイプセーフな記述ではないが、扱うことは可能という事でしょうか?

タイプセーフというのは S2JDBC-Gen が生成する
クラスを使った場合の話ですよね.
そういうことではなく,ここで書いたのは,S2JDBC
そのものの API の話です.

元々 S2JDBC としては innerJoin() 等で
追加の条件を指定することができなかったので,
例えば id が 1 の BAA を持っている FOO を
(BAA をフェッチせずに) 取得するには

select() // jdbcManager.from(Foo.class)
    .innerJoin(baaList(), false)
    .where(eq(baaList().id(), 1))
    .getResultList();

と where() で指定するしかなかったのです.
当時は SimpleWhere を使ったので

select() // jdbcManager.from(Foo.class)
    .innerJoin(baaList(), false)
    .where(new SimpleWhere().eq("baaList.id", 1))
    .getResultList();

となりますが,同じことです.
これがフェッチしない結合を where で扱えていると
いうことです.
innerJoin() で追加の条件を指定できるように
なったのは 2.4.22 からなので,それ以前から
使っていた人達はこういう指定をしているわけです.

> 今でも WHERE でやろうと思えばやれるが、
> JOIN でなら、重複さえ許せばタイプセーフでそのまま実現できるのではないか?
> ということが私の言いたいことです。
> (このことが全体的なパフォーマンス劣化に如実に影響するということなのであれば。
> 無理強いはしません。)

パフォーマンスは関係なくて,仕様の互換性と
整合性,わかりやすさの問題です.

> これを許してしまうと、
> WHERE で使えなくなったり、重複した時に使えなくなったりする、というのは
> どういう場合なのでしょうか?

select() // jdbcManager.from(Foo.class)
    .innerJoin(baaList(), false)
    .innerJoin(baaList())
    .where(eq(baaList().id(), 1))
    .getResultList();

と書かれた時の baaList().id() の解釈の問題です.
フェッチしない結合は where() で使えないことに
すれば 2 番目の結合であることが一意に決まりますが,
前述のように互換性を損ないます.

重複した時だけ,フェッチしない結合を where で
使えないことにすると,いかにも落とし穴のように
思えます.
上の例で,baaList().id() が下の innerJoin の
ものだとすぐに理解できるでしょうか?

> leftOuterJoin なのであれば結合条件だけど、
> innerJoin であるならば選択条件でしょ、ということですね。

全然違います.
結合そのものの条件は JOIN ON に書くべきで,
それを結合条件と書きました.
行を選択して減らす,そのための条件は WHERE 句で
書くべきで,それを選択条件と書きました.
そういう違い.inner/outer の違いは関係ありません.
結合条件とか選択条件とか勝手な用語を使ったのは
失敗でしたね.

わざとらしい例で言うと,名前を指定して従業員を
選択するのに,

select e1.*
from employee e1
  inner join employee e2 on e1.id = e2.id and e2.name = 'HOGE'

なんて書かないですよね?

select *
from employee
where name = 'HOGE'

って書きますよね?
ここで name = 'HOGE' は選択のための条件です.
「ID が 1 の Baa を持っている Foo」というのも
これと「全く」同じで,選択のための条件です.



-- 
<component name="koichik">
    <property name="fullName">"Koichi Kobayashi"</property>
    <property name="email">"[E-MAIL ADDRESS DELETED]"</property>
    <property name="blog">"http://d.hatena.ne.jp/koichik"</property>
</component>



Seasar-user メーリングリストの案内