2016-01-20 4 views
0

У меня есть еще один вопрос о производительности с EF.Производительность с платформой Entity

Там один способ получить объект из контекста:

tDocumentTyp DocumentTypObject = Context.tDocumentTyps.Where(s => s.DocumentTypID == iTypID).FirstOrDefault(); 

Этот метод занимает ~ 2979 мс.

Тогда я написал метод, чтобы получить DBSet с помощью отражения и выполняется таким образом:

tDocumentTyp DocumentTypObject = Context.GetEntries<tDocumentTyp>().Where(s => s.DocumentTypID == iTypID).FirstOrDefault(); 

Мой метод нуждается в ~ 222 мс для выполнения.

Итак, теперь мой вопрос: почему мой метод намного быстрее первоначального? Или что-то не так с моим методом?

Чтобы сделать это немного легче, вот мой метод для получения DBSet с помощью отражения:

public static IEnumerable<T> GetEntries<T>(this AppContext DataContext, 
    string PropertyName = null, IEnumerable<string> includes = null) where T : IEntity 
{ 
    Type ContextType = typeof(AppContext); 
    PropertyInfo Entity = null; 
    if (null == PropertyName) 
     Entity = ContextType.GetProperty(typeof(T).Name) 
        ?? ContextType.GetProperty(typeof(T).Name + "s"); 
    else 
     Entity = ContextType.GetProperty(PropertyName); 

    if (null == Entity) 
     throw new Exception("Could not find the property. If the property is not equal to the tablesname, you have to parametrize it."); 
    DbQuery<T> set = ((DbSet<T>)Entity.GetValue(DataContext, null)); 
    if (includes != null) 
     includes.ForEach(f => set = set.Include(f)); 
    return set; 
} 
+0

EF - это ОРМ. Он генерирует и выполняет SQL-инструкции. Где создаются запросы? Имеет ли базовая таблица индексы? Вы даже получаете одинаковые результаты? Как вы оценили код? Ваш метод возвращает запрос в IEnumerable, который должен * выполнить * запрос. –

+0

Эй, да, у меня такие же результаты. Я могу изменять значения через контекст и сохранять и все нормально на данный момент ... нет индексов –

+0

Нет индексов означает, что серверу придется искать * все * строки, чтобы найти совпадение. Тем не менее, вы все еще не размещали * SQL-запросы, созданные. Вы не можете устранить неисправность SQL, если не знаете, что выполняется, и против чего - сколько строк? Как вы подключаетесь к базе данных? Как вы используете код? Например, вы можете часто считывать кешированные значения, думая, что каким-то образом метод secod работает быстрее. Повторно ли вы используете один и тот же контекст в тестах? –

ответ

0

Второй пример получает всю таблицу и применения Where в памяти. Вы применяете метод расширения System.Linq.Enumerable.Where, который работает на IEnumerable<T>. Обратите внимание, что это реализация в памяти. В первом примере вы используете метод расширения System.Linq.Queryable.Where, который работает на IQueryable<T>. Это другой метод, хотя они имеют одно и то же имя.

Если вы внимательно осмотритесь, вы также обнаружите, что в первом примере параметр метода имеет тип Expression<Func<T, bool>>, а во втором примере это просто Func<T, bool>. Это очень важная разница: выражение может быть обработано для создания SQL-запроса.

Так почему же второй быстрее? Ну, это сложно ответить без дополнительной информации о вашем источнике данных. Но, как отметили другие пользователи в комментариях, если база данных не индексируется, то, возможно, быстрее будет выбрать всю таблицу и выполнить фильтр в памяти, чем использовать фильтр SQL для фильтрации.

+0

Это не означает, что второй запрос будет быстрее, а тем более менее 10 раз. В обоих случаях сервер должен сканировать все строки. В случае № 1, хотя будет возвращена только 1 строка. Во втором случае вся таблица будет отправлена ​​обратно. Возможно, если аппаратное обеспечение сервера очень * медленно, а набор данных мал, выполнение вычисления на клиенте происходит быстрее. Скорее всего, что код тестирования неверен и, например, использует кешированные значения –

+0

@PanagiotisKanavos Server не нужно «сканировать» все строки, чтобы вернуть всю таблицу, а не в том смысле, в котором это необходимо, если есть «где» '. Выбор всей таблицы - это оптимизированная операция для большинства реализаций сервера.EDIT: Просто для уточнения, я не возражаю против вашей точки зрения, что она, вероятно, не должна быть быстрее :) Просто указывая, что выбор всей таблицы может быть оптимизирован. –

+0

В обоих случаях потребуется сканирование таблицы - это то, что происходит, когда индекс не используется. В первом случае, однако, queyr, скорее всего, «SELECT TOP 1 ... WHERE ...». Будет возвращена только одна строка. Во втором - все строки. На самом деле, я бы поспорил, что планы выполнения для обоих запросов показывают, что второй случай требует намного больше ввода-вывода. OP, хотя и не предоставил запросы, планы выполнения или даже размер данных. 10x просто нелогично. –

Смежные вопросы