使用谓词构建器查询速度慢的问题

时间:2011-09-12 08:39:32

标签: asp.net-mvc predicatebuilder

这个问题根本没有时间执行,但如果我取消注释最后一行需要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])
))

解决 原来,最后一个select语句中的INNER JOIN不起作用。所以我将谓词的最后一行更改为:

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 个答案:

答案 0 :(得分:2)

  

如何找到问题?

与往常一样,找出方法是查看生成的SQL,并通过SQL事件探查器运行它。

我的猜测是,当你只对单一联系人类型感兴趣时,它会从简单的内部联接变为更复杂的,甚至可能是“N + 1选择”问题。无论如何,查看SQL应该会让它更加清晰。

答案 1 :(得分:0)

尼古拉斯,

我会按照建议查看SQL,看看该级别发生了什么。我还建议在初始linq查询上执行.Include(),因为这会急切地加载Contacts, Memberships and PartyCategories个实体。否则,你绝对会在N + 1选择模式上延迟加载。请查看以下链接:.included usage:

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

Linq-to-entities - Include() method not loading

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

...欢呼声