This is a cache of http://dbflute.seasar.org/ja/manual/function/ormapper/conditionbean/sidebar/pagingselectandquerysplit.html. It is a snapshot of the page at 2024-03-19T00:31:59.757+0000.
Paging<strong>s</strong>electAndQuery<strong>s</strong>plit | <strong>dbflute</strong>

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 になっています。将来的に削除されるわけではありませんが、"安易に使ってくれるな" ということを示します。