Linq Query Performance, сравнивая скомпилированный запрос с некомпилированным - PullRequest
1 голос
/ 22 марта 2010

Мне было интересно, если бы я извлек запрос общего предложения 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" ?

Любые материалы будут высоко оценены.

Спасибо, AG

1 Ответ

6 голосов
/ 22 марта 2010

Во-первых, Эрик абсолютно прав: если вы беспокоитесь о производительности, вам нужно измерить ее .Выясните, что именно вы хотите измерить, и запишите, что происходит для каждого изменения, которое вы вносите в свой код.Существуют различные аспекты бенчмаркинга, на которые у меня сейчас нет времени, но ключевым из них, вероятно, является обеспечение того, чтобы тесты выполнялись достаточно долго, чтобы они были значимыми - если ваш тест занимает всего 50 мс, вывряд ли удастся отличить ваш код от шума.

Теперь, если вы используете LINQ to Objects, вы почти наверняка не хотите использовать деревья выражений вообще.Придерживайтесь делегатов - это то, что LINQ to Objects использует в любом случае.

Теперь, что касается реструктуризации ... если у вас есть общий предикат, то вы можете отфильтровать свой список по этому, чтобы начать сс новым IEnumerable<T>.Предикат будет применен лениво, поэтому он не будет иметь никакого значения для скорости выполнения, но он может сделать ваш код более читабельным.Это может замедлить работу очень незначительно , поскольку это создаст дополнительный уровень косвенности, когда вы фактически получите два разных предложения where.

Если результат применения фильтров будет иметьочень мало результатов, вы можете захотеть его материализовать (например, позвонив по номеру ToList) и запомнить результат - таким образом вам не нужно снова запрашивать все для второго запроса.

Тем не менее, big преимущество, которое я вижу, заключается в том, чтобы вызывать 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...