データベースへの繰り返しの呼び出しに関連していると思われるいくつかのパフォーマンスの問題に取り組んでいます (数十の子オブジェクトをそれぞれにロードする数千のオブジェクト)。
問題は、リレーションシップを熱心にロードしているにもかかわらず (そして、休止状態の SQL を記録することによってオブジェクトが実際に熱心にロードされていることを確認している) にもかかわらず、データベースから毎回フェッチされているようです。
私の本能は、オブジェクトが既にメモリにあると確信しているときに、オブジェクトのためにデータベースに戻るのではなく、メモリ内のオブジェクトを使用するように grails/hibernate に指示する方法があるかどうかを尋ねることです。
しかし、これは間違った質問かもしれません。
何が起こっているかの具体的な例を挙げます。私のドメインクラスの親は次を定義します:
static hasMany = [children: Child]
static mapping = {children fetch:'select'}
fetch:'eager' であった可能性があります... 両方の方法を試しましたが、どちらが以下のログ結果を生成したかはわかりませんが、データを熱心にフェッチしていることは明らかです。
私が最初に行うことは次のとおりです。
def results = Parent.executeQuery("親 p とは異なる p を選択する WHERE ... 複雑な where 句")
ログを見ると、これは子リレーションシップを積極的にロードしていませんが、これはそれほど予想外ではなく、現時点では致命的ではありません。次に、親全体を反復処理します。
for(Parent parent : results)
{ blah blah }
ループの各反復は、hibernate が ID によって親 p を照会しており、すべての子関係を熱心にロードしているように見えることを示しています。ログ スニペット:
select
parent0_.id as id4_4_,
parent0_.version as version4_4_,
parent0_.date_created as date3_4_4_,
child1_.parent_id as parent6_6_,
child1_.id as id6_,
child1_.child_idx as idx9_6_,
child1_.id as id22_1_,
child1_.version as version22_1_,
...continues for all fields.
注: id フィールドを 2 回マップする理由がわかりません。
すごい!必要な子オブジェクトを熱心にロードしています! 上記の親ループ内で、子を反復処理します。
for(Parent parent : results)
{
for(Child child : parent.children)
{ blah blah }
}
そして、ここが問題です。内側のループを反復するたびに、別の hibernate クエリがログに記録され、id によってオブジェクトが読み込まれます。ログ スニペット:
select child0_.id as id22_1_,
child0_.version as version22_1_,
child0_.parent_id as parent6_22_1_,
child0_.sequence_number as sequence8_22_1_,
...and all the rest
これらの不必要な負荷は、何千もの読み取りを実行しているため、パフォーマンスを完全に低下させています (少なくとも、これがボトルネックのようです。100% 確実ではありません)。メモリ内オブジェクトを適切に使用する方法や、データをロードするさまざまな方法についての考えは非常に高く評価されています。