OnClause
概要
基本概念
リレーションの結合における、on 句での絞り込み条件を設定します。
例えば、"会員ステータスの表示順が 2 であること" という条件があったとして、通常の Query では、この条件は where 句に展開されます。それを、where 句ではなく、結合(join)の on 句に展開されるようにできます。この場合、検索結果は大きく異なります。
- where 句
- 表示順が 2 のステータスに関連付く会員のみ検索対象
- on 句
- 表示順が 2 のステータスのみが会員と結合される(会員は全て検索対象)
on 句での絞り込みは、言わば "結合時に結合先テーブルだけを絞り込む" と捉えることができます。(実行計画の内部的な挙動と一致するかどうかは別にして)
これにより、DB構造上は {n : 1} 型リレーションでも、SQL上では(一時的な) {n : 0...1} 型リレーションになります。 例えば、SetupSelect をした場合、基点テーブルの Entity は on 句で絞り込まれた関連テーブルのデータを持っていません(null になる)。
会話上では、おんくろーず と表現します。
論理削除との相性
主に、{n : 0...1} 型リレーションで関連テーブルに論理削除の概念がある場合に役に立ちます。OnClause を使えば、結合前に論理削除されているレコードを除外することができます。
InlineView でも実現可能
InlineView でも同じことが実現できます。
実装方法
実装の流れ
query().query[relation]() の後、on() を呼び出し、その後続けて、関連テーブルの Query (絞り込み条件)を実装します。
e.g. OnClauseの実装手順 (Eclipseでコード補完) {MemberStatus} @Java
MemberCB cb = new MemberCB();
cb.query().queryMemberStatus().on // .on と打って enter
--
cb.query().queryMemberStatus().on().setDisplayOrder_Equal(2);
e.g. 会員ステータスの表示順が 2 のものだけを結合 @DisplaySql
...
from MEMBER dfloc
left outer join MEMBER_STATUS dfrel_0
on dfloc.MEMBER_STATUS_CODE = dfrel_0.MEMBER_STATUS_CODE
and dfrel_0.DISPLAY_ORDER = 2
メソッド仕様
リレーションに対してのみ利用
リレーションに対してのみ利用できます。基点テーブルの Query で呼び出した場合は例外です。
他の機能との組み合わせ
他の機能との組み合わせは以下の通りです。
- OrScopeQuery は利用可能
- ColumnQuery は不可
- ExistsReferrer, (Query)DerivedReferrer などのサブクエリは不可
OnClause と InlineView どちら?
OnClause だけでなく、InlineView でも同じことを実現できます。さて、どちらを使えば良いのでしょうか?
他の機能との組み合わせで若干 InlineView の方が自由度が高いため、その制約に該当する場合は、InlineView で良いでしょう。但し、そういうパターンよりも、"もうどっちでもいい" というパターンの方が多いでしょう。そういう場合はやはりパフォーマンス勝負となります。
結局は、OrScopeQuery と UnionQuery の話と同様で、そのとき実行計画を調べて速い(と思われる)方を使うに尽きます。 大抵の場合はパフォーマンス上の違いは出ないでしょう。実際に、Exampleで100万件のデータを使って幾つかのパターンを試しましたが(PostgreSQL 8.4, Oracle 10g Xe)、全く差が見られません。それでも一応、DBFluteでは、基本を OnClause に置くことをお奨めしています。万が一のインラインビューでフルスキャンが発生するリスクを考えてのことです。 また、実装がバラバラになるのも良くないというのもあるので、とにかく OnClause を基本として、パフォーマンス的な改善が見込めるようであれば InlineView というスタンスが落としどころでしょうか。