【问题标题】:In LINQ expression how to get FirstOrDefault with better performance?在 LINQ 表达式中如何获得具有更好性能的 FirstOrDefault?
【发布时间】:2018-02-05 14:46:59
【问题描述】:

在我们的 Xamarin Forms 应用程序中,此代码:

return database.GetAllWithChildren<Review>(x => x.ProductId == prodId, true).OrderByDescending(x => x.ReviewId).FirstOrDefault();

存在性能问题,该产品的评论越多,需要的时间越长。

对于一个有 7 条评论的产品,大约需要 17 秒,这是不可接受的。

如何优化性能?

毕竟我不需要所有评论信息,只需要最新的。

这似乎检索了所有 7 条评论,然后对它们进行降序排序,然后获得列表中的第一个。

有没有办法只获取具有最大 ID 的那个?

【问题讨论】:

  • 17 秒听起来有些过分,即使您加载了所有 7 条评论。您可能需要在 RDBMS 中添加一些缺失的索引。
  • 我在使用 LINQ 和 SQLiteNetExtensions 时遇到了很多性能问题。似乎它总是在执行过滤器或排序之前将所有数据加载到内存中。所以我最终放弃了,将检索策略改为SQL查询字符串。
  • 使用 Martin Zikmund 解决方案,查询在 5 秒内加载。不是很好,但有很大的改进。
  • 我也会用 SQL 查询字符串进行测试并告诉你结果

标签: performance linq xamarin linq-to-sql xamarin.forms


【解决方案1】:

似乎使用GetAllWithChildren 是问题所在。此方法递归地加载所有评论的信息,而不仅仅是一个。然后从数据库返回的所有数据之后执行排序和选择。

解决方案是先过滤,然后才返回Review

var review = database.Table<Review>().Where(x => x.Product == prodId ).
              OrderByDescending( x => x.ReviewId ).FirstOrDefault();
database.GetChildren( review, true );
return element;

【讨论】:

  • 我测试了这两种解决方案,您的解决方案性能最佳!非常感谢
  • 从 17 秒提高到 5 秒。 :)
  • GetChildren 方法和 true 用于递归确实加载了相关对象的整个树,它似乎工作效率不高。您最好手动运行选择查询以获取您实际需要的对象并将它们分配给评论的属性。
【解决方案2】:

database.GetAllWithChildren&lt;Review&gt; 返回完整构建的评论的List&lt;Review&gt;。这意味着产品拥有的评论越多,FirstOrDefault() 在构建后立即丢弃的评论就越多。

尝试先获取最大 id,然后过滤评论:

// This assumes that ID is int. Change to another nullable type matching ReviewId
int? maxId = database.Reviews.Where(r => r.ProductId == prodId).Max((int?)r.ReviewId);
return database
    .GetAllWithChildren<Review>(x => x.ProductId == prodId && x.ReviewId == maxId, true)
    .SingleOrDefault();

【讨论】:

  • @MartinZikmund 对,我忘了添加Where 条件。谢谢!
  • 谢谢你我测试了这个并且它有效。但是 Zikmund 的解决方案的性能稍好一些。非常感谢!
猜你喜欢
  • 2020-11-07
  • 2021-02-19
  • 2013-01-18
  • 2011-11-26
  • 2013-09-03
  • 1970-01-01
  • 2011-11-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多