实体框架查询速度太慢
我是新来的实体框架,喜欢简单但是速度有些麻烦。我想我可能会使用不正确的延迟加载,但很难将其包围。我已经分离了我的数据模型层和业务实体层,并使用一个函数从我的数据模型创建业务实体。在这个函数中,我遍历不同的嵌套实体来创建它们相应的模型。好了,够了散漫这里是一些代码:实体框架查询速度太慢
IM_ITEM.cs(产品数据模型)
public partial class IM_ITEM
{
public IM_ITEM()
{
this.IM_INV = new HashSet<IM_INV>();
this.IM_BARCOD = new HashSet<IM_BARCOD>();
this.IM_GRID_DIM_1 = new HashSet<IM_GRID_DIM_1>();
this.IM_GRID_DIM_2 = new HashSet<IM_GRID_DIM_2>();
this.IM_GRID_DIM_3 = new HashSet<IM_GRID_DIM_3>();
this.IM_PRC = new HashSet<IM_PRC>();
}
public string ITEM_NO { get; set; }
public string DESCR { get; set; }
// many more properties...
public virtual ICollection<IM_INV> IM_INV { get; set; }
public virtual ICollection<IM_BARCOD> IM_BARCOD { get; set; }
public virtual ICollection<IM_GRID_DIM_1> IM_GRID_DIM_1 { get; set; }
public virtual ICollection<IM_GRID_DIM_2> IM_GRID_DIM_2 { get; set; }
public virtual ICollection<IM_GRID_DIM_3> IM_GRID_DIM_3 { get; set; }
public virtual ICollection<IM_PRC> IM_PRC { get; set; }
}
业务实体的创建方法:
public static ProductEntity FromEfObject(IM_ITEM obj) {
var product = new ProductEntity {
ItemNumber = obj.ITEM_NO,
StyleNumber = obj.VEND_ITEM_NO,
Title = obj.DESCR_UPR,
LongName = obj.ADDL_DESCR_1,
ShortDescription = obj.DESCR,
VendorCode = obj.ITEM_VEND_NO,
Quarter = obj.ATTR_COD_2,
Color = obj.PROF_ALPHA_2,
Markdown = obj.PRC_1,
Price = obj.REG_PRC ?? 0,
Status = obj.STAT,
DepartmentCode = obj.ATTR_COD_1,
DepartmentDigit = obj.ATTR_COD_1.Substring(0, 1),
MixAndMatch = obj.MIX_MATCH_COD,
Inventory = new Inventory(obj.IM_INV),
Sizes = new List<ProductSize>(),
Widths = new List<ProductSize>(),
Lengths = new List<ProductSize>(),
Barcodes = new Dictionary<string, string>()
};
if (obj.IM_PRC.Any()) {
var price = obj.IM_PRC.First();
product.DnsPrice2 = price.PRC_2.GetValueOrDefault();
product.DnsPrice3 = price.PRC_3.GetValueOrDefault();
}
foreach (var barcode in obj.IM_BARCOD) {
product.Barcodes.Add(barcode.DIM_1_UPR, barcode.BARCOD);
}
foreach (var size in obj.IM_GRID_DIM_1) {
product.Sizes.Add(ProductSize.FromEfObject(size));
}
foreach (var width in obj.IM_GRID_DIM_2) {
product.Widths.Add(ProductSize.FromEfObject(width));
}
foreach (var length in obj.IM_GRID_DIM_3) {
product.Lengths.Add(ProductSize.FromEfObject(length));
}
if (!product.Sizes.Any()) {
product.Sizes.Add(new ProductSize());
}
if (!product.Widths.Any()) {
product.Widths.Add(new ProductSize());
}
if (!product.Lengths.Any()) {
product.Lengths.Add(new ProductSize());
}
return product;
}
而我的方法来检索模式:
public ProductEntity GetProductById(string itemNumber, int storeNumber) {
var product = _unitOfWork
.GetProductRepository(storeNumber)
.GetQueryable()
.FirstOrDefault(p => p.ITEM_NO == itemNumber);
return product == null ? null : ProductEntity.FromEfObject(product);
}
而GetQueryable方法:
internal DbSet<TEntity> DbSet;
public GenericRepository(TContext context)
{
Context = context;
DbSet = context.Set<TEntity>();
}
public virtual IQueryable<TEntity> GetQueryable()
{
IQueryable<TEntity> query = DbSet;
return query;
}
更多信息..我使用数据库优先建模来创建我的数据模型,而我测试的数据库没有大量数据。另外,我尝试在我的GetProductById
方法中使用.Include()
加载(急切地相信),但是它进一步放慢了速度。
我在做一些根本性的错误吗?或者正在使用EF对于这样的查询会变得很慢。
编辑:为了防止延迟加载我我的查询更新为:
public ProductEntity GetProductById(string itemNumber, int storeNumber) {
var product = _unitOfWork
.GetProductRepository(storeNumber)
.GetQueryable()
.Include(p => p.IM_INV.Select(i => i.IM_INV_CELL))
.Include(p => p.IM_BARCOD)
.Include(p => p.IM_GRID_DIM_1)
.Include(p => p.IM_GRID_DIM_2)
.Include(p => p.IM_GRID_DIM_3)
.Include(p => p.IM_PRC)
.FirstOrDefault(p => p.ITEM_NO == itemNumber);
return product == null ? null : ProductEntity.FromEfObject(product);
}
跟踪时,这给了我一个很大的讨厌的查询比使用懒加载需要较长的时间http://pastebin.com/LT1vTETb
您可以优化您的查询以避免延迟加载。在这种情况下,当你从数据库加载一个对象时,你就知道你将不得不将几乎整个对象图映射到内存。无论如何,您将需要查找所有这些外键 - 作为一个查询完成所有操作会更快,而不是让延迟加载执行这项工作。有关更多信息,请参见here。
它应该是这个样子:
public ProductEntity GetProductById(string itemNumber, int storeNumber) {
var product = _unitOfWork
.GetProductRepository(storeNumber)
.GetQueryable()
.Include(p => p.IM_BARCOD)
.Include(p => p.IM_GRID_DIM_1)
.Include(p => p.IM_GRID_DIM_2)
.Include(p => p.IM_GRID_DIM_3)
.Include(p => p.IM_PRC)
.FirstOrDefault(p => p.ITEM_NO == itemNumber);
return product == null ? null : ProductEntity.FromEfObject(product);
}
需要注意的是,如果这些外键都有自己的外键(即IM_BARCOD具有IM_OtherType的集合),你还需要映射到你ProductEntity模式,你还应该包括那些。你可以做到这一点符合这样的:
.Include(p => p.IM_BARCOD.Select(b => b.IM_OTHERTYPE))
在这种情况下,我想做的.Where(p => p.ITEM_NO == itemNumber)包含之前,正确吗?我测试了它,并且它从约8秒变为约20秒,所以我回到调试时没有包含 –
不,你不需要以前的地方。使用EF,所有这些代码都会被转换为一个SQL查询 - 它并不是在C#中实际执行的。这些语句的顺序并不重要,因为它在最后变成了同一个SQL查询。 –
好吧,这是很好的知道..我知道它编译为一个查询,但不知道它是聪明的,以订购的东西..排序的问题,但如果我有几个Where语句它优化我的订单? –
什么是你的'_unitOfWork.GetProductRepository(storeNumber)实现.GetQueryable()',因为如果这部分是错误的,它可能是EF查询您的整个产品表成你的'FirstOrDefault'执行之前的内存,从而减缓它的速度。 – SynerCoder
用该代码更新..谢谢! –
Sql Server是您的后端存储库吗?如果是这样,请使用Sql Server Profiler查看服务器上实际执行的内容。如果有多个语句(比如@SynerCoder建议的语句),那么它可能就是您没有向我们展示的一段代码,它会在执行FirstOrDefault之前实现整个表。无论哪种方式来看看执行什么。如果这看起来是正确的,那么开始分析(调优)查询,如果看起来不对,开始挖掘代码。 – Igor