LINQ和来自大数据库的选择行

时间:2013-04-12 07:24:01

标签: c# linq iqueryable

我有一些数据库,现在它包含一个大约有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. 它将从数据库和服务器端加载所有行,并返回从“从”到“到”的范围内的记录。其他将被忽略。在这种情况下,我的应用程序将遇到很大的麻烦。想象一下,每次从数据库加载1 000 000行。这将是灾难。
  2. 它将构造SQL请求,只返回我需要的行而不加载其他行。这正是我需要的。
  3. 我认为这将是两个场景,但我不确定,也无法检查。我是对的吗?

3 个答案:

答案 0 :(得分:4)

作为旁注,您不必致电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代码的问题:

答案 1 :(得分:3)

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

使用IQueryable接口,不运行SQL。正是在您调用IEnumerable.GetEnumerator()时,底层Linq Provider将WHOLE表达式转换为查询。在这种情况下是一个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)。

答案 2 :(得分:1)

你是对的。 2.场景将会发生。当查询是eventuallty exectuted时。

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

queryRes.Skip(from).Take(to)

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

如果您想要准确测试会发生什么,请尝试下载LinqPad - 这对于解密linq查询非常有用。