NHibernate - Tamaño de lote
En este capítulo, cubriremos la actualización del tamaño del lote. El tamaño del lote le permitecontrol the number of updates que salen en un solo viaje de ida y vuelta a su base de datos para las bases de datos compatibles.
El tamaño del lote de actualización se ha predeterminado a partir de NHibernate 3.2.
Pero si está utilizando una versión anterior o necesita ajustar su aplicación NHibernate, debería mirar el tamaño del lote de actualización, que es un parámetro muy útil que se puede utilizar para ajustar el rendimiento de NHibernate.
En realidad, el tamaño del lote controla cuántas inserciones enviar en un grupo a una base de datos.
Por el momento, solo SQL Server y Oracle admiten esta opción porque el proveedor de la base de datos subyacente debe admitir el procesamiento por lotes de consultas.
Echemos un vistazo a un ejemplo simple en el que hemos establecido el tamaño del lote en 10 que insertará 10 registros en un conjunto.
cfg.DataBaseIntegration(x => {
x.ConnectionString = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
x.BatchSize = 10;
});
Aquí está la implementación completa en la que se agregarán 25 registros a la base de datos.
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();
}
}
}
}
Ahora ejecutemos su aplicación y verá que todas esas actualizaciones están saltando al generador de perfiles de NHibernate. Tenemos 26 viajes de ida y vuelta individuales a la base de datos, 25 para la inserción y uno para recuperar la lista de estudiantes.
Ahora, ¿por qué es eso? La razón es que NHibernate necesita hacer unaselect scope identity ya que estamos usando la estrategia de generación de identificadores nativos en el archivo de mapeo para ID como se muestra en el siguiente código.
<?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>
Así que necesitamos usar un método diferente como el guid.combmétodo. Si vamos a ir a guid.comb, debemos acercarnos a nuestro cliente y cambiar esto a unguid. Entonces eso funcionará bien. Ahora cambiemos del nativo a guid.comb usando el siguiente código.
<?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>
Entonces, es la base de datos la responsable de generar esos ID. La única forma en que NHibernate puede averiguar qué ID se generó fue seleccionarlo inmediatamente después. De lo contrario, si hemos creado un lote de estudiantes, no podrá coincidir con la identificación del estudiante que se creó.
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
}
}
Solo necesitamos actualizar nuestra base de datos. Dejemos caer la tabla de estudiantes y creemos una nueva tabla especificando la siguiente consulta, así que vaya al Explorador de objetos de SQL Server y haga clic derecho en la base de datos y seleccione elNew Query… opción.
Abrirá el editor de consultas y luego especificará la siguiente consulta.
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)
);
Esta consulta primero eliminará la tabla de estudiantes existente y luego creará una nueva tabla. Como puede ver, hemos utilizadoUNIQUEIDENTIFIER en lugar de utilizar una clave primaria entera como ID.
Ejecute esta consulta y luego vaya al Designer view y verá que ahora la ID se crea con un identificador único como se muestra en la siguiente imagen.
Ahora necesitamos eliminar la ID del archivo program.cs, mientras insertamos datos, porque ahora generará el guids para ello automáticamente.
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();
}
}
}
}
Ahora ejecute la aplicación nuevamente y eche un vistazo al generador de perfiles de NHibernate. Ahora, el generador de perfiles NHibernate, en lugar de realizar 26 viajes de ida y vuelta, solo hará cuatro.
Se insertan diez filas en la tabla, luego otras diez filas y luego las cinco restantes. Y después de la confirmación, ha insertado uno más para recuperar todos los registros.
Así que lo dividió en grupos de diez, lo mejor que pudo.
Entonces, si está haciendo muchas inserciones, esto puede mejorar drásticamente el rendimiento de la inserción en su aplicación, porque puede agruparlas.
Esto se debe a que NHibernate asigna esas guías por sí mismo utilizando la guid.comb algoritmo, y no tiene que depender de la base de datos para hacer esto.
Entonces, usar el tamaño del lote es una excelente manera de ajustarlo.