sunil kumar meena Ответов: 2

Я могу это сделать.где.список против интерфейса IQueryable.tolist. where, какой запрос лучше с точки зрения производительности?


У меня есть два запроса, оба дают один и тот же результат, но я хочу знать, какой из них более эффективен. Ниже приведены запросы, я написал только предложения запроса. Внутренние условия одинаковы для обоих запросов.

IQueryable ().Где().Список();
IQueryable ().Вызова метода toList().Где();

В моем конце я попробовал ниже код, и он показывает "IQueryable ().Вызова метода toList().Где (); " лучше. Есть несколько вопросов, которые я не понимаю: 1. не видя моего приведенного ниже временного кода, какой запрос более эффективен? 2. Как ФАС, как я знаю, IQueryable является хорошим для выполнения запросов удаленных данных. Итак, не лучше ли сначала отфильтровать элементы, а затем использовать ToList, чтобы нам не нужно было выполнять функцию ToList для нерелевантных элементов? (если это так, то почему ниже кода говорится, что запрос 2 более эффективен?)

Stopwatch st1 = new Stopwatch();
            Stopwatch st2 = new Stopwatch();
            int counter = 10000;
            IEnumerable<Employee> iEmp = null;
            IQueryable<Employee> qEmp = null;
            BindingList<Employee> bList = new BindingList<Employee>();
            for (int i = 1; i <= counter; ++i)
            {
                bList.Add(new Employee
                {
                    Department = $"Dept - {i}",
                    EmployeeID = i,
                    EmployeeName = $"Employee - {i}",
                    Salary = i + 10000
                });
            }

            iEmp = bList.AsEnumerable<Employee>();
            qEmp = bList.AsQueryable<Employee>();

            st1.Start();
            var t = qEmp.Where(x => x.EmployeeID % 2 == 0).ToList();
            st1.Stop();
            Console.WriteLine($"Queryable-Where-ToList: {st1.ElapsedTicks}");

            st2.Start();
            var t1 = qEmp.ToList().Where(x => x.EmployeeID % 2 == 0);
            st2.Stop();
            Console.WriteLine($"Queryable-ToList-Where: {st2.ElapsedTicks}");
            Console.ReadKey();


Что я уже пробовал:

Я попробовал пример, но я не удовлетворен, потому что он противоречит моей теории, и я не в состоянии оправдать результат.

2 Ответов

Рейтинг:
18

Richard Deeming

Во-первых, ваш тест не запрашивает удаленные данные; вы запрашиваете данные в памяти. Между ними не будет большой разницы, когда данные уже находятся в памяти.

Во-вторых, LINQ не выполняет никакой обработки, пока вы не перечислите последовательность. В запросе 1 Вы делаете это, вызывая ToList; в запросе 2 вы не выполняете последовательность, поэтому фильтр никогда не применяется.

В-третьих, ToList метод имеет оптимизацию для случаев, когда входная последовательность является чем-то, что реализует ICollection<T> - он предварительно выделит внутреннюю память списка для правильного размера. Если входные данные не реализуют этот интерфейс, список будет начинаться с места для четырех элементов и удваивать емкость каждый раз, когда в нем заканчивается место. Запрос 1 проходит в итераторе, который не реализует этот интерфейс; запрос 2 проходит в итераторе, который не реализует этот интерфейс. BindingList<T>, который делает реализуйте этот интерфейс.

И, наконец, оценка производительности кода-сложная тема. Вам нужно "разогреть" код, позволив JIT-компилятору скомпилировать его; и вам нужно выполнить код, который вы тестируете, много раз. Ваши текущие тесты не делают ни того, ни другого, поэтому результаты ничего не стоят.


Чтобы ответить на ваш вопрос, .Where(...).ToList() будет эффективнее, чем .ToList().Where(...) для любого реального сценария. Особенно с удаленными данными (например: база данных), где фильтр может быть вычислен в источнике, ограничивая количество возвращаемых объектов.


Рейтинг:
0

F-ES Sitecore

IQueryable действительно предназначен только для объектов, которые действительно его используют. В вашем случае оба ваших запроса действительно используют только IEnumerable, однако когда вы используете IQueryable, вы просто оборачиваете IEnumerable в другой интерфейс (IQueryable), ваш базовый BindingList не поддерживает IQueryable.

Если вы использовали провайдера, который поддерживает IQueryable, например EntityFramework, то ваш .Вызова метода toList().Где() спровоцирует

"выберите поля из таблицы"

запросите (on ToList) и возьмите все результаты в память, и ваш Where будет работать над этим списком результатов в памяти.

Ваш.Где().Однако ToList () будет преобразован в оператор "select fields from table where...", поэтому ToList будет загружать только эти записи в память.

Так и для эф .Где.ToList лучше, так как это означает, что извлекаются только соответствующие данные, тогда как .Список.Где получает все данные и делает фильтр в памяти.

Поскольку вы не используете провайдера, поддерживающего IQueryable, ваш вызов IQueryable такой же, как и ваш IEnumerable, но с некоторыми дополнительными накладными расходами.