Linq和Ienumerable懒惰查询。效率损失了?

时间:2013-01-10 11:21:12

标签: c# performance linq ienumerable

我一直在读,Ienumerables不会马上跑。所以我试图找到查询列表的最佳方法。

以下是我的getAll方法。接下来是我的过滤方法。接下来是一个首选的过滤方法(可读性)。

我的问题是,第三种方法是否与直接查询相同?换句话说,它会或者不会从数据库加载所有myObjects然后过滤?或者从DB获取时进行过滤。

   public static IEnumerable<myObject> getAll()
    {
        using (var db = Database.OpenConnectionString(blahblah))
        {
            var queryResults = db.Query("SELECT * FROM vu_myObjects");

            return queryResults .Select(x => new myObject(x.myObjectName, x.myObjectF));
        }
    }

    public static IEnumerable<myObject> getAllForFilter(String filter)
    {
        using (var db = Database.OpenConnectionString(blahblah))
        {
            var queryResults  = db.Query("SELECT * FROM vu_myObjects WHERE ObjectF = @0", filter);

            return queryResults.Select(x => new myObject(x.myObjectName, x.ObjectF));
        }
    }

   public static IEnumerable<myObject> getAllForFilter(String filter)
    { // Not checked syntax.
        return getAll().Where(x => x.ObjectF = filter);
    }

或者,如果你有更好的建议,我会全力以赴。

2 个答案:

答案 0 :(得分:3)

  

它会不会从DB加载所有myObjects然后过滤?

不会,因为您还没有真正查询过数据库。因此,IQueryable<T>已延迟执行,以便实际返回执行查询所需的结果集。这可以通过几种方式完成,例如调用ToList或迭代列表。

任何过滤,即您的Where子句,都将在DB端完成。

实际上,您目前的代码甚至无法正常工作 - 它会抛出ObjectDisposedException,因为您在处理数据后尝试对延迟查询应用过滤器上下文。要使代码生效,您需要将where子句作为参数传递给getAll方法,例如

public static IEnumerable<myObject> getAll(Expression<Func<myObject,bool>> where)
{
    using (var db = Database.OpenConnectionString(blahblah))
    {
        var queryResults = db.Query("SELECT * FROM vu_myObjects");
        if (where != null)
        {
            queryResults.Where(where);
        }
        return queryResults .Select(x => new myObject(x.myObjectName, x.myObjectF));
    }
}

public static IEnumerable<myObject> getAllForFilter(String filter)
{ // Not checked syntax.
    return getAll(x => x.ObjectF = filter);
}

<强>更新

正如您刚刚指出的那样,您使用WebMatrix.Database以上都不适用,因为这里没有发生延迟执行。 Query方法立即执行并返回IEnumerable<T>的结果集,因此任何过滤后应用的过滤都将在内存中完成。因此,就效率而言,第一种过滤方法会更好,因为它在数据库方面做了所有事情。

您可以同时获得可读性和安全性。通过将Where子句转换为实际字符串并将其附加到查询中来提高效率。

答案 1 :(得分:2)

他们基本上都是一样的。在你实际查询从getAlLForFilter调用返回的IEnumerable之前,它将是一个懒惰的评估查询。如果你在它上面调用.ToList()或访问内容,那么它将调用数据库。如果在第3次调用中设置断点,则在告诉调试器评估查询之前,您将看到它不会包含查询结果。