2016-11-08 5 views
1

Меня попросили исследовать причину плохого выполнения запроса в нашей базе данных. Я решил, что он был сгенерирован оператором LINQ и отследил его до исходного кода и загрузил его в linqpad. В Linqpad я отобразил сгенерированный SQL, как показано ниже. Как вы можете видеть, первая часть предложения WHERE не нужна и значительно замедляет запрос, избегая индексов. Он должен просто запрашивать ключ DocumentStorageId, и все. В инструкции IN() нет смысла, каждая строка в таблице продуктов имеет одно из этих значений и не является нулевым. Любые идеи о том, как я могу изменить свой оператор linq, чтобы идентификатор был первым и попал в индексы?Почему этот запрос LINQ Framework Entity Framework генерирует медленное предложение where?

void Main() 
{ 
    var uow = new UnitOfWork(this); 
    var repo = new Repository<Product>(this,uow); 
    var documentStorageId = new Guid("473BAE6B-A1A1-49BE-9FD5-AB6B870A82B1"); 
    var result = repo.Queryable() 
       .Where(x => x.DocumentStorageId == documentStorageId)     
       .FirstOrDefault(); 
    result.Dump();    
} 

Сгенерированный SQL Выход:

SELECT  
     [Extent1].[AColumn], 
     [Extent1].[BColumn] 
    FROM [dbo].[Product] AS [Extent1] 
    WHERE 
      ([Extent1].[ProductType] IN  
       (N'Type1',N'Type2',N'Type3',N'Type4',N'Type5',N'Type6')) 
    AND ([Extent1].[DocumentStorageId] = @p__linq__0) 

EDIT: уточнить далее, модель создается с помощью Code First. Продукт является базовым классом. Существует 6 производных типов продукта (Type1, Type2 и т. Д.). ProductType - это столбец дискриминатора. Поэтому кажется, что EF пытается включить все возможные типы Продуктов, но зачем беспокоиться? Включение всех - это то же самое, что не указывать конкретный, а предложение IN() делает запрос медленным.

+1

Я не уверен, почему 'IN' используется здесь только с базовым' .Where (x => x.Id == Id) 'use. Вы уверены, что нет каких-либо дополнительных ограничений? –

+0

Да, я согласен с travis, это не вызвано кодом, который вы опубликовали, можете ли вы отправить свой код конфигурации модели и модели. –

+0

@Travis Как я сказал в вопросе, когда я помещаю верхний оператор в LinqPad и нажимаю «Show Generated SQL», я получаю дно. Я ЗНАЮ, что это не имеет смысла и не является оптимальным, поэтому я публикую этот вопрос. – redwards510

ответ

0

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

Существует два способа решить эту проблему.

  1. Привяжите не-tph DbSet в свой контекст и используйте это.
  2. Добавить индекс по (ProductType, DocumentStorageId), так что здесь может быть быстрым
+0

Это таблица за иерархию. ProductType - это столбец дискриминатора. – redwards510

+0

@ redwards510 обновленный ответ. Концепция и решения одинаковы :) –

+0

Я выбрал это как ответ, потому что у него были некоторые ответные ответы, хотя я не очень понимаю # 1. Повторная установка всей нашей базы данных не является вариантом. Я использовал Query Analyzer, чтобы предложить некоторые индексы и использовал их для повышения производительности. – redwards510

0

Есть 6 производные типы продукта (Type1, TYPE2 и т.д.). ProductType - это столбец дискриминатора.

Вы знаете это ... но EF не знает об этом. Насколько мне известно, у вас есть 20 типов продуктов, но только сказал EF об этих 6. Представьте себе путаницу, когда вы попросите их всех, и она вернула 20, хотя есть только 6, на которые вы запрограммировали.

Почему этот запрос LINQ Framework Entity Framework генерирует медленное предложение where?

Поэтому, чтобы запрос возвращался как ожидалось, здесь используется предложение in. (Также одна из причин, которые я предпочитаю TPT над TPH).

+0

TPT еще менее удобен для запросов. –

+0

IMHO Присоединение более дружелюбное, чем столбец дискриминатора, поверх того факта, что это фактически нормализованная таблица. –

+0

Несомненно, модель данных лучше, но одно внешнее соединение на каждый подтип при запросе всех типов, хм ... (Не говорите никому, но я всегда стараюсь избежать наследования с помощью EF.) –

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

  • Нет связанных вопросов^_^