NHibernate - Tamanho do lote
Neste capítulo, iremos cobrir a atualização do tamanho do lote. O tamanho do lote permite que vocêcontrol the number of updates que saem em uma única viagem de ida e volta para seu banco de dados para os bancos de dados suportados.
O tamanho do lote de atualização foi padronizado a partir do NHibernate 3.2.
Mas se você estiver usando uma versão anterior ou precisar ajustar seu aplicativo NHibernate, você deve olhar para o tamanho do lote de atualização, que é um parâmetro muito útil que pode ser usado para ajustar o desempenho do NHibernate.
Na verdade, o tamanho do lote controla quantas inserções enviar de um grupo para um banco de dados.
No momento, apenas o SQL Server e o Oracle oferecem suporte a essa opção porque o provedor de banco de dados subjacente precisa oferecer suporte ao envio em lote de consultas.
Vamos dar uma olhada em um exemplo simples em que definimos o tamanho do lote para 10 que irá inserir 10 registros em um conjunto.
cfg.DataBaseIntegration(x => {
x.ConnectionString = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
x.BatchSize = 10;
});
Aqui está a implementação completa na qual 25 registros serão adicionados ao banco de dados.
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();
}
}
}
}
Agora vamos executar seu aplicativo e você verá que todas essas atualizações estão pulando para o perfilador do NHibernate. Temos 26 viagens individuais de ida e volta ao banco de dados, 25 para inserção e uma para recuperação da lista de alunos.
Agora, por que isso? A razão é porque o NHibernate precisa fazer umselect scope identity já que estamos usando a estratégia de geração de identificador nativo no arquivo de mapeamento para ID, conforme mostrado no código a seguir.
<?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>
Portanto, precisamos usar um método diferente, como o guid.combmétodo. Se vamos para guid.comb, precisamos ir até nosso cliente e mudar isso para umguid. Então isso vai funcionar bem. Agora vamos mudar do nativo para guid.comb usando o código a seguir.
<?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>
Portanto, é o banco de dados o responsável por gerar esses IDs. A única maneira do NHibernate descobrir qual ID foi gerado é selecioná-lo imediatamente depois. Ou então, se tivermos criado um lote de alunos, não será possível coincidir com o ID do aluno que foi criado.
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
}
}
Precisamos apenas atualizar nosso banco de dados. Vamos eliminar a tabela do aluno e criar uma nova tabela especificando a seguinte consulta, então vá para o SQL Server Object Explorer e clique com o botão direito do mouse no banco de dados e selecione oNew Query… Opção.
Ele abrirá o editor de consulta e, em seguida, especificará a consulta a seguir.
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 eliminará primeiro a tabela do aluno existente e, em seguida, criará uma nova tabela. Como você pode ver, temos usadoUNIQUEIDENTIFIER em vez de usar uma chave primária inteira como um ID.
Execute esta consulta e vá para o Designer view e você verá que agora o ID é criado com um identificador exclusivo, conforme mostrado na imagem a seguir.
Agora precisamos remover o ID do arquivo program.cs, ao inserir os dados, porque agora ele irá gerar o guids para isso automaticamente.
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();
}
}
}
}
Agora execute o aplicativo novamente e dê uma olhada no criador de perfil do NHibernate. Agora, o perfilador do NHibernate, em vez de fazer 26 viagens de ida e volta, fará apenas quatro.
São inseridas dez linhas na tabela, depois outras dez linhas e, posteriormente, as cinco restantes. E após o commit, ele inseriu mais um para recuperar todos os registros.
Portanto, é dividido em grupos de dez, da melhor maneira possível.
Portanto, se você estiver fazendo muitas inserções, isso pode melhorar drasticamente o desempenho da inserção em seu aplicativo, porque você pode agrupá-las.
Isso ocorre porque o NHibernate atribui esses próprios guias usando o guid.comb algoritmo e não precisa depender do banco de dados para fazer isso.
Portanto, usar o tamanho do lote é uma ótima maneira de ajustá-lo.