【问题标题】:LINQ and selection rows from big database大数据库中的 LINQ 和选择行
【发布时间】:2013-04-12 07:24:01
【问题描述】:

我现在有一些数据库,它包含一个大约 100 行的表。但将来它不会有 100 行而是 1 000 000+ 行,我必须小心我现在正在开发的 Web 应用程序。

下一个问题是:在网页上,我需要创建分页列表来向用户显示记录。这是我打算使用的代码示例

public IQueryable<MyTable> GetRows(int from, int to)
{
   var queryRes = (from row in SomeDataContext.MyTable
                   order by row.id
                   select row).AsQueriable();
   return queryRes.Take(to).Skip(from);
}

这只是代码示例。我没有运行它。 但问题是在这种情况下会发生什么?我看到了两个场景

  1. 它将从数据库和服务器端加载所有行,并返回从 'from' 到 'to' 范围内的记录。其他将被忽略。在这种情况下,我的应用程序会有很大的麻烦。想象一下每次从数据库中加载 1 000 000 行。这将是一场灾难。
  2. 它将构造 SQL 请求,只返回我需要的行而不加载其他行。这正是我需要的。

我认为这将是 2 种情况,但我不确定也无法检查。我说的对吗?

【问题讨论】:

  • @GertArnold 这有关系吗?它是一个可查询的 Linq。作为一个接口,它可以是 L2S L2EF 或 L2nH,它仍然可以正常工作。
  • 我认为一个好的计划是将SomeDataContext.Log 设置为某个值(例如Console.Out),然后您就可以确切地看到正在使用的SQL。
  • 我问是因为SomeDataContext 可以是任何东西。它建议 L2S,但谁知道呢?并且抽象是泄漏的。每个引擎都有自己的策略来实现分页。例如,L2E 要求您在 Skip 之前进行排序。
  • 我使用实体框架,它类似于 MyEntities SomeDataContext = new MyEntities();

标签: c# linq iqueryable


【解决方案1】:

附带说明,您不必致电AsQueryable。做就够了

var queryRes = SomeDataContext.MyTable.OrderBy(r => r.Id);
return queryRes.Take(to).Skip(from);

并回答您的问题 - 场景 2 将被执行。您始终可以使用 SQL Server Profiler 检查生成的 SQL,但如果您使用的是 Entity Framework,您甚至可以使用queryRes.ToString()。正如@Aron 正确指出的那样——只有在枚举结果(例如调用queryRes.ToList())时,才会对数据库实际执行查询。

这些问题更详细地解决了查找 SQL 代码的问题:

【讨论】:

  • queryRes.ToString() 不会给出生成的 SQL。您需要使用.ToTraceString(),并且需要将查询转换为ObejctQuery&lt;T&gt; ,然后才能执行此操作
  • @JensKloster - 你试过了吗?我的 EF 有点生疏,我可能记错了,但 ToTraceString 是旧的做法,而在较新的 EF 版本中,ToString 返回 SQL 生成的查询。不过需要仔细检查。
  • 我不知道 :) 我在 Ef 4.1 中进行了测试,但它不起作用。但在较新版本的 EF 中,您很可能是对的。 ToString()返回生成的SQL
  • @JensKloster - 据此:social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/… ToString 应该可以解决问题。我将能够在今天晚些时候对其进行测试。
【解决方案2】:

严格来说,1 和 2 都不正确。运行代码不会命中数据库。它构造了一个表达式树。调用代码仍然可以进一步修改表达式树而无需访问数据库。

使用 IQueryable 接口不运行 SQL。正是在您调用 IEnumerable.GetEnumerator() 时,底层 Linq 提供程序将整个表达式转换为查询。本例是一个 SQL 查询,然后运行它。

例如,使用此代码。你可以有

void Main()
{
    var foo = from x in GetRows(10, 10)
            where x.Id > 1000
            select x;
    foreach(var f in foo)
    {
        //Stuff
    }
}

实际运行的sql实际上会更接近

SELECT a,b,c FROM 
(SELECT a,b,c, ROW_NUMBER() OVER (ORDER BY ...) as row_number
FROM Table
WHERE id > 1000) t0
WHERE to.row_number BETWEEN 10 and 20;

说实话,你做错了。您不需要 GetRows 方法。我会在构建表本身时直接调用 Linq 查询。你应该看看 MVC 脚手架使用的 IRepository 模式。

最后,如果这被称为 AJAX 的 WebQuery,我会看看 .net 中的两个 OData 实现(WCF 数据服务和 WebAPI OData)。

【讨论】:

    【解决方案3】:

    你是对的。 2.情景是会发生什么。当查询最终被执行时。

    我建议反转 Take - Skip,所以你从 Skip 开始

    queryRes.Skip(from).Take(to)
    

    Debuggen 这个方法不会对数据库进行任何调用。它只是返回查询 - 而不是结果。

    如果您想准确测试会发生什么,请尝试下载 LinqPad - 它非常适合揭开 linq 查询的神秘面纱。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-31
      • 1970-01-01
      • 1970-01-01
      • 2010-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-17
      相关资源
      最近更新 更多