NHibernate - Chargengröße
In diesem Kapitel werden wir uns mit der Aktualisierung der Stapelgröße befassen. Die Chargengröße ermöglicht es Ihnencontrol the number of updates die in einem einzigen Roundtrip zu Ihrer Datenbank für die unterstützten Datenbanken ausgehen.
Die Update-Stapelgröße wurde ab NHibernate 3.2 voreingestellt.
Wenn Sie jedoch eine frühere Version verwenden oder Ihre NHibernate-Anwendung optimieren müssen, sollten Sie sich die Update-Stapelgröße ansehen. Dies ist ein sehr nützlicher Parameter, mit dem Sie die Leistung von NHibernate optimieren können.
Die tatsächliche Stapelgröße steuert, wie viele Einfügungen in einer Gruppe an eine Datenbank gesendet werden sollen.
Derzeit unterstützen nur SQL Server und Oracle diese Option, da der zugrunde liegende Datenbankanbieter das Batching von Abfragen unterstützen muss.
Schauen wir uns ein einfaches Beispiel an, in dem wir die Stapelgröße auf 10 festgelegt haben, um 10 Datensätze in einen Satz einzufügen.
cfg.DataBaseIntegration(x => {
x.ConnectionString = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
x.BatchSize = 10;
});
Hier ist die vollständige Implementierung, in der 25 Datensätze zur Datenbank hinzugefügt werden.
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();
}
}
}
}
Lassen Sie uns nun Ihre Anwendung ausführen und sehen, dass all diese Updates auf den NHibernate-Profiler übertragen werden. Wir haben 26 individuelle Rundreisen in die Datenbank 25 zum Einfügen und einen zum Abrufen der Studentenliste.
Warum ist das so? Der Grund ist, dass NHibernate a tun mussselect scope identity Wir verwenden die Strategie zur Generierung nativer Bezeichner in der Zuordnungsdatei für ID, wie im folgenden Code gezeigt.
<?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>
Wir müssen also eine andere Methode wie die verwenden guid.combMethode. Wenn wir zu guid.comb gehen wollen, müssen wir zu unserem Kunden gehen und dies in a ändernguid. Das wird also gut funktionieren. Wechseln wir nun mit dem folgenden Code von native zu 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>
Es ist also die Datenbank, die für die Generierung dieser IDs verantwortlich ist. Die einzige Möglichkeit für NHibernate, herauszufinden, welche ID generiert wurde, bestand darin, sie unmittelbar danach auszuwählen. Wenn wir einen Stapel von Schülern erstellt haben, kann die ID des erstellten Schülers nicht übereinstimmen.
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
}
}
Wir müssen nur unsere Datenbank aktualisieren. Lassen Sie uns die Schülertabelle löschen und eine neue Tabelle erstellen, indem Sie die folgende Abfrage angeben. Gehen Sie also zum SQL Server-Objekt-Explorer, klicken Sie mit der rechten Maustaste auf die Datenbank und wählen Sie die ausNew Query… Möglichkeit.
Es öffnet den Abfrageeditor und gibt dann die folgende Abfrage an.
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)
);
Diese Abfrage löscht zuerst die vorhandene Schülertabelle und erstellt dann eine neue Tabelle. Wie Sie sehen, haben wir verwendetUNIQUEIDENTIFIER anstatt einen ganzzahligen Primärschlüssel als ID zu verwenden.
Führen Sie diese Abfrage aus und gehen Sie dann zu Designer view und Sie werden sehen, dass jetzt die ID mit einer eindeutigen Kennung erstellt wird, wie im folgenden Bild gezeigt.
Jetzt müssen wir die ID aus der Datei program.cs entfernen, während wir Daten einfügen, da jetzt die ID generiert wird guids dafür automatisch.
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();
}
}
}
}
Führen Sie nun die Anwendung erneut aus und sehen Sie sich den NHibernate-Profiler an. Jetzt macht der NHibernate-Profiler statt 26 Rundreisen nur noch vier.
Es werden zehn Zeilen in die Tabelle eingefügt, dann weitere zehn Zeilen und später die restlichen fünf. Nach dem Festschreiben wurde eine weitere eingefügt, um alle Datensätze abzurufen.
Also hat es es in Zehnergruppen aufgeteilt, so gut es geht.
Wenn Sie also viele Einfügungen vornehmen, kann dies die Einfügungsleistung in Ihrer Anwendung erheblich verbessern, da Sie sie stapeln können.
Dies liegt daran, dass NHibernate diese Guids selbst mithilfe von zuweist guid.comb Algorithmus, und es muss nicht auf die Datenbank angewiesen sein, um dies zu tun.
Die Verwendung der Stapelgröße ist daher eine hervorragende Möglichkeit, diese zu optimieren.