EntityFramework - 仅从集合中加载最后一个子项(性能问题)

时间:2017-02-22 13:59:01

标签: c# entity-framework entity-framework-5

这是我的模特:

public partial class auctions
{
    public int id { get; set; }
    public virtual ICollection<auction_data> auction_data { get; set; }
}
public partial class auction_data
{
    public int id { get; set; }
    public int auction_id { get; set; }
    public string title { get; set; }
    public virtual auctions auctions { get; set; }
}

每次拍卖都可能附加数千个auction_data项目。 但我只对最后一个感兴趣:

var matchingAuctions = context.auctions.Where(a => /** some conditions **/);
foreach (auctions auction in matchingAuctions)
{
    var data = auction.auction_data.LastOrDefault(); // <---- takes very long time and memory when having large count of auction_data
}

似乎EF将所有auction_data加载到内存中,然后返回最后一个。 问题是:如何提高此代码的性能并避免将所有这些记录加载到内存中?

编辑:一些时间

DateTime t1 = DateTime.Now;
var data = auction.auction_data.LastOrDefault();
DateTime t2 = DateTime.Now;
TimeSpan diff = t2 - t1; // 8.8s


DateTime t1 = DateTime.Now;
var data = auction.auction_data.OrderByDescending(a => a.id).FirstOrDefault();
DateTime t2 = DateTime.Now;
TimeSpan diff = t2 - t1; // 8.7s

DateTime t1 = DateTime.Now;
var data = auction.auction_data.Last();
DateTime t2 = DateTime.Now;
TimeSpan diff = t2 - t1; // 8.7s

int id = auction.id;
DateTime t1 = DateTime.Now;
var data = context.auction_data.Where(d => d.auction_id == id).OrderByDescending(d => d.id).FirstOrDefault();
DateTime t2 = DateTime.Now;
TimeSpan diff = t2 - t1; // 0.06s

2 个答案:

答案 0 :(得分:2)

这很正常。当你写auction.auction_data时,它会读取所有auction.auction_data。如果我是你,我会这样做以获得更好的表现:

public partial class auctions
{
  public int id { get; set; }
  public int lastDataId { get; set;}
  public virtual ICollection<auction_data> auction_data { get; set; }
}

并且在插入数据时将id作为最后一个插入。

作为测试:我没有要测试的大型数据库,但是改变Last()而不是LastOrDefault()可能会阻止你。我读到了这个:

LastOrDefault是一种有用的方法。它找到集合中与条件匹配的最后一个元素

所以要测试加工条件需要读取所有记录,但可能 Last()不会

答案 1 :(得分:0)

变化:

var data = auction.auction_data.LastOrDefault();

为:

var data = auction.auction_data.OrderByDescending(x => x.id).FirstOrDefault();