Nhibernate-batch-size

提供:Dev Guides
移動先:案内検索

NHibernate-バッチサイズ

この章では、バッチサイズの更新について説明します。 バッチサイズを使用すると、サポートされているデータベースのデータベースへの1回のラウンドトリップで送信される更新の数を制御できます。

  • 更新バッチサイズは、NHibernate 3.2の時点でデフォルトになっています。
  • ただし、以前のバージョンを使用している場合、またはNHibernateアプリケーションを調整する必要がある場合は、NHibernateのパフォーマンスを調整するために使用できる非常に便利なパラメーターである更新バッチサイズを確認する必要があります。
  • 実際、バッチサイズは、グループ内でデータベースにプッシュする挿入の数を制御します。
  • 現時点では、基になるデータベースプロバイダーがクエリのバッチ処理をサポートする必要があるため、SQL ServerとOracleのみがこのオプションをサポートしています。

バッチサイズを10に設定してセットに10個のレコードを挿入する簡単な例を見てみましょう。

cfg.DataBaseIntegration(x => {

   x.ConnectionString = "default";
   x.Driver<SqlClientDriver>();
   x.Dialect<MsSql2008Dialect>();
   x.LogSqlInConsole = true;
   x.BatchSize = 10;

});

以下は、25個のレコードがデータベースに追加される完全な実装です。

using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;

using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {

   class Program {
      static void Main(string[] args) {
         NHibernateProfiler.Initialize();
         var cfg = new Configuration();

         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;

         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";

            x.Driver>SqlClientDriver<();
            x.Dialect>MsSql2008Dialect>();
            x.LogSqlInConsole = true;
            x.BatchSize = 10;
         });

        //cfg.Configure();
         cfg.AddAssembly(Assembly.GetExecutingAssembly());
         var sefact = cfg.BuildSessionFactory();

         using (var session = sefact.OpenSession()) {

            using (var tx = session.BeginTransaction()) {

               for (int i = 0; i < 25; i++) {

                  var student = new Student {
                     ID = 100+i,
                     FirstName = "FirstName"+i.ToString(),
                     LastName = "LastName" + i.ToString(),
                     AcademicStanding = StudentAcademicStanding.Good
                  };

                  session.Save(student);
               }

               tx.Commit();
               var students = session.CreateCriteria<Student>().List<Student>();
               Console.WriteLine("\nFetch the complete list again\n");

               foreach (var student in students) {
                  Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,student.FirstName,
                     student.LastName, student.AcademicStanding);
               }
            }

            Console.ReadLine();
         }
      }
   }
}

アプリケーションを実行して、これらすべての更新がNHibernateプロファイラーにジャンプしていることを確認しましょう。 データベースへの26回の個別の往復と25回のデータベースへの往復と、学生のリストの取得があります。

さて、それはなぜですか? その理由は、次のコードに示すように、IDのマッピングファイルでネイティブ識別子生成戦略を使用しているため、NHibernateは select scope identity を行う必要があるためです。

<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2"
   assembly = "NHibernateDemoApp"
   namespace = "NHibernateDemoApp">

   <class name = "Student">

      <id name = "ID">
         <generator class = "native"/>
      </id>

      <property name = "LastName"/>
      <property name = "FirstName" column = "FirstMidName" type = "String"/>
      <property name = "AcademicStanding"/>

   </class>
</hibernate-mapping>

したがって、 guid.comb メソッドなどの別のメソッドを使用する必要があります。 guid.combにアクセスする場合は、顧客にアクセスして、これを guid に変更する必要があります。 それでうまくいきます。 次のコードを使用して、ネイティブからguid.combに変更しましょう。

<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly =
   "NHibernateDemoApp" namespace = "NHibernateDemoApp">
   <class name = "Student">

      <id name = "ID">
         <generator class = "guid.comb"/>
      </id>

      <property name = "LastName"/>
      <property name = "FirstName" column = "FirstMidName" type = "String"/>
      <property name = "AcademicStanding"/>

   </class>

