实体框架查询速度太慢

问题描述:

我是新来的实体框架,喜欢简单但是速度有些麻烦。我想我可能会使用不正确的延迟加载,但很难将其包围。我已经分离了我的数据模型层和业务实体层,并使用一个函数从我的数据模型创建业务实体。在这个函数中,我遍历不同的嵌套实体来创建它们相应的模型。好了,够了散漫这里是一些代码:实体框架查询速度太慢

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

+3

什么是你的'_unitOfWork.GetProductRepository(storeNumber)实现.GetQueryable()',因为如果这部分是错误的,它可能是EF查询您的整个产品表成你的'FirstOrDefault'执行之前的内存,从而减缓它的速度。 – SynerCoder

+0

用该代码更新..谢谢! –

+0

Sql Server是您的后端存储库吗?如果是这样,请使用Sql Server Profiler查看服务器上实际执行的内容。如果有多个语句(比如@SynerCoder建议的语句),那么它可能就是您没有向我们展示的一段代码,它会在执行FirstOrDefault之前实现整个表。无论哪种方式来看看执行什么。如果这看起来是正确的,那么开始分析(调优)查询,如果看起来不对,开始挖掘代码。 – Igor

您可以优化您的查询以避免延迟加载。在这种情况下,当你从数据库加载一个对象时,你就知道你将不得不将几乎整个对象图映射到内存。无论如何,您将需要查找所有这些外键 - 作为一个查询完成所有操作会更快,而不是让延迟加载执行这项工作。有关更多信息,请参见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)) 
+0

在这种情况下,我想做的.Where(p => p.ITEM_NO == itemNumber)包含之前,正确吗?我测试了它,并且它从约8秒变为约20秒,所以我回到调试时没有包含 –

+0

不,你不需要以前的地方。使用EF,所有这些代码都会被转换为一个SQL查询 - 它并不是在C#中实际执行的。这些语句的顺序并不重要,因为它在最后变成了同一个SQL查询。 –

+0

好吧,这是很好的知道..我知道它编译为一个查询,但不知道它是聪明的,以订购的东西..排序的问题,但如果我有几个Where语句它优化我的订单? –