EntityFramework - 仅从集合中加载最后一个子项(性能问题)
Posted
技术标签:
【中文标题】EntityFramework - 仅从集合中加载最后一个子项(性能问题)【英文标题】:EntityFramework - load only last child from collection (performance issue) 【发布时间】:2017-07-12 14:59:29 【问题描述】:这是我的模型:
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;
每次拍卖都可能附有数千个拍卖数据项。 但我只对最后一个感兴趣:
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 将所有拍卖数据加载到内存中,然后返回最后一个。 问题是:如何提高此代码的性能并避免将所有这些记录加载到内存中?
编辑:一些时机
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
【问题讨论】:
您可以反转排序,然后使用First()
而不是Last()
在没有应用排序的情况下,为什么你会选择最后一行? 定义...最后一个? (最高 ID/最新日期时间?)
也尝试过这种方式,但得到了相同的结果
我认为不是..auction.auction_data.OrderByDescending(a => /** column name **/).FirstOrDefault()
不会检索所有行...
最后一个元素是插入到表中的最后一个元素(它的 ID 最高)
【参考方案1】:
这很正常。当您编写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() 不需要
【讨论】:
我从一开始就不相信OrderByDescending
。这几乎是一样的。但我建议的最后一种(好)方法,你需要有数据ID。 ?
还有一点:var data = context.auction_data.Where(d => d.auction_id == id).OrderByDescending(d => d.id).FirstOrDefault();
不需要排序 id为主键时只有一个元素【参考方案2】:
变化:
var data = auction.auction_data.LastOrDefault();
到:
var data = auction.auction_data.OrderByDescending(x => x.id).FirstOrDefault();
【讨论】:
我试过这种方式,但几乎没有区别(在我的测试用例中是 8.8 秒 vs 8.7 秒) 你有适当的索引吗?我想知道,因为当你的数据库表被正确索引时,EF 确实表现得很好。 是的,我在 ID 上设置了主键。正如我所提到的,问题是 EF 将整个表读入内存,然后返回记录,而不是只从表中读取一行以上是关于EntityFramework - 仅从集合中加载最后一个子项(性能问题)的主要内容,如果未能解决你的问题,请参考以下文章