我一直在做很多阅读,但没有在LinqToSql缓存上找到任何好的答案...我想问我问题的最好方法就是问问题。
我有一个jQuery脚本,它根据脚本从表格每行的前两个单元格获取的信息调用WCF服务。基本上它循环遍历表,使用表格单元格中的信息调用服务,并根据服务返回的信息更新行。
服务本身基于来自客户端的信息运行查询,基本上是以下形式:
Dim b = From r In db.batches _
Where r.TotalDeposit = amount _
And r.bDate > startDate AndAlso r.bDate < endDate _
Select r
使用firebug我注意到每个响应都在125ms-3secs之间。我做了一些研究,遇到了关于缓存LINQ对象的article并将其应用到我的项目中。我能够将对象计数(b.Count)之类的东西作为页面中的响应返回并注意到它是缓存的,所以我以为我正在用油脂做饭...但是当我尝试运行上面的查询时缓存的对象时间变得一致700ms,太长了。
我在某处读到LINQ自动缓存,所以我做了以下事情:
Dim t As New List(Of batch)
Dim cachedBatch = From d In db.batches _
Select d
t = From r In cachedBatch _
Where r.TotalDeposit = amount _
And r.bDate > startDate AndAlso r.bDate < endDate _
Select r
Return t
现在查询运行的响应时间始终为120-140毫秒......我假设它的缓存,因为对db运行查询需要一点时间(&lt; 35,000条记录)。
我想我的问题是,我应该尝试缓存LINQ对象吗?如果我错过了这个标记,有没有好办法呢?
像往常一样,谢谢!!!
答案 0 :(得分:4)
请勿使用该链接文章中的代码。我不知道那个人吸烟的是什么,但代码基本上读取了表的全部内容并将其放入内存缓存中。对于一个非平凡的表格,我想不出更糟糕的选择(35,000条记录绝对是非平凡的)。
Linq to SQL不会缓存查询。 Linq to SQL 跟踪特定的实体,使用主键查询查询。这意味着如果你:
DataContext
; SubmitChanges
); 然后,上面#3的结果将与您在(1)中检索的实体相同,并且您在(2)中进行了更改 - 换句话说,您将获得Linq已经跟踪的现有实体,而不是旧的数据库中的实体。但它仍然必须执行查询以便知道要加载哪些实体;更改跟踪不是性能优化。
如果您的数据库查询花费的时间超过100毫秒,那么问题几乎肯定在数据库端。您可能在要查询的列上没有相应的索引。如果要缓存而不是处理DB perf问题,则需要缓存特定查询的结果,您可以通过将它们键入用于创建查询的参数来完成。例如(C#):
IEnumerable<Batch> GetBatches(DateTime startDate, DateTime endDate,
Decimal amount)
{
string cacheKey = string.Format("GetBatches-{0}-{1}-{2}",
startDate, endDate, amount);
IEnumerable<Batch> results = Cache[cacheKey];
if (results != null)
{
return results;
}
results = <LINQ QUERY HERE>.ToList();
Cache.Add(cacheKey, results, ...);
return results;
}
只要在项目位于缓存中时无法更改结果,或者您不关心获取过时结果,这样就可以了。如果这是一个问题,那么它开始变得更复杂,我不会在这里涉及所有细微之处。
底线是,“缓存”表中的每个记录根本不缓存,它将一个高效的关系数据库(SQL Server)变成一个草率低效的内存数据库(缓存中的通用列表) 。如果需要,请不要缓存表,缓存查询,在您决定这样做之前,尝试解决数据库本身的性能问题。
为了记录,我还应该注意到有人似乎已经实现了一种缓存形式based on the IQueryable<T>
itself。我没有测试过这种方法,我不确定在实践中使用它会比上面容易多少(你仍然必须专门选择使用它,它不是自动的),但是我将它列为一种可能的替代方案。