Capas de acceso a datos .NET escalables de verdad: el batido perfecto para el rendimiento de tus...

Post on 23-Jan-2018

403 views 0 download

Transcript of Capas de acceso a datos .NET escalables de verdad: el batido perfecto para el rendimiento de tus...

SOLIDQ SUMMIT MADRID 2017

#SQSummit17

Enrique Catalá | Mentor | ecatala@solidq.com | @enriquecatala

Guillermo Perez | DEV | gperez@solidq.com |

Capas de acceso a datos .NET escalables de verdad: el batido perfecto para el rendimiento

de tus bases de datos

SOLIDQ SUMMIT MADRID 2017

Tipología de

acceso

Por conjuntos Por cursores

Patrones de

bajo nivel

Dinámico

Adhoc

Parametrizable

Estático

Stored

procedures

Arquitecturas

Modelo

conectividad

Conectada

Desconectada

Modelo de

desarrollo

Manual

ORM

SOLIDQ SUMMIT MADRID 2017

Fu

nd

am

en

tos • Tiempo de desarrollo

• Diferencia de roles

• Desarrollador vs. DBA

• Independencia de la

aplicación

• Uso de modelo de

datos

• Abstracción de servidor

de base de datos Más

mo

tivo

s • Rechazo a T-SQL

• Manejo de cadenas

para acceso a datos

• Errores en tiempo de

ejecución vs.

Compilación

• Uso de lenguajes más

familiares

• Es más “cool”

SOLIDQ SUMMIT MADRID 2017

SOLIDQ SUMMIT MADRID 2017

Librería Método ¿Qué hace?

Query.PlanCompiler

.PlanCompiler

Compile(cqt.DbCommandTree ctree,

…….)

Compila query hacia SQL Server. Coste

de compilación. Aquí generalmente es

donde debemos poner esfuerzos en

optimizar linq

Objects.Elinq.Compi

ledELinqQueryState

GetExecutionPlan(MergeOption?

forMergeOption)

Obtener plan de ejecución ya

compilado previamente

Objects.Elinq.ELinq

QueryState

GetExecutionPlan(MergeOption?

forMergeOption)

Obtener plan de ejecución todavía no

compilado

Objects.ObjectQuer

y<T>

GetResults(MergeOption?

forMergeOption)

Obtiene datos. Incluye datos

GetExecutionPlan, Compile y el coste de

materializar incluido. Es el coste total

SOLIDQ SUMMIT MADRID 2017

List<T>

O(n)

Dictionary<T,U>

O(1)

SOLIDQ SUMMIT MADRID 2017

Generalmente es preferible hacer menos operaciones a la BBDD con mas conjuntos de filas

SOLIDQ SUMMIT MADRID 2017

SOLIDQ SUMMIT MADRID 2017

SOLIDQ SUMMIT MADRID 2017

public class MyDbContext : DbContext{

//...public DbSet<Product> Products

{ get; set;

}

}

var product = _dbContext.Products.Find(4);

var product2 = _dbContext.Products.AsNoTracking().Where(p => p.Id == 4).FirstOrDefault();Implementación Dapper y EF Core

SOLIDQ SUMMIT MADRID 2017

using(var _dapper = new SqlConnection(config.ConnectionString))

{

_dapper.Open();

var product = _dapper.Query<Product>(@"

SELECT

Id,Name,Col1,Col2

FROM [dbo].[Products]

WHERE Id = @ProductId",

new

{

ProductId = 4

}).FirstOrDefault();

}

Implementación Dapper y EF Core

SOLIDQ SUMMIT MADRID 2017

var order = _dbContext.Orders

.AsNoTracking()

.Include(o => o.Details)

.ThenInclude(d => d.Product)

.Include(o => o.Customer)

.Where(o => o.Id == 4);

Implementación Dapper y EF Core

Hierarchy Load

SOLIDQ SUMMIT MADRID 2017

var orders = _dapper.Query<Order, Customer, Order>("/* Order join with customer */“

,(order, customer) => {order.Customer = customer;return order;

}, queryParam

);

var details = _dapper.Query<OrderDetail, Product,OrderDetail>("/* detail join with product */“, (detail, product) => {

detail.Product = product;return detail;

}, queryParam, splitOn: "OrderId,Id“

);

foreach (var order in orders){

order.Details = detailResult.Where(d => d.OrderId == order.Id).ToList();

}

Implementación Dapper y EF CoreHierarchy Load

SOLIDQ SUMMIT MADRID 2017

var orders = _dapper.Query<Order, Customer, Order>("/* Order join with customer */“

,(order, customer) => {order.Customer = customer;return order;

}, queryParam

);

var details = _dapper.Query<OrderDetail, Product,OrderDetail>("/* detail join with product */“, (detail, product) => {

detail.Product = product;return detail;

}, queryParam, splitOn: "OrderId,Id“

);

//Potencialmente peligroso sin un "lock“. Si ponemos un lock, lo hacemos monothread

Parallel.ForEach(orders, (order) =>{

order.Details = detailResult.Where(d => d.OrderId == order.Id).ToList();

});Implementación Dapper y EF CoreHierarchy Load

SOLIDQ SUMMIT MADRID 2017

var ordersList = _dapper.Query<Order, Customer, Order>(/* ... */

);

var orders = new ConcurrentDictionary<int, Order>(ordersList.ToDictionary(o => o.Id, o => o)

);

var detailsList = _dapper.Query<OrderDetail, Product,OrderDetail>(/*... */

);var details = new ConcurrentDictionary<int, IEnumerable<OrderDetail>>(

detailResult.GroupBy(d => d.OrderId).ToDictionary(

d => d.FirstOrDefault().OrderId, d => d.AsEnumerable()

));

Parallel.ForEach(orders, (o) => {if (details.ContainsKey(o.Key))

o.Value.Details = details[o.Key].ToList();

});

Implementación Dapper y EF CoreHierarchy Load

SOLIDQ SUMMIT MADRID 2017

SOLIDQ SUMMIT MADRID 2017

SOLIDQ SUMMIT MADRID 2017

• Evita dependencia entre clases con el uso de

Interfaces

Arquitectura de

aplicación

• Evita procesados fila a filaCapas de acceso a

datos

• La estructura de datos importa, no es todo BBDDComplejidad

algorítmica

• Ya no estamos en los 90. Hasta tu móvil tiene 8

núcleos ☺

Consideraciones de

concurrencia

• Elige con criterio y úsalo bienORMs

SOLIDQ SUMMITMADRID 2017

GRACIAS!