【问题标题】:Trying to query data from an enormous SQL Server table using EF 5尝试使用 EF 5 从巨大的 SQL Server 表中查询数据
【发布时间】:2015-12-22 23:08:28
【问题描述】:

我正在处理一个包含 8000 万 (80,000,000) 行的 SQL Server 表。数据空间 = 198,000 MB。毫不奇怪,针对该表的查询经常会发生变化或超时。为了增加这些问题,表行会相当频繁地更新,并且还会定期添加新行。因此,它像病毒爆发一样继续增长。

我的问题是我想编写 Entity Framework 5 LINQ to Entities 查询来从这个怪物表中获取行。正如我所尝试的那样,超时已成为彻底的流行病。还有一些事情:表的主键已编入索引,并且在其 19 列中的 4 列上具有非聚集索引。

到目前为止,我正在编写使用事务范围和读取未提交隔离级别的简单 LINQ 查询。我尝试增加命令超时和连接超时。我编写了返回 FirstOrDefault() 或集合的查询,如下所示,它试图从当前日期前 7 天获取单个 ID(一个 int):

public int GetIDForSevenDaysAgo(DateTime sevenDaysAgo)
{
    using (var txn = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted }))
    {                
        var GetId = from te in _repo.GetTEvents()
                    where te.cr_date > sevenDaysAgo
                    orderby te.cr_date
                    select te.id;

        return GetId.FirstOrDefault();
    }
}

public IEnumerable<int> GetIDForSevenDaysAgo(DateTime sevenDaysAgo)
{
    using (var txn = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted }))
    {                
        var GetId = from te in _repo.GetTEvents()
                    where te.cr_date > sevenDaysAgo
                    orderby te.cr_date
                    select te.id;

        return GetId.Take(1);
    }
}

无论超时设置如何,每个查询都会重复超时。我将存储库模式与 Unity DI 一起使用,并通过 IQueryable&lt;&gt; 调用获取表。我还将存储库调用限制为从当前日期起八天(希望只获取这个庞大表的所需子集)。我正在使用 Visual Studio 2013 和针对 .NET v4.5 和 SQL Server 2008 R2 的更新 5。

我生成了 EF 生成的 SQL 语句,它看起来并不比上面的 LINQ 语句复杂得多。而且我的大脑很痛。

那么,我是否达到了某种对 EF 的容忍度限制?桌子太大了吗?查询此表时是否应该恢复为存储过程/域方法?我还有其他选择吗?有一些关于删除表格行的讨论,但这可能不会很快发生。我确实阅读了一些关于分页的内容,但我不确定这是否有帮助。任何想法或想法将不胜感激!谢谢!

【问题讨论】:

  • 能否展示 EF 生成的查询和表结构,如果可以的话,加上查询计划。
  • 第一个问题:您的表上是否有一个 index 包含 te.cr_date 列(单独或作为索引中的第一列)?

标签: sql-server linq c#-4.0 entity-framework-5


【解决方案1】:

我可以看到您只选择数据而不更改它。那么为什么需要使用TransactionScope?仅当您的代码中有 2 个或更多 SaveChanges() 并且您希望它们在一个事务中时才需要它。所以摆脱它。

在您的情况下,我应该使用的另一件事是禁用更改跟踪和自动检测您的上下文中的更改。但是,如果您没有在每个请求上重新阅读您的上下文,请小心。它可以保存旧数据。

要做到这一点,你应该在你的上下文初始化附近写下这行:

context.ObjectTrackingEnabled = false;
context.DeferredLoadingEnabled = false;

您应该考虑的另一件事是分页和缓存。但正如我在你的例子中看到的那样,你试图只得到一行。所以不能说什么特别的。

我建议您阅读this article 以进一步优化。

【讨论】:

    【解决方案2】:

    很难说您是否必须使用存储过程或 EF,因为我们代表一个怪物。 :-)

    我要做的第一件事是在显示实际执行计划的 SSMS 中运行查询。有时它会提供有关缺失索引的信息,这可能会提高性能。

    从您的示例中,我很确定您需要在该日期列上建立索引。

    换句话说,如果您有权访问,请确保表设计对于该数据量是最佳的。

    我的想法是,如果一个简单的查询挂了,EF 还能做什么?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-13
      • 1970-01-01
      • 2013-07-18
      • 2015-03-28
      • 2015-10-17
      • 1970-01-01
      • 2021-08-09
      相关资源
      最近更新 更多