Проблема с медленным запросом с использованием построителя предикатов - PullRequest
0 голосов
/ 12 сентября 2011

Этот вопрос не занимает времени, но если я раскомментирую последнюю строку, это займет 5 секунд.Как это может так сильно повлиять на запрос?Это почти точно такой же запрос.

return db.Parties.Where(predicate).Select(p => new SearchResult
{
    adressPerson = p.Contacts.SingleOrDefault(m => m.contact_type == "H").streetname,
    //adressOrg = p.Contacts.SingleOrDefault(m => m.contact_type == "W").streetname
});  

Как мне найти проблему?

Вот как выглядит предикат:

    predicate = predicate.Or(p => p.surname.EndsWith(keyword));
    predicate = predicate.Or(p => p.lastname.EndsWith(keyword));
    predicate = predicate.Or(p => p.organisation.EndsWith(keyword));
    predicate = predicate.Or(p => p.Contacts.Any(c => c.streetname.EndsWith(keyword)));
    predicate = predicate.Or(p => p.Memberships.Any(m => m.Congregation.congregation_name.EndsWith(keyword)));
    predicate = predicate.Or(p => p.PartyCategories.Any(m => m.Category.category_name.EndsWith(keyword) || m.Category.category_code.EndsWith(keyword)));  

Я знаю, что глупо публиковать много кода, но в любом случае это SQL-запрос.Есть какие-нибудь подсказки?

SELECT (
    SELECT [t6].[streetname]
    FROM [dbo].[Contact] AS [t6]
    WHERE ([t6].[contact_type] = @p7) AND ([t6].[party_id] = [t0].[party_id])
    ) AS [adressPerson], (
    //SELECT [t7].[streetname]
    //FROM [dbo].[Contact] AS [t7]
    //WHERE ([t7].[contact_type] = @p8) AND ([t7].[party_id] = [t0].[party_id])
    //) AS [adressOrg]
FROM [dbo].[Party] AS [t0]
WHERE ([t0].[surname] LIKE @p0) OR ([t0].[lastname] LIKE @p1) OR ([t0].[organisation] LIKE @p2) OR (EXISTS(
    SELECT NULL AS [EMPTY]
    FROM [dbo].[Contact] AS [t1]
    WHERE ([t1].[streetname] LIKE @p3) AND ([t1].[party_id] = [t0].[party_id])
    )) OR (EXISTS(
    SELECT NULL AS [EMPTY]
    FROM [dbo].[Membership] AS [t2]
    LEFT OUTER JOIN [dbo].[Congregation] AS [t3] ON [t3].[congregation_id] = [t2].[congregation_id]
    WHERE ([t3].[congregation_name] LIKE @p4) AND ([t2].[party_id] = [t0].[party_id])
    )) OR (EXISTS(
    SELECT NULL AS [EMPTY]
    FROM [dbo].[PartyCategories] AS [t4]
    INNER JOIN [dbo].[Category] AS [t5] ON [t5].[category_id] = [t4].[category_id]
    WHERE (([t5].[category_name] LIKE @p5) OR ([t5].[category_code] LIKE @p6)) AND ([t4].[party_id] = [t0].[party_id])
))

решено Оказалось, что INNER JOIN в последнем операторе select не работает.Поэтому я изменил последнюю строку предиката на:

predicate = predicate.Or(p => p.PartyCategories
    .GroupJoin(db.Categories, b => b.category_id, c => c.category_id, (b, c) => new { b, c })
    .SelectMany(c => c.c.DefaultIfEmpty(), (c, b) => new { c.c, b })
    .Any(m => m.b.category_name.EndsWith(keyword) || m.b.category_code.EndsWith(keyword)));

Ответы [ 2 ]

2 голосов
/ 12 сентября 2011

Как мне найти проблему?

Как всегда, способ выяснить это посмотреть на сгенерированный SQL и запустить его через SQL profiler.

Я предполагаю, что это превращается из простого внутреннего соединения, когда вас интересует только один тип контакта, во что-то более сложное или, возможно, даже проблему "N + 1-выбор". В любом случае, изучение SQL должно сделать его более понятным.

0 голосов
/ 12 сентября 2011

Никлас,

Я бы посмотрел на предложенный SQL, чтобы увидеть, что происходит на этом уровне. Я бы также предложил сделать .Include() в исходном запросе linq, так как это с готовностью загрузит Contacts, Memberships and PartyCategories сущности. В противном случае вы определенно будете лениво загружать шаблон выбора N + 1. Проверьте следующую ссылку для .included использования:

http://blogs.msdn.com/b/alexj/archive/2009/06/02/tip-22-how-to-make-include-really-include.aspx

Linq-to-entity - метод Include () не загружается

http://www.singingeels.com/Articles/Entity_Framework_and_Lazy_Loading.aspx

веселит ...

...