webdevqa.jp.net

NHibernateのパフォーマンスを改善する最良の方法は何ですか?

私は、NHibernateをORMとして使用するアプリケーションを使用していますが、データへのアクセス方法が原因で、パフォーマンスの問題が発生することがあります。 NHibernateのパフォーマンスを向上させるには、どのようなことができますか? (回答ごとに1つの推奨に制限してください)

61
Ray Vega

NHibernateで発生する可能性がある最初で最も劇的なパフォーマンスの問題は、作成するすべてのセッションに対して新しいセッションファクトリを作成する場合です。アプリケーションの実行ごとにセッションファクトリインスタンスを1つだけ作成し、すべてのセッションをそのファクトリで作成する必要があります。

これらの線に沿って、意味のある限り同じセッションを使い続ける必要があります。これはアプリケーションによって異なりますが、ほとんどのWebアプリケーションでは、リクエストごとに1つのセッションが推奨されます。セッションを頻繁に破棄すると、キャッシュのメリットが得られません。セッションキャッシュをインテリジェントに使用すると、クエリの数が多い(または少ない)ルーチンを、多くの作業を行わずに定数に変更できます。

同様に重要なことは、オブジェクト参照の遅延読み込みを確実にしたいということです。そうでない場合は、最も単純なクエリでも、オブジェクトグラフ全体をロードできます。これを行わない理由はいくつかありますが、遅延読み込みから始めて、必要に応じて元に戻すことをお勧めします。

これにより、遅延読み込みの反対である、積極的なフェッチが可能になります。オブジェクト階層をトラバースしたり、コレクションをループしたりしているときに、実行しているクエリの数を追跡できなくなり、クエリの数が指数関数的になってしまいます。熱心なフェッチは、FETCH JOINを使用してクエリごとに実行できます。常に結合をフェッチするテーブルの特定のペアがある場合など、まれな状況では、その関係の遅延読み込みをオフにすることを検討してください。

いつものように、SQLプロファイラーは、実行が遅いクエリや繰り返し実行されるクエリを見つけるための優れた方法です。私の最後の仕事では、ページリクエストごとのクエリもカウントする開発機能がありました。ルーチンに対するクエリの数が多いことは、ルーチンがNHibernateでうまく機能していないことを示す最も明白な指標です。ルーチンまたは要求ごとのクエリの数が適切に見える場合は、おそらくデータベースのチューニングにかかっています。キャッシュに実行プランとデータを保存するための十分なメモリがあることを確認し、データに正しくインデックスを付けるなど。

私たちが遭遇した1つのトリッキーな小さな問題は、SetParameterList()に関するものでした。この関数を使用すると、パラメーターのリストをクエリに簡単に渡すことができます。 NHibernateは、渡されるアイテムごとに1つのパラメーターを作成することでこれを実装しました。これにより、パラメーターの数ごとに異なるクエリプランが生成されます。ほとんどの場合、実行計画はキャッシュから解放されていました。また、多数のパラメーターがクエリの速度を大幅に低下させる可能性があります。 NHibernateのカスタムハックを行って、単一のパラメーターで区切られたリストとして項目を送信しました。 SQL Serverでは、ハッキングがクエリのIN句に自動的に挿入するテーブル値関数によってリストが区切られていました。アプリケーションによっては、このような他の地雷が存在する可能性があります。 SQLプロファイラーはそれらを見つけるための最良の方法です。

53
Chuck

NHibernateのSessionFactoryは負荷の高い操作であるため、適切な戦略は、メモリ内にSessionFactoryのインスタンスが1つだけ存在することを保証するシングルトンを作成することです。

   public class NHibernateSessionManager
    {
        private readonly ISessionFactory _sessionFactory;

        public static readonly NHibernateSessionManager Instance = new NHibernateSessionManager();

        private NHibernateSessionManager()
        {
            if (_sessionFactory == null)
            {
                System.Diagnostics.Debug.WriteLine("Factory was null - creating one");
                _sessionFactory = (new Configuration().Configure().BuildSessionFactory());
            }
        }

        public ISession GetSession()
        {
            return _sessionFactory.OpenSession();
        }

        public void Initialize()
        {
            ISession disposeMe = Instance.GetSession();
        }
    }

次に、Global.Asax Application_Startupで初期化できます。

protected void Application_Start()
{
    NHibernateSessionManager.Instance.Initialize();
}
26
David P

Select N + 1 problem を回避または最小化するには、遅延読み込みから、実行速度の遅いクエリの熱心なフェッチに切り替えるタイミングを認識します。

11
Ray Vega

推奨事項はありませんが、役立つツール:NH教授( http://nhprof.com/ )は有望であるようで、ORMフレームワークの使用を評価できます。これは、NHibernateのチューニングの開始点として最適です。

10
MatthieuGD

発生しているパフォーマンスの問題の種類に関する詳細がなければ、私は一般化のみを提供できます。私の経験では、ほとんどのデータベースクエリのパフォーマンスの問題は、適切なインデックスの欠如から発生します。したがって、最初のアクションについての私の提案は、非インデックスクエリのクエリプランを確認することです。

4
Mike Monette

「回答ごとに1つの推奨」のみですか。それから私はこれに行きます:

2つ以上の並列対多関連に沿った結合による結合の重複(別名デカルト積)は避けてください。代わりに、Exists-subqueries、MultiQueries、またはFetchMode "subselect"を使用してください。

以下から取得: Hibernate Performance Tuning Tips

3
gnome26

NHibernateは、すぐに使える非常に高速なSQLを生成します。私はそれを1年間使用しており、それを使用してベアSQLを記述する必要はまだありません。私のパフォーマンスの問題はすべて 正規化 とインデックスの欠如が原因です。

最も簡単な修正は、クエリの実行プランを調べて、特に外部キー列に適切なインデックスを作成することです。 Microsoft SQL Serverを使用している場合は、「データベースエンジンチューニングアドバイザー」がこれに役立ちます。

3
Eric Lathrop

回答を1つのオプションに制限することはできますか?その場合、NHibernateの2次キャッシュメカニズムを実装することを選択します。

このようにして、マッピングファイル内の各オブジェクトに対して、キャッシュ戦略を定義できます。 2次レベルキャッシュは、既に取得したオブジェクトをメモリに保持するため、データベースへの別のラウンドトリップは行いません。これは巨大なパフォーマンスブースターです。

あなたの目標は、アプリケーションが常にアクセスするオブジェクトを定義することです。それらの中には、一般的な設定などがあります。

Nhibernateの2次レベルキャッシュとその実装方法については、多くの情報が見つかります。

幸運を :)

1
Hace

プロファイリングは、最大の効果が得られる場所を見つけるための最初のステップです(単純な時限ユニットテストでも)。

コレクションの場合、発行される選択ステートメントの数を減らすためにバッチサイズを設定することを検討してください-詳細については、セクション パフォーマンスの向上 を参照してください

1
Richard

(適切に)遅延読み込みをまだ使用していない場合は、開始します。必要のないときにコレクションをフェッチすると、すべての無駄になります。

パフォーマンスの改善 は、これとパフォーマンスを改善する他の方法を説明します。

1
lotsoffreetime

キャッシング、キャッシング、キャッシング-第1レベルのキャッシングを正しく使用していますか[セッションを途中で終了するか、StatelessSessionを使用して第1レベルのキャッシングをバイパスしますか?]まれにしか変化しない値のために、単純な2次キャッシュをセットアップする必要がありますか?クエリ結果セットをキャッシュして、変更頻度の低いクエリを高速化できますか?

[設定も-アイテムを不変として設定できますか?クエリを再構築して、必要な情報のみを取り戻し、それらを元のエンティティに変換できますか?バットマンがダムにたどり着く前に、リドラーを止めることができるでしょうか? ...おお、ごめんなさい。]

1
Watson

Lotsoffreetimeが言ったこと。

ドキュメントの「パフォーマンスの向上」の第19章をお読みください。
NHibernate: http://nhibernate.info/doc/nhibernate-reference/performance.html
休止状態: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html

SQLプロファイラー(または使用しているデータベースと同等のもの)を使用して、実行時間の長いクエリを見つけます。適切なインデックスでこれらのクエリを最適化します。

アプリケーションのほぼすべての単一ページで使用されるデータベース呼び出しの場合、CreateMultiQueryを使用して、単一のデータベースクエリから複数の結果セットを返します。

そしてもちろん、キャッシュ。ページ/コントロールのOutputCacheディレクティブ。データのNHibernateキャッシング。

0
Axl