Hibernate の第 2 レベルのクエリ キャッシュが機能しない 熱心なフェッチ
-
20-09-2019 - |
質問
NHibernate Profiler では、関連付けに対して積極的なフェッチを使用し、HQL クエリで「left join fetch」を使用するか、条件クエリで .SetFetchMode() を使用すると、クエリがクエリ キャッシュにキャッシュされなくなることがわかりました。
実際、私が見た限りでは、非常に基本的なクエリのみがキャッシュされています。どのクエリがキャッシュされ、どのクエリがキャッシュされないかについて洞察を提供できる人がいれば、回答をマークします。
何か違いがあれば、私は Memcached を使用しています...クエリ密度の高いシステムに適した L2 キャッシュの選択肢はありますか?
私はこれがかなり難しいと感じています。熱心なロードを使用しない場合、N+1の問題が発生します(ただしキャッシュを使用します)。熱心なロードを使用すると、データベースからすべてのエンティティを取得しますが、キャッシュはありません。
かなり厚い境界線があるようです。どちらの戦略でもパフォーマンスは向上しますが、どちらの戦略ももう一方の戦略からパフォーマンスを奪います。
最適なパフォーマンスを得るには、この「太い線」のどこに配置する必要があるか、または「線を細くする」方法について洞察を与えることができる人がいれば...私なら厳重に答えをマークします。
解決
アップデート: 私の関連する質問をご覧ください ここ. 。肝心なのは、すでに 2 次キャッシュにあるオブジェクトとの結合を避けるために fetch="select" を使用してみてください。
私の以前の回答(まだ役に立つかもしれません)
クエリ キャッシュは、実際のオブジェクトではなく、クエリから返された識別子をキャッシュします。
正しく使用するには、次のことを行う必要があります
- プレースホルダーを使用します (?または:varName)
- クエリキャッシュを true に設定します (実際に実行しました)
- クエリはプロパティではなくオブジェクトを返す必要があります (
from Foo
, 、 ないselect foo.bar from Foo foo
) - 返されたオブジェクトは 2 次キャッシュに存在するか、後続の呼び出しが同じ休止状態セッション (同じトランザクション) 内にある必要があります。
#4 を明確にするために、2 つの異なるトランザクションが正確なパラメーターを使用して正確な (キャッシュされた) クエリを実行し、まったく同じオブジェクトを返した場合でも、それが 2 レベルのキャッシュにない場合、実際のオブジェクトを取得するためにデータベース ヒットが発生します (おそらく、選択してください。で )
クエリ キャッシュは 2 つの点で役立ちます。キャッシュされていないアイテムに対する HQL クエリの同じトランザクションでデータベースに再ヒットすることを回避し、HQL クエリに対して第 2 レベルのキャッシュされたオブジェクトを利用できるようにします (load または get コマンドで自動的に使用されます)。
森がきれいになってくれればいいのですが…
他のヒント
私はNHibernateは知りませんが、休止状態では、明示的にクエリを使用ヒントのためのクエリキャッシュを有効にする必要があります。 L2キャッシュは自動的に個々のオブジェクトをキャッシュすることがありますが、クエリのためには、明示的な方向性を必要とします。
そうでもない答え - むしろヒント...コレクションとクエリキャッシュの両方が実際に結果を格納しません。彼らはただ結果のエンティティの識別子を格納します。これは、エンティティのデータを格納しますエンティティ/クラスキャッシュです。
だから、それについて考える - クエリが複数のエンティティタイプ(すなわち、熱心な負荷を)返す場合、エンティティ間の関係がありますので、それが合理的にIDの配列を格納することはできません。私は、キャッシュ自体は非常にシンプルな構造であると考えています。
私は「価値」クエリについて確認していない - の代わりにクラスの投影を使用することになり、すなわち、そのようなこと。私はあなたがこれらをキャッシュすることはできませんと言うでしょう。しかし、私は間違っているかもしれません。
今では、あなたの問題のお手伝いをしていないかもしれないが - その可能性のある他の技術があります。すなわち、バッチ・ロードと適切なエンティティキャッシュ。私は、コレクションのキャッシュに関する注意が必要だろう。私はそれらによって数回かましまっています。
役立つホープ(少なくともビット)。