【问题标题】:NHibernate LINQ query performance, which code fragment is better?NHibernate LINQ 查询性能,哪个代码片段更好?
【发布时间】:2012-09-25 07:20:07
【问题描述】:

这个问题是问以下两种方法中哪一种更受鼓励(以及出于什么原因)?

我正在使用 C# 4.0 在 ServiceStack REST 应用程序中使用 FluentNHibernate,但这个问题对于 NHibernate LINQ 查询很常见。

是否更鼓励:

(方法 1) 快速运行 简单 查询,该查询返回与用户 ID 匹配的所有行:

// Query the User by id
var user = session.Get<User>(request.UserId);

然后在返回的 List 上单独使用 LINQ 进一步缩小结果:

// 'User' contains a 'List<Location>'
var locations = user.Locations.Where(location =>
                        location.Timestamp >= (request.MinTimestamp.HasValue ? request.MinTimestamp.Value : 0) &&
                        location.Timestamp <= (request.MaxTimestamp.HasValue ? request.MaxTimestamp.Value : DateTime.Now.ToTimestamp()));

return locations;

(方法 2)或,是否更鼓励在单个查询中运行 更复杂的 查询:

var locationsQuery = session.QueryOver<LocationModel>()
                        .Where(table => table.User.Id == request.UserId)
                        .And(table => table.Timestamp >= (request.MinTimestamp.HasValue ? request.MinTimestamp.Value : 0))
                        .And(table => table.Timestamp <= (request.MaxTimestamp.HasValue ? request.MaxTimestamp.Value : DateTime.Now.ToTimestamp()));

return locationsQuery.List();

如果我的目标是:

a) 更快的执行时间


基准(修订)

修改后的完整测试代码:http://pastebin.com/0ykKwcxX

基准输出:

方法 1 耗时 147.291 秒超过 5000 次迭代。

上一次迭代的查询结果:
{ 时间戳=1348659703485,纬度=179.40000,经度=209.40000 }
{ 时间戳=1348659703486,纬度=179.55000,经度=209.55000 }
{ 时间戳=1348659703487,纬度=179.70000,经度=209.70000 }
{ 时间戳=1348659703488,纬度=179.85000,经度=209.85000 }
{ 时间戳=1348659703489,纬度=180.00000,经度=210.00000 }

方法 2 耗时 133.728 秒超过 5000 次迭代。

上一次迭代的查询结果:
{ 时间戳=1348659703485,纬度=179.40000,经度=209.40000 }
{ 时间戳=1348659703486,纬度=179.55000,经度=209.55000 }
{ 时间戳=1348659703487,纬度=179.70000,经度=209.70000 }
{ 时间戳=1348659703488,纬度=179.85000,经度=209.85000 }
{ 时间戳=1348659703489,纬度=180.00000,经度=210.00000 }

区别:方法 2 快了大约 13.5 秒。


b) 长期重复使用和稳定性

【问题讨论】:

  • 在执行时间方面,你为什么不测试一下看看?
  • 我很惊讶第二种方法似乎更慢。你检查过 NHibernate 执行的 SQL 查询吗?可以发一下吗?
  • 在第一种情况下,您应该得到两个查询,例如:select * from Users where UserId = , select * from Locations where UserId = 。在第二种情况下,我们应该只有一个查询:select * from Locations where UserId = 。在您的测量中,第二个选项几乎慢了 2 倍 - 这让我感到惊讶。
  • 如果将DateTime.Now.Timestamp 移出查询并将其存储在临时变量中会怎样?这是否在数据库中重复映射和执行?正如@lowleveldesign 所说,看到 NHibernate 生成的原始 SQL 会很有趣。
  • var locationsQuery = ... 实际上根本没有查询数据库。 var 是 IQueryOver&lt;LocationModel&gt; 而不是 List&lt;LocationModel&gt;。测试是否相等?

标签: performance linq fluent-nhibernate benchmarking queryover


【解决方案1】:

如果您的目标是更快的执行时间,那么我认为第二种方法最好,因为它不会对用户实体进行不必要的加载。话虽如此,我不是 NHibernate 用户,所以不确定,并且可以肯定的是,如果重要的话,你应该进行一些测量的性能测试(“你不能改进你无法测量的东西” - 不记得是谁说的,但这是一个很好的格言)。

Ayende 写了很多值得一看的好 NHibernate 帖子(例如 http://ayende.com/blog/3988/nhibernate-the-difference-between-get-load-and-querying-by-id)

当涉及到“长期重复使用和稳定性”时,这取决于您如何使用此代码。您始终可以重构查询部分,以便您的用户 ID 和时间戳过滤器是扩展方法。示例见这篇文章:http://lostechies.com/jimmybogard/2012/08/30/evolutionary-project-structure/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-06
    • 2015-03-14
    • 1970-01-01
    • 2011-11-24
    • 1970-01-01
    • 2011-12-02
    • 1970-01-01
    相关资源
    最近更新 更多