我正在使用C# 4.0在ServiceStack REST应用程序中使用FluentNHibernate,但这个问题通常适用于NHibernate LINQ查询。
哪种方法更受鼓励: (方法1) 快速运行一个简单的查询,返回所有与用户ID匹配的行:
// Query the User by id
var user = session.Get<User>(request.UserId);
然后可以单独使用LINQ在返回的List上进一步缩小结果范围:
// '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;
方法二,更鼓励运行一个更复杂的查询来在单个查询中完成上述操作:
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在5000次迭代中花费了147.291秒。
最后一次迭代的查询结果:
{ Timestamp=1348659703485, Latitude=179.40000, Longitude=209.40000 }
{ Timestamp=1348659703486, Latitude=179.55000, Longitude=209.55000 }
{ Timestamp=1348659703487, Latitude=179.70000, Longitude=209.70000 }
{ Timestamp=1348659703488, Latitude=179.85000, Longitude=209.85000 }
{ Timestamp=1348659703489, Latitude=180.00000, Longitude=210.00000 }
方法2在5000次迭代中花费了133.728秒。
最后一次迭代的查询结果:
{ Timestamp=1348659703485, Latitude=179.40000, Longitude=209.40000 }
{ Timestamp=1348659703486, Latitude=179.55000, Longitude=209.55000 }
{ Timestamp=1348659703487, Latitude=179.70000, Longitude=209.70000 }
{ Timestamp=1348659703488, Latitude=179.85000, Longitude=209.85000 }
{ Timestamp=1348659703489, Latitude=180.00000, Longitude=210.00000 }
差异:方法2大约快了13.5秒。
b) 长期重复使用和稳定性
DateTime.Now.Timestamp
移出查询并存储在临时变量中,会发生什么?这是否会在数据库中被映射和重复执行?正如@lowleveldesign所说,看到NHibernate生成的原始SQL将是有趣的。 - Tim Croydonvar locationsQuery = ...
实际上并没有查询数据库。var
是IQueryOver<LocationModel>
而不是List<LocationModel>
。这些测试是否等效? - Andrew WhitakerlocationsQuery.List<LocationModel>();
,但这应该无关紧要,因为这会使代码变得更长,对吧? - Jason