Pega Report Definition パフォーマンス設計|Join・サブレポート・列最適化の判断
Report Definition は書けば動きますが、結合とフィルタの設計を誤ると本番データ量で一気に遅くなります。鍵は「公開列で結合・フィルタ・ソートしているか」——BLOB 内の未公開プロパティを条件にした瞬間、全行展開のスキャンに落ちます。本記事では Join とサブレポートの使い分け、集約とインデックス、列最適化の判断基準を実務目線でまとめます。
結論から:条件・結合・ソートは必ず「公開列」で行う
Pega の Report Definition は、ドラッグ&ドロップで列を並べればとりあえず動きます。ところが、開発環境の少量データでは一瞬で返っていたレポートが、本番のデータ量になった途端に数十秒かかる——これは Pega の性能相談で最も多いパターンの一つです。
原因のほとんどは1点に集約されます。
結合・フィルタ・ソートを「公開列(exposed column)」で行っているか。BLOB 内の未公開プロパティを条件にした瞬間、レポートは全行を展開して評価するスキャンに落ちる。
Report Definition は、対象クラス(=データベース上のテーブル)に対して SQL として実行されます。だからこそ「データベースが索引で効率的に絞り込める形になっているか」が性能を決めます。この記事では、公開列という土台の上で、関連データの結合(Class Join かサブレポートか)、集約(Group By と WHERE/HAVING の区別)、埋め込みプロパティ(Declare Index)をどう設計するかを、実案件の判断として整理します。
Report Definition は「対象クラス」に対して実行される
まず前提を揃えます。Report Definition は、選んだ 対象クラス(Applies To)=背後のテーブル に対して1本の SQL を組み立てて実行するルールです。列の表示・フィルタ・ソート・集約は、最終的にこの SQL に翻訳されます。つまり、レポートの速さは「その SQL がデータベースの索引を使って効率よく絞り込めるか」でほぼ決まります。
対象クラス1つで完結するレポートは素直です。難しくなるのは、別クラスの関連データを一緒に見たいときです。Pega ではこれを2つの方法で表現します。ひとつは Association を使った Class Join、もうひとつは サブレポート(Sub-report) です。この使い分けが設計の分岐点になります。
関連データの結合 — Class Join かサブレポートか
Association による Class Join(既定の選択)
関連先クラスの 属性そのものをレポートに引きたい(列に出す、フィルタ条件に使う、ソートに使う)場合は、Association を土台にした Class Join を選びます。
Association ルール(Rule-Obj-Association)は「このクラスとあのクラスは、このキーでつながっている」という関係の宣言です。一度定義しておけば、Report Definition では関連先の列を宣言的に選ぶだけでよく、レポートごとに結合条件を手で書く必要がありません。生成される SQL には Pega が適切な JOIN を追加します。「取引先の与信ランクでフィルタ」「担当営業名を列に出す」といった、関連先の値を直接使う要件はこちらが基本です。
サブレポート — 存在判定・集約フィルタ・相関条件に向く
一方、サブレポートは「レポートの中に別のレポートを埋め込む」仕組みで、次のような 属性を並べて表示する以外の用途 に向きます。
- EXISTS 型の存在判定 — 「未完了の子ケースが1件でもある親ケースだけを出したい」のように、関連先の存在有無で親行を絞る
- 集約してから比較する条件 — 「明細合計が100万円を超える注文だけ」のように、関連先を集約した結果で親を絞る
- 相関条件 — 親行ごとに関連先を評価する必要がある条件
サブレポートは強力ですが、多用するとコストが増えます。とくに相関サブレポート(親行の値を参照して評価するもの)は、一般に親行ごとにサブクエリが評価される形になりやすく、件数が増えると効いてきます(Pega Academy も相関サブクエリについて「行ごとに別クエリが実行されることを意味し得る」と述べています。ただし近年のデータベースはオプティマイザがサブクエリを unnest して緩和することもあり、実際のコストは DB とバージョンに依存します)。いずれにせよ、「関連先の属性を単に列に並べたいだけ」なのにサブレポートを使うのは典型的な過剰設計です。Pega の公式トレーニングも「サブレポートで Class Join と同じ結果集合が得られるなら、より単純で直接的な Class Join を使うべき」と明言しています。サブレポートは「存在判定・集約値との比較・相関条件」という、Class Join では素直に書けない条件に限定して使うのが実務の型です。
| 判断ポイント | Class Join(Association) | サブレポート |
|---|---|---|
| 主な用途 | 関連先の属性を列・フィルタ・ソートに使う | 存在判定・集約フィルタ・相関条件で親を絞る |
| 典型パターン | 名称・区分・数値を関連先から引く | EXISTS、合計 > 閾値、親行ごとの相関評価 |
| 定義の再利用 | Association を複数レポートで再利用できる | レポート内に個別に組む |
| コスト特性 | 索引が効けば軽い | 親件数に比例して重くなりやすい |
| 多用時の注意 | 結合列が公開列であることが前提 | 多用は避け、限定的に |
集約レポートの設計 — Group By と WHERE/HAVING の区別
集計レポートは、Group By(グルーピング列) と 集計関数(Count / Sum / Avg / Max / Min) で組み立てます。ここで設計を誤りやすいのが、2種類のフィルタの区別です。
- 行フィルタ(WHERE 相当) — 集計する前に、対象となる行そのものを絞る条件。例:「今年度のレコードだけを集計対象にする」
- 集計後フィルタ(HAVING 相当) — 集計した結果に対して絞る条件。例:「グループごとの合計が100万円を超えるグループだけ表示」
この2つは実行される順序が違います。行フィルタは集計前に効くので、そもそも集計対象を減らして軽くなります。集計後フィルタは集計してからでないと判定できません。したがって、先に落とせる条件は必ず行フィルタ(WHERE 側)に置く のが鉄則です。「合計が閾値以上のグループだけ」のような、集計結果に依存する条件だけを集計後フィルタ(HAVING 側)に回します。
| 観点 | 行フィルタ(WHERE 相当) | 集計後フィルタ(HAVING 相当) |
|---|---|---|
| 効くタイミング | 集計の前(行を絞る) | 集計の後(グループを絞る) |
| 使う条件 | 個々の行で判定できるもの | 集計値に依存する(合計・件数など) |
| 性能上の狙い | 集計対象を減らして軽くする | 集計結果の絞り込み |
| よくある誤り | ここに置ける条件を後段に回して遅くする | 行で判定できる条件をここに書く |
両方に置けてしまう条件を集計後フィルタに書いてしまうと、無駄に多くの行を集計してから捨てることになります。「その条件は集計前に落とせないか?」を一度自問するだけで、集約レポートの多くは軽くなります。
埋め込みプロパティを対象にするなら Declare Index
Pega ではケースの中に ページリスト(明細行のような繰り返し構造) を持たせることがよくあります。この埋め込みプロパティを条件にレポートしたい——たとえば「明細行のどれかが特定ステータスのケースを探す」——というとき、ページリストは BLOB の中に格納されているため、そのままではレポートで効率的に扱えません。
ここで使うのが Declare Index(宣言的インデックス) です。Declare Index を定義すると、埋め込みプロパティの各要素を 別の索引テーブルに1行ずつ展開 して保持できます。レポートはこの索引テーブルに対して実行できるようになり、公開列としてフィルタ・結合・ソートが可能になります。
ページリストや繰り返し構造に対する検索・集計要件が出てきたら、「Declare Index が要るサイン」と捉えてください。索引テーブルを持たずに BLOB 内の繰り返しプロパティを条件にすると、後述の全行展開スキャンに直行します。
公開列と未公開プロパティ — なぜ BLOB 条件は遅いのか
ここが本記事の核心です。Pega のインスタンスは、主要な列以外のプロパティを BLOB(Storage Stream) としてまとめて1カラムに格納しています。プロパティを 公開列(exposed column) にする(列最適化する)と、その値が独立した1カラムとして持たれ、データベースの索引・フィルタ・ソート・結合の対象になります。
逆に、未公開のまま BLOB の中にあるプロパティ を条件にすると、データベースは索引で絞り込めません。全行の BLOB を取り出して展開し、1行ずつ中身を評価する——実質的な 全行スキャン になります。開発環境の数十件なら一瞬でも、本番の数十万件では致命的に遅くなります。
対策は明快で、フィルタ・結合・ソートに使うプロパティを公開列にする(列最適化する) ことです。Pega には対象プロパティを列化する仕組み(列最適化のウィザードやプロパティ最適化の操作)が用意されています。ただし、ツールの正確な名称・起動場所・手順はプラットフォームのバージョンによって異なる ため、実装時は対象バージョンの公式ドキュメントで確認してください。ここで押さえるべき原則は「レポートで条件・結合・ソートに使う列は、事前に公開列にしておく」——この一点です。
よくある失敗
Report Definition の性能問題は、経験上ほぼ次のパターンに収まります。
- 未公開プロパティでフィルタ・ソートしている — 最頻出。BLOB 内のプロパティを条件にして全行展開スキャンになっている。→ 使う列を公開列にする。
- 上限やページングのない巨大結果 — 数万件を一度に返す設計。取得・転送・描画のすべてが重くなる。→ 最大行数を設定し、ページングを前提にする。
- 不要な列まで取得している — 使いもしない列を大量に並べ、そのぶん BLOB 展開や結合が増える。→ 本当に必要な列だけを出す。
- 重い Access when 依存の行制御 — 行ごとに評価される重い条件(複雑な参照や外部呼び出しを含む Access when 等)で表示可否を制御し、行数ぶんコストが積み上がる。→ 可能な限りデータベース側で絞れる条件に置き換える。
- 属性を並べたいだけなのにサブレポートを多用 — Class Join で済むものをサブレポートにして親件数ぶん重くしている。→ 存在判定・集約・相関以外は Class Join に寄せる。
- 集計前に落とせる条件を集計後フィルタに置いている — 無駄に集計してから捨てている。→ 行フィルタ(WHERE 側)へ移す。
まとめ
- 土台は公開列。 結合・フィルタ・ソートに使う列は必ず公開列にする。BLOB 内の未公開プロパティを条件にした瞬間、全行展開スキャンに落ちる。
- 関連データの結合は使い分ける。 関連先の属性を使うなら Association による Class Join、存在判定・集約フィルタ・相関条件はサブレポート。サブレポートの多用は避ける。
- 集約は WHERE と HAVING を分ける。 先に落とせる条件は行フィルタ(集計前)へ、集計値に依存する条件だけを集計後フィルタへ。
- 埋め込みプロパティは Declare Index。 ページリスト等を条件にするなら索引テーブルを持たせる。
- 列最適化の手順はバージョン依存。 ツール名・操作は対象バージョンの公式ドキュメントで確認する。
Report Definition は「書けば動く」からこそ、設計の良し悪しが本番データ量まで見えにくいルールです。だからこそ、公開列を土台に、結合・集約・インデックスの判断を設計時に言語化しておく ことが、後工程での性能トラブルを防ぐ最短ルートになります。
Pega の設計・実装でお困りの際は、Pega Platform 開発支援 や 無料相談 をご利用ください。Pega 認定資格の最高位 LSA(Lead System Architect)を保有するコンサルタントが、性能設計からご支援します。
関連リンク
関連記事
Pega 宣言的処理のコスト設計|前方連鎖と後方連鎖の使い分け
Declare Expression は便利だが、前方連鎖のカスケードは1つのプロパティ変更が広範な再計算を引き起こす。宣言的処理は「書けば動く」半面、実行コストが見えにくい。本記事は前方連鎖と後方連鎖、宣言的と手続き的の境界線を、性能と保守性の観点で整理する。
記事を読むPega Insights と Report Definition の使い分け|セルフサービス分析と運用レポートの線引き
「レポートは Report Definition で作るべきか、Insights でユーザーに任せるべきか」——ダッシュボード設計で必ず出る分岐です。統制と再利用が要る定型レポートはルール化し、アドホックな探索はセルフサービスに開く、が基本方針。本記事では両者のガバナンス差とデータソースの前提から、線引きの判断軸を示します。
記事を読むPega 監査証跡設計:フィールド監査・履歴・セキュリティ監査の使い分け
「何を、どこまで監査するか」は Pega のセキュリティ設計で最も判断が割れるテーマです。フィールド監査・ケース履歴・セキュリティイベントの使い分けと、監査のかけ過ぎが招く性能・容量問題の回避策を、LSA の視点で解説します。
記事を読む