代码之家  ›  专栏  ›  技术社区  ›  netmatrix01

LINQ查询性能,比较已编译查询与未编译查询

  •  1
  • netmatrix01  · 技术社区  · 16 年前

    我想知道,如果我对一个集合使用与WHERE子句第一部分完全相同的10个LINQ查询,是否将公共WHERE子句查询提取到一个公共表达式中,会使查询速度更快?

    我做了一个小例子来解释更多。

    public class  Person
    {
        public string First { get; set; }
        public string Last { get; set; }
        public int Age { get; set; }
        public String Born { get; set; }
        public string Living { get; set; }
    }
    
    public sealed class PersonDetails : List<Person>
    {
    }
    
    
    
    PersonDetails d = new PersonDetails();
            d.Add(new Person() {Age = 29, Born = "Timbuk Tu", First = "Joe", Last = "Bloggs", Living = "London"});
            d.Add(new Person() { Age = 29, Born = "Timbuk Tu", First = "Foo", Last = "Bar", Living = "NewYork" });
    
            Expression<Func<Person, bool>> exp = (a) => a.Age == 29;
            Func<Person, bool> commonQuery = exp.Compile();
    
            var lx = from y in d where commonQuery.Invoke(y) && y.Living == "London" select y;
    
            var bx = from y in d where y.Age == 29 && y.Living == "NewYork" select y;
    
            Console.WriteLine("All Details {0}, {1}, {2}, {3}, {4}", lx.Single().Age, lx.Single().First , lx.Single().Last, lx.Single().Living, lx.Single().Born );
            Console.WriteLine("All Details {0}, {1}, {2}, {3}, {4}", bx.Single().Age, bx.Single().First, bx.Single().Last, bx.Single().Living, bx.Single().Born);
    

    因此,如果编写这样的查询是一个好的实践,这里的一些专家能否给我一些建议?

     var lx = "Linq Expression "
    

     var bx = "Linq Expression" ?
    

    任何投入都将受到高度赞赏。

    谢谢, 银

    1 回复  |  直到 16 年前
        1
  •  6
  •   Jon Skeet    16 年前

    首先,埃里克是绝对正确的:如果你关心性能,你需要 测量它 . 准确地计算出您想要测量的内容,并记录您在代码中所做的每一个更改所发生的情况。基准测试有很多方面,我现在没有时间讨论,但关键的一点可能是要确保测试运行的时间足够长,使它们有意义——如果测试只需要50毫秒,那么您不太可能从噪音中分辨出代码的改进。

    现在,如果您使用的是linq-to对象,那么您几乎肯定不想使用表达式树。坚持委托-这就是LinqToObjects使用的方法。

    现在,关于重组……如果你有一个共同的谓词,那么你可以用它过滤你的列表,从中开始,想出一个新的谓词。 IEnumerable<T> . 谓词将被延迟地应用,因此它不会对执行速度产生任何影响,但它 可以 使代码更可读。它可以减缓速度 非常轻微 因为当你有效地得到两个不同的时候,它会引入一个额外的间接级别。 where 条款。

    如果应用过滤器的结果很少,则 可以 想要实现它(例如通过呼叫 ToList )记住结果——这样您就不需要再次查询第二个查询的全部内容了。

    然而, 大的 我能看到的好处是只需要打电话 Single 每个查询一次。目前,您正在对每个属性执行整个查询,这显然是低效的。

    这是您的代码,相应地重写-并使用集合初始值设定项:

    PersonDetails d = new PersonDetails
    {
        new Person {Age = 29, Born = "Timbuk Tu", First = "Joe", 
                   Last = "Bloggs", Living = "London"},
        new Person { Age = 29, Born = "Timbuk Tu", First = "Foo", 
                    Last = "Bar", Living = "NewYork" }
    };
    
    var peopleOfCorrectAge = d.Where(a => a.Age == 29);
    
    var londoners = peopleOfCorrectAge.Where(p => p.Living == "London");
    var newYorkers = peopleOfCorrectAge.Where(p => p.Living == "New York");
    
    var londoner = londoners.Single();
    var newYorker = newYorker.Single();
    
    Console.WriteLine("All Details {0}, {1}, {2}, {3}, {4}",
                      londoner.Age, londoner.First, 
                      londoner.Last, londoner.Living, londoner.Born);
    
    Console.WriteLine("All Details {0}, {1}, {2}, {3}, {4}",
                      newYorker.Age, newYorker.First, 
                      newYorker.Last, newYorker.Living, newYorker.Born);
    

    或者,对于最后一节,封装“写出一个人”的内容:

    DisplayPerson(londoners.Single());
    DisplayPerson(newYorkers.Single());
    
    ...
    
    private static void DisplayPerson(Person person)
    {
        Console.WriteLine("All Details {0}, {1}, {2}, {3}, {4}",
                          person.Age, person.First, 
                          person.Last, person.Living, person.Born);
    }
    
    推荐文章