LINQtoSQL缓存问题

时间:2010-02-16 19:16:43

标签: linq-to-sql caching

我一直在做很多阅读,但没有在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对象吗?如果我错过了这个标记,有没有好办法呢?

像往常一样,谢谢!!!

1 个答案:

答案 0 :(得分:4)

请勿使用该链接文章中的代码。我不知道那个人吸烟的是什么,但代码基本上读取了表的全部内容并将其放入内存缓存中。对于一个非平凡的表格,我想不出更糟糕的选择(35,000条记录绝对是非平凡的)。

Linq to SQL不会缓存查询。 Linq to SQL 跟踪特定的实体,使用主键查询查询。这意味着如果你:

  1. 查询某些实体的DataContext;
  2. 更改这些实体(但暂不调用SubmitChanges);
  3. 运行另一个检索相同实体的查询。
  4. 然后,上面#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。我没有测试过这种方法,我不确定在实践中使用它会比上面容易多少(你仍然必须专门选择使用它,它不是自动的),但是我将它列为一种可能的替代方案。