2

メソッドごとに 1 つのセッションで nHibernate を使用しています。メソッドを実行する前にCastle Dynamic Proxyを使用してセッションとトランザクションを開き、このメソッドの実行直後にトランザクションをコミットしてセッションを閉じます。

SQLite データベースを使用していますが、cascade を SaveUpdate または None に設定しても何も変わりません。nHIbernate は、デフォルト構成の Fluent nHibernate で構成されます。

セッションをフラッシュすると、2 秒以上かかります。

public void AddNewChild(LightPatientDto patient, LightPatientDto child)
{
    var ePatient = this.Session.Load<Patient>(patient.Id);
    var eChild = this.Session.Load<Patient>(child.Id);

    switch (ePatient.Gender)
    {
        case Gender.Male:
            eChild.Father = ePatient;
            break;
        case Gender.Female:
            eChild.Mother = ePatient;
            break;
        default:
            Assert.FailOnEnumeration(eChild.Gender);
            break;
    }

    this.Session.Update(eChild);
    this.Session.Flush(); // <== takes more than 2 seconds
}

NHibernate プロファイラーは、この SQL が 2008 ミリ秒で実行されることを示しています。SQLite 管理ツールを使用してこの SQL をコピー ペーストすると、90 ミリ秒で実行されます。

UPDATE Patient
SET    BirthDate = '1964-05-06T00:00:00.00' /* @p0 */,
       Fee = 0 /* @p1 */,
       Height = 0 /* @p2 */,
       InscriptionDate = '2007-05-21T00:00:00.00' /* @p3 */,
       PlaceOfBirth = 'xxxxxx' /* @p4 */,
       PrivateMail = '' /* @p5 */,
       PrivateMobile = NULL /* @p6 */,
       PrivatePhone = '0496/xx.xx.xx' /* @p7 */,
       Reason = 'diabète' /* @p8 */,
       Father_id = 2 /* @p9 */,
       Insurance_id = 1 /* @p10 */,
       Mother_id = NULL /* @p11 */,
       Practice_id = 1 /* @p12 */,
       Profession_id = NULL /* @p13 */,
       Reputation_id = 1 /* @p14 */
WHERE  Person_id = 3 /* @p15 */

実行時間を最適化するにはどうすればよいですか?

編集1

@csanchez が示唆したように、エンティティに動的更新を追加することに成功しました。SQL を NH Profiler で調べていると、次のようになります。

UPDATE Patient
SET    Father_id = 2 /* @p0 */
WHERE  Person_id = 21 /* @p1 */

これは非常に最適化されています!しかし、実行時間は…1852ms o_O

デバッガーでは、時間がかかるトランザクションをコミットしていることがわかります...なぜそんなに遅いのかわかりません...

編集2

各患者には、バイト配列としてテーブルに格納されている医療写真があります。テーブル作成用の SQL は次のとおりです (Fluent nHibernate によって実行されます)。

CREATE TABLE Picture (
  Id               integer PRIMARY KEY AUTOINCREMENT,
  Bitmap           blob,
  Creation         datetime,
  LastUpdate       datetime,
  Notes            text,
  IsImported       bool,
  Tag_id           bigint,
  Patient_id       bigint,
  ThumbnailBitmap  blob,
  /* Foreign keys */
  FOREIGN KEY (Patient_id)
    REFERENCES Patient(), 
  FOREIGN KEY (Tag_id)
    REFERENCES "Tag"()
);

でデータをドロップしDELETE Pictureてアプリケーションを再起動すると、更新は非常に高速です。

nHibernate はスマートになろうとして、すべてを遅くするようなことをしているようです。ただし、このコードで純粋な SQL クエリを実行すると、更新に 1 秒以上かかります。

using (var tx = this.Session.BeginTransaction())
{   
    var sql = "UPDATE Patient SET Father_id = 2 WHERE Person_id = 21";     
    var query = this.Session.CreateSQLQuery(sql);
    query.ExecuteUpdate();

    tx.Commit();
}
4

3 に答える 3

1

更新するのが親または母だけの場合はdynamic-update="true"、患者のマッピング ファイルで使用できます。

于 2012-11-07T13:08:06.240 に答える
0

データを変更するたびにセッションをフラッシュしないでください。NHibernate のバッファ更新と一括変更のフラッシュを許可する必要があります。そうでなければ、彼らは暗黙的なフラッシュ操作を行い、それについて心配する必要はありません。

于 2012-11-04T22:06:41.353 に答える
0

このパフォーマンスは、DB への最初のコミットだけでヒットしますか。SQLite にはスピンアップ時間がかかる場合があります。

「メソッドごとのセッション」と言っていますが、モジュールレベルのセッション変数を使用しているようです。Session インスタンスで多くのことが行われるほど、キャッシングのために遅くなります。これがより多くのバッチ操作になる場合は、StatelessSession を検討してください。

NHibernate + Log4Net のロギング構成も確認してください。ログが詳細になるほど、NH の応答が遅くなります。

于 2012-11-04T21:49:38.203 に答える