Как оптимизировать Entity Framework Queries - PullRequest
4 голосов
/ 05 августа 2009

Я использую Linq-To-Entities для выполнения запроса, который возвращает только 947 строк, но для его выполнения требуется 18 секунд. Я сделал «ToTraceString», чтобы получить базовый sql и запустить то же самое непосредственно в базе данных и получить то же время.

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

Глядя на план выполнения запроса, есть пара вложенных циклов, которые занимают 95% времени, но они уже работают с индексами?

Есть ли у кого-нибудь идеи о том, как принудительно оптимизировать запрос EF?

РЕДАКТИРОВАТЬ: Предоставление дополнительной информации

Базовая диаграмма ER для трех таблиц выглядит следующим образом:

People >----People_Event_Link ----< Events
P_ID        P_ID                    E_ID
            E_ID

Линк, который я запускаю, предназначен для возврата всех событий для определенного человека (с использованием P_ID):

        var query = from ev in genesisContext.Events
                    join pe in genesisContext.People_Event_Link
                    on ev equals pe.Event
                    where pe.P_ID == key
                    select ev;
        return query;

Вот сгенерированный SQL (глубокий вдох!):

SELECT 
1 AS [C1], 
[Extent1].[E_ID] AS [E_ID], 
[Extent1].[E_START_DATE] AS [E_START_DATE], 
[Extent1].[E_END_DATE] AS [E_END_DATE], 
[Extent1].[E_COMMENTS] AS [E_COMMENTS], 
[Extent1].[E_DATE_ADDED] AS [E_DATE_ADDED], 
[Extent1].[E_RECORDED_BY] AS [E_RECORDED_BY], 
[Extent1].[E_DATE_UPDATED] AS [E_DATE_UPDATED], 
[Extent1].[E_UPDATED_BY] AS [E_UPDATED_BY], 
[Extent1].[ET_ID] AS [ET_ID], 
[Extent1].[L_ID] AS [L_ID]
FROM  [dbo].[Events] AS [Extent1]
INNER JOIN [dbo].[People_Event_Link] AS [Extent2] ON  EXISTS (SELECT 
    1 AS [C1]
    FROM    ( SELECT 1 AS X ) AS [SingleRowTable1]
    LEFT OUTER JOIN  (SELECT 
        [Extent3].[E_ID] AS [E_ID]
        FROM [dbo].[Events] AS [Extent3]
        WHERE [Extent2].[E_ID] = [Extent3].[E_ID] ) AS [Project1] ON 1 = 1
    LEFT OUTER JOIN  (SELECT 
        [Extent4].[E_ID] AS [E_ID]
        FROM [dbo].[Events] AS [Extent4]
        WHERE [Extent2].[E_ID] = [Extent4].[E_ID] ) AS [Project2] ON 1 = 1
    WHERE ([Extent1].[E_ID] = [Project1].[E_ID]) OR (([Extent1].[E_ID] IS NULL) AND ([Project2].[E_ID] IS NULL))
)
WHERE [Extent2].[P_ID] = 291

Ответы [ 3 ]

4 голосов
/ 05 августа 2009

Да. Перепишите запрос LINQ. Большинство запросов LINQ to Entities могут быть написаны разными способами и по-разному переведены в SQL. Поскольку вы не показываете ни LINQ, ни SQL, ни план запроса, это все, что я могу сказать.

Вы умны, тем не менее, пытаться выполнить SQL напрямую. Компиляция запросов также может занять некоторое время, но вы исключили это, определив, что SQL учитывает все измеренное время.

Попытка:

    var query = from pe in genesisContext.People_Event_Link
                where pe.P_ID == key
                from ev in pe.Event // presuming one to many
                select ev;

или, если pe.Event один к одному:

    var query = from pe in genesisContext.People_Event_Link
                where pe.P_ID == key
                select pe.Event;

    return query;
1 голос
/ 06 августа 2009

@ Craig Я не смог заставить ваш запрос работать, так как я получаю сообщение об ошибке, в котором говорится, что не удалось определить тип при вызове SelectMany.

Однако я воспользовался вашим советом и отказался от использования соединения с запросом типа ANDE "olde style":

        var query = from pe in genesisContext.People_Event_Link
                    from ev in genesisContext.Events
                    where pe.P_ID == key && pe.Event == ev
                    select ev;

Который производит довольно приличный sql!

1 голос
/ 05 августа 2009

Поскольку 95% времени находится во вложенных циклах, их устранение должно решить проблему.

Есть несколько вещей, на которые вы можете посмотреть:

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

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

Обычно я использую профилировщик SQL-сервера, чтобы посмотреть, что производит SQL linq, мне легче, особенно если у вас два экрана.

Если у вас все еще есть проблемы, опубликуйте запрос linq.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...