DBFlute -- 大量データのハンドリング


http://d.hatena.ne.jp/Hnoss/20070814

テーマにしているSql2Entityとはちょっと外れますが、
大量データのハンドリングについて語らせてくださいw

非接続型のO/R-Mapperで10万件をそのまま検索すると
大抵の場合OutOfMemoryになります。

【画面表示のための一覧の場合】
基本的には画面仕様としてPagingを採用します。
1画面(ページ)の表示を20件までとし、検索して取得するInstance自体も20件とします。
但し、PagingNavigationを画面で作成するために、「Paging絞り無し総件数」を
SQLで取得する必要があります。

= = = = = = = = = = = = = = = = = = = =
final BookCB cb = new BookCB();
cb.fetchFirst(20);
cb.fetchPage(3); // 3ページ目を検索
cb.query().setXxx_GreaterEqual(...);

// 「Paging絞り無し総件数」&「Paging検索」&「PagingNavigation計算処理」
PagingResultBean bookPage = bookBhv.selectPage(cb);
= = = = = = = = = = = = = = = = = = = =

外だしSQLの場合(Sql2Entityを使った場合)も同じくPaging実装して
必要な分だけ検索します。(無論、総件数も取得する)
http://dbflute.sandbox.seasar.org/ja/tips-paging.html

【夜間バッチ処理の場合】
やはり10万件一気にメモリ上には持てません。
やり方は色々あるのですが、その1つを紹介します。

1. 処理対象の10万件の「主キーのみ一覧」を検索
2. その一覧をLoopして、1件ずつ処理をする。

= = = = = = = = = = = = = = = = = = = =
final BookCB cb = new BookCB();
cb.limitSelect_PKOnly();
cb.query().setBookStatus_Equals_Prepare(); // 準備中のものだけ検索
...(主キーのみ一覧) = bookBhv.selectList(cb);
= = = = = = = = = = = = = = = = = = = =

実際にこのやり方で自分の周りのプロジェクトではたくさん
バッチ処理をこなしています。

但し、上記のやり方は、「バッチ実行中にInsertされたレコード」を処理できません。
終了後に0件になるまでもう一度同じ検索を行うなどの工夫が必要です。
(そこまで厳密に処理したい要件が無ければ別に問題はないですが)

他には、20件ずつInstance化(Pagingみたいに)して、
処理をするやり方もありますが、1回1回のSQLは10万件をOrderByする
ことになるので、あまりパフォーマンスよくありません。

随時バッチとかであれば、大量データにならないのであまり気にしなくても
いいかもしれませんが、いざ運用時に随時が途切れて、再開時に大量データを
扱いたくなることもあるかと思うので、基本的にOutOfMemoryにならないような
仕組みにしておく方が良いと考えています。