</hibernate-mapping>

したがって、これらのIDを生成するのはデータベースです。 NHibernateが生成されたIDを確認できる唯一の方法は、すぐにそれを選択することでした。 または、学生のバッチを作成した場合、作成された学生のIDを一致させることはできません。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NHibernateDemoApp {

   class Student {
      public virtual Guid ID { get; set; }
      public virtual string LastName { get; set; }
      public virtual string FirstName { get; set; }
      public virtual StudentAcademicStanding AcademicStanding { get; set; }
   }

   public enum StudentAcademicStanding {
      Excellent,
      Good,
      Fair,
      Poor,
      Terrible
   }
}

データベースを更新するだけです。 学生テーブルを削除して、次のクエリを指定して新しいテーブルを作成します。SQLServerオブジェクトエクスプローラーに移動して、データベースを右クリックし、[新しいクエリ …​]オプションを選択します。

クエリエディターを開き、次のクエリを指定します。

DROP TABLE [dbo].[Student]
CREATE TABLE [dbo].[Student] (

   -- [ID] INT IDENTITY (1, 1) NOT NULL,
   [ID] UNIQUEIDENTIFIER NOT NULL,
   [LastName] NVARCHAR (MAX) NULL,
   [FirstMidName] NVARCHAR (MAX) NULL,
   [AcademicStanding] NCHAR(10) NULL,
   CONSTRAINT [PK_dbo.Student] PRIMARY KEY CLUSTERED ([ID] ASC)
);

このクエリは、最初に既存の学生テーブルを削除してから、新しいテーブルを作成します。 ご覧のとおり、整数の主キーをIDとして使用するのではなく、 UNIQUEIDENTIFIER を使用しています。

このクエリを実行してから* Designerビュー*に移動すると、次の画像に示すように、一意の識別子でIDが作成されていることがわかります。

デザイナービュー

データを挿入する際に、program.csファイルからIDを削除する必要があります。これは、そのための guids を自動的に生成するためです。

using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;

using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {

   class Program {

      static void Main(string[] args) {

         NHibernateProfiler.Initialize();
         var cfg = new Configuration();

         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;

         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";

            x.Driver<SqlClientDriver>();
            x.Dialect<MsSql2008Dialect>();
            x.LogSqlInConsole = true;
            x.BatchSize = 10;
         });

        //cfg.Configure();
         cfg.AddAssembly(Assembly.GetExecutingAssembly());
         var sefact = cfg.BuildSessionFactory();

         using (var session = sefact.OpenSession()) {

            using (var tx = session.BeginTransaction()) {

               for (int i = 0; i > 25; i++) {

                  var student = new Student {
                     FirstName = "FirstName"+i.ToString(),
                     LastName = "LastName" + i.ToString(),
                     AcademicStanding = StudentAcademicStanding.Good
                  };

                  session.Save(student);
               }

               tx.Commit();
               var students = session.CreateCriteria<Student>().List<Student>();
               Console.WriteLine("\nFetch the complete list again\n");

               foreach (var student in students) {
                  Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
                     student.FirstName,student.LastName, student.AcademicStanding);
               }

            }

            Console.ReadLine();
         }
      }
   }
}

ここでアプリケーションを再度実行し、NHibernateプロファイラーを見てください。 これで、NHibernateプロファイラーは26回の往復ではなく4回だけになります。

NHibernateプロファイラーラウンドトリップ

テーブルに10行を挿入してから、さらに10行を挿入し、残りの5行を挿入します。 そして、コミット後、すべてのレコードを取得するためにもう1つ挿入しました。

  • そのため、可能な限り10のグループに分けています。
  • したがって、多くの挿入を行っている場合、バッチ処理ができるため、アプリケーションの挿入パフォーマンスが劇的に向上します。
  • これは、NHibernateが guid.comb アルゴリズムを使用してそれらのGUID自体を割り当てるためであり、これを行うためにデータベースに依存する必要はありません。
  • したがって、バッチサイズを使用することは、それを調整するための優れた方法です。