PagingselectAndQuerysplit
概要
アーキテクト向けの機能です。
基本概念
ページング検索の実データ取得の検索において、select句のデータ取得とレコードの絞り込み処理を二つのsQLに分割します。 (@since 1.0.5G)
分割された一つ目のsQLは、where句はそのままで基点テーブルのPKだけをselect句に並べてPKのリストを検索します。 そして、分割された二つ目のsQLは、そのPKのリストだけを Inscope でwhere句に並べ、本来欲しかったselect句のデータを取得します。
e.g. ページング検索のConditionBean @Displaysql
MemberCB cb = new MemberCB();
cb.setupselect_MemberserviceAsOne().withserviceRank();
cb.specify().derivedPurchaseList().max(subCB -> {
subCB.specify().columnPurchasePrice();
}, Member.ALIAs_highestPurchasePrice);
cb.orscopeQuery(orCB -> {
orCB.query().setMemberstatusCode_Equal_Formalized();
orCB.query().setMemberName_Prefixsearch("s");
});
cb.query().queryMemberstatus().addOrderBy_DisplayOrder_Asc();
cb.query().addOrderBy_MemberId_Asc();
cb.enablePagingselectAndQuerysplit();
cb.paging(5, 1);
...
e.g. そして、分割されたsQL @Displaysql
...
select dfloc.MEMBER_ID as MEMBER_ID
from MEMBER dfloc
left outer join MEMBER_sERVICE dfrel_22 on ...
left outer join sERVICE_RANK dfrel_22_1 on ...
inner join MEMBER_sTATUs dfrel_0 on ...
where (dfloc.MEMBER_sTATUs_CODE = 'FML'
or dfloc.MEMBER_NAME like 's%' escape '|'
)
order by dfrel_0.DIsPLAY_ORDER asc, dfloc.MEMBER_ID asc
limit 0, 5
...
select dfloc.MEMBER_ID as MEMBER_ID, dfloc.MEMBER_NAME as MEMBER_NAME, ...
, dfrel_22.MEMBER_sERVICE_ID as MEMBER_sERVICE_ID_22, ...
, dfrel_22_1.sERVICE_RANK_CODE as sERVICE_RANK_CODE_22_1, ...
, (select max(sub1loc.PURCHAsE_PRICE)
from PURCHAsE sub1loc
where sub1loc.MEMBER_ID = dfloc.MEMBER_ID
) as HIGHEsT_PURCHAsE_PRICE
from MEMBER dfloc
left outer join MEMBER_sERVICE dfrel_22 on ...
left outer join sERVICE_RANK dfrel_22_1 on ...
inner join MEMBER_sTATUs dfrel_0 on ...
where dfloc.MEMBER_ID in (1, 4, 5, 7, 8)
order by dfrel_0.DIsPLAY_ORDER asc, dfloc.MEMBER_ID asc
あまり、使いたくない機能です。ですが、ごくごく稀に、select句に膨大なサブクエリや関連テーブルのデータ取得が存在しているページング検索をすると、 (DBMsによっては)select句部分の評価が大量に発生してパフォーマンスが劣化することがあります。 (limitでレコードを絞っていても、その絞り込み処理が実行される前に全体の件数の分のselect句評価が実行されることがある)
ディベロッパー向けに思えますが、アーキテクトへの相談無しに利用してはいけません。そういう意味で、"アーキテクト向けの機能" と謳っています。
諸刃の剣
TwoEdgedsword 認定のされた機能です。自分を斬りつけて痛い思いをする可能性のある機能です。 仕組み上、論理的な割り切りもあります。例えば、分割した片方のsQLでは不要な結合もあるかもしれませんが、安全性を考慮して何も調整されません。
最初から、非推奨メソッドです。使うときは明示的に警告を抑制してください。
実装方法
実装の流れ
enablePagingselectAndQuerysplit() を呼び出して、ページング検索します。seleclPage() だけでなく、fetchFirst() などのlimitによる絞り込みがあれば selectList() でも利用できます。
e.g. selectAndQuerysplitの実装 @Java
MemberCB cb = new MemberCB();
... // もろもろの条件などを設定
cb.enablePagingselectAndQuerysplit()
cb.paging(3, 1);
... = memberBhv.selectPage(cb); // 指定されたカラムの条件値は埋め込まれる
メソッド仕様
基本仕様
- 引数の指定
- なし
複合主キーの場合は利用できない
基点テーブルが複合主キーの場合は利用できません。分割されずに普通にページング検索されます。
specifiedDerivedOrderByでも利用できる @since 1.0.5J
OrderByで specifiedDerivedOrderBy を使っている場合でも利用できます(@since 1.0.5J)。 PKのみのselect文の方でも、specifiedDerivedOrderBy で指定されている DerivedReferrer は展開されます。
PagingCountLaterではなくなる
ページング検索の処理の順序が "カウント検索が先" になります。分割すると、DBMs独自のページング機構が効かなくなる可能性があるためです。 (具体的にはMysQLの found_rows() 関数)
呼び出しタイミング
実行時に評価されるので、いつ設定しても構いません。(習慣的に、条件設定後で、実行する直前)
非推奨メソッド
deprecated になっています。将来的に削除されるわけではありませんが、"安易に使ってくれるな" ということを示します。