LINQ / EF声明性能的临时变量

时间:2014-02-25 05:47:16

标签: c# sql linq entity-framework

我有一个数据库查询。我可以使用原始SQL快速完成,但我真的想在LINQ中做类似的事情

declare @ruleInstanceCount int
select @ruleInstanceCount
    = (select count(distinct(gri.RuleInstance_Id))
       from [Group] g  
       left join GroupRuleInstance gri on g.id = gri.Group_Id
       where g.name= @groupName)

SELECT cache.EntityKey
from RuleInstanceCurrentMembershipCacheItem cache
left join RuleInstance ri on ri.id = cache.RuleInstanceId 
left join GroupRuleInstance gri on ri.id = gri.RuleInstance_Id
left join [Group] g on g.id = gri.Group_Id 
where cache.IsMember = 1 and g.Name = @groupName 
group by cache.EntityKey
HAVING  count(cache.RuleInstanceId) = @ruleInstanceCount
order by cache.EntityKey

Yay SQL真的很快,因为我可以声明一个变量并在以后使用它

到目前为止,这是我对LINQ的最好尝试,但它的速度要慢50倍

from g in ctx.Groups
where g.Name == groupName
let ruleCount = g.Rules.Select(r => r.Id).Distinct().Count()
from ri in g.Rules
from mem in ri
    .CurrentMembership
    .Where(m => m.IsMember)
    .Select(m => new { m.EntityKey, m.RuleInstanceId, ruleCount })
group mem by mem.EntityKeyinto ekGroup
let ruleCount = ekGroup.Any() ? ekGroup.FirstOrDefault().ruleCount : 0
where ekGroup.Count() == ruleCount
orderby ekGroup.Key
select ekGroup.Key

生成的SQL有点乱(如果需要我可以发布)但是这和我手工编写的SQL有两个重要的区别。

  1. 没有声明声明 - 这意味着它会一遍又一遍地执行实际的@ruleInstanceCount。
  2. 在比较看到规则实例的次数时,没有条款。
  3. 我认为它因为1而变慢但我不知道做声明或类似的任何方式,所以它只执行一次计数。

    enter image description here

    修改

    这里要求的是生成的SQL

    SELECT 
        [Project13].[EntityKey] AS [EntityKey]
        FROM ( SELECT 
            [Project12].[EntityKey] AS [EntityKey]
            FROM ( SELECT 
                [Project11].[EntityKey] AS [EntityKey], 
                [Project11].[C1] AS [C1], 
                [Project11].[C2] AS [C2], 
                [Project11].[C3] AS [C3], 
                (SELECT 
                    COUNT(1) AS [A1]
                    FROM   [dbo].[Group] AS [Extent17]
                    INNER JOIN [dbo].[GroupRuleInstance] AS [Extent18] ON [Extent17].[Id] = [Extent18].[Group_Id]
                    INNER JOIN [dbo].[RuleInstanceCurrentMembershipCacheItem] AS [Extent19] ON ([Extent18].[RuleInstance_Id] = [Extent19].[RuleInstanceId]) AND ([Extent19].[IsMember] = 1)
                    WHERE ((([Extent17].[Name] = @p__linq__0) AND ( NOT ([Extent17].[Name] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent17].[Name] IS NULL) AND (@p__linq__0 IS NULL))) AND ([Project11].[EntityKey] = [Extent19].[EntityKey])) AS [C4]
                FROM ( SELECT 
                    [Project10].[EntityKey] AS [EntityKey], 
                    [Project10].[C1] AS [C1], 
                    [Project10].[C2] AS [C2], 
                    (SELECT 
                        COUNT(1) AS [A1]
                        FROM   [dbo].[Group] AS [Extent14]
                        INNER JOIN [dbo].[GroupRuleInstance] AS [Extent15] ON [Extent14].[Id] = [Extent15].[Group_Id]
                        INNER JOIN [dbo].[RuleInstanceCurrentMembershipCacheItem] AS [Extent16] ON ([Extent15].[RuleInstance_Id] = [Extent16].[RuleInstanceId]) AND ([Extent16].[IsMember] = 1)
                        WHERE ((([Extent14].[Name] = @p__linq__0) AND ( NOT ([Extent14].[Name] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent14].[Name] IS NULL) AND (@p__linq__0 IS NULL))) AND ([Project10].[EntityKey] = [Extent16].[EntityKey])) AS [C3]
                    FROM ( SELECT 
                        [Project9].[EntityKey] AS [EntityKey], 
                        [Project9].[C1] AS [C1], 
                        (SELECT 
                            COUNT(1) AS [A1]
                            FROM   [dbo].[Group] AS [Extent11]
                            INNER JOIN [dbo].[GroupRuleInstance] AS [Extent12] ON [Extent11].[Id] = [Extent12].[Group_Id]
                            INNER JOIN [dbo].[RuleInstanceCurrentMembershipCacheItem] AS [Extent13] ON ([Extent12].[RuleInstance_Id] = [Extent13].[RuleInstanceId]) AND ([Extent13].[IsMember] = 1)
                            WHERE ((([Extent11].[Name] = @p__linq__0) AND ( NOT ([Extent11].[Name] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent11].[Name] IS NULL) AND (@p__linq__0 IS NULL))) AND ([Project9].[EntityKey] = [Extent13].[EntityKey])) AS [C2]
                        FROM ( SELECT 
                            [Project7].[EntityKey] AS [EntityKey], 
                            CASE WHEN ( EXISTS (SELECT 
                                1 AS [C1]
                                FROM   [dbo].[Group] AS [Extent8]
                                INNER JOIN [dbo].[GroupRuleInstance] AS [Extent9] ON [Extent8].[Id] = [Extent9].[Group_Id]
                                INNER JOIN [dbo].[RuleInstanceCurrentMembershipCacheItem] AS [Extent10] ON ([Extent9].[RuleInstance_Id] = [Extent10].[RuleInstanceId]) AND ([Extent10].[IsMember] = 1)
                                WHERE ((([Extent8].[Name] = @p__linq__0) AND ( NOT ([Extent8].[Name] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent8].[Name] IS NULL) AND (@p__linq__0 IS NULL))) AND ([Project7].[EntityKey] = [Extent10].[EntityKey])
                            )) THEN [Project7].[C1] ELSE 0 END AS [C1]
                            FROM ( SELECT 
                                [Project6].[EntityKey] AS [EntityKey], 
                                [Project6].[C1] AS [C1]
                                FROM ( SELECT 
                                    [Project2].[EntityKey] AS [EntityKey], 
                                    (SELECT TOP (1) 
                                        [Project4].[C1] AS [C1]
                                        FROM    (SELECT 
                                            [Extent4].[Id] AS [Id], 
                                            (SELECT 
                                                COUNT(1) AS [A1]
                                                FROM ( SELECT DISTINCT 
                                                    [Extent5].[RuleInstance_Id] AS [RuleInstance_Id]
                                                    FROM [dbo].[GroupRuleInstance] AS [Extent5]
                                                    WHERE [Extent4].[Id] = [Extent5].[Group_Id]
                                                )  AS [Distinct2]) AS [C1]
                                            FROM [dbo].[Group] AS [Extent4]
                                            WHERE (([Extent4].[Name] = @p__linq__0) AND ( NOT ([Extent4].[Name] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent4].[Name] IS NULL) AND (@p__linq__0 IS NULL)) ) AS [Project4]
                                        INNER JOIN [dbo].[GroupRuleInstance] AS [Extent6] ON [Project4].[Id] = [Extent6].[Group_Id]
                                        INNER JOIN [dbo].[RuleInstanceCurrentMembershipCacheItem] AS [Extent7] ON ([Extent6].[RuleInstance_Id] = [Extent7].[RuleInstanceId]) AND ([Extent7].[IsMember] = 1)
                                        WHERE [Project2].[EntityKey] = [Extent7].[EntityKey]) AS [C1]
                                    FROM ( SELECT 
                                        [Distinct1].[EntityKey] AS [EntityKey]
                                        FROM ( SELECT DISTINCT 
                                            [Extent3].[EntityKey] AS [EntityKey]
                                            FROM   [dbo].[Group] AS [Extent1]
                                            INNER JOIN [dbo].[GroupRuleInstance] AS [Extent2] ON [Extent1].[Id] = [Extent2].[Group_Id]
                                            INNER JOIN [dbo].[RuleInstanceCurrentMembershipCacheItem] AS [Extent3] ON ([Extent2].[RuleInstance_Id] = [Extent3].[RuleInstanceId]) AND ([Extent3].[IsMember] = 1)
                                            WHERE (([Extent1].[Name] = @p__linq__0) AND ( NOT ([Extent1].[Name] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent1].[Name] IS NULL) AND (@p__linq__0 IS NULL))
                                        )  AS [Distinct1]
                                    )  AS [Project2]
                                )  AS [Project6]
                            )  AS [Project7]
                        )  AS [Project9]
                    )  AS [Project10]
                )  AS [Project11]
            )  AS [Project12]
            WHERE (([Project12].[C2] = [Project12].[C1]) AND ( NOT ([Project12].[C3] IS NULL OR [Project12].[C1] IS NULL))) OR (([Project12].[C4] IS NULL) AND ([Project12].[C1] IS NULL))
        )  AS [Project13]
        ORDER BY [Project13].[EntityKey] ASC
    

    模特:

    public class Group
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public ICollection<RuleInstance> Rules { get; set; }
    }
    
    public class RuleInstance
    {
        public Guid Id { get; set; }
        public ICollection<Group> Groups { get; set; }
        public ICollection<RuleInstanceCurrentMembershipCacheItem> CurrentMembership { get; set; }
    }
    
    public class RuleInstanceCurrentMembershipCacheItem
    {
        public Guid RuleInstanceId { get; set; }
        public int EntityKey { get; set; }
        public RuleInstance RuleInstance { get; set; }
        public bool IsMember { get; set; }
    }
    

    编辑:

    基于@ MarcinJuraszek的回答,我解决了以下问题:

    var ruleInstances = from g in ctx.Groups
                from ri in g.Rules
                where g.Name == groupName
                select ri.Id;
    
    var cache = (   from g in ctx.Groups
            where g.Name == groupName
            from ri in g.Rules
            from mem in ri.CurrentMembership
            where mem.IsMember
            group mem by mem.AnimalKey into akGroup
            where akGroup.Count() == ruleInstances.Distinct().Count()
            orderby akGroup.Key
            select akGroup.Key).ToArray();
    

    它产生以下查询

    SELECT 
    [Project4].[EntityKey] AS [EntityKey]
    FROM ( SELECT 
        [GroupBy1].[K1] AS [EntityKey]
        FROM     (SELECT 
            [Extent3].[EntityKey] AS [K1], 
            COUNT(1) AS [A1], 
            COUNT(1) AS [A2], 
            COUNT(1) AS [A3]
            FROM   [dbo].[Group] AS [Extent1]
            INNER JOIN [dbo].[GroupRuleInstance] AS [Extent2] ON [Extent1].[Id] = [Extent2].[Group_Id]
            INNER JOIN [dbo].[RuleInstanceCurrentMembershipCacheItem] AS [Extent3] ON ([Extent2].[RuleInstance_Id] = [Extent3].[RuleInstanceId]) AND ([Extent3].[IsMember] = 1)
            WHERE (([Extent1].[Name] = @p__linq__0) AND ( NOT ([Extent1].[Name] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent1].[Name] IS NULL) AND (@p__linq__0 IS NULL))
            GROUP BY [Extent3].[EntityKey] ) AS [GroupBy1]
        CROSS JOIN  (SELECT 
            COUNT(1) AS [A1]
            FROM ( SELECT DISTINCT 
                [Extent5].[RuleInstance_Id] AS [RuleInstance_Id]
                FROM  [dbo].[Group] AS [Extent4]
                INNER JOIN [dbo].[GroupRuleInstance] AS [Extent5] ON [Extent4].[Id] = [Extent5].[Group_Id]
                WHERE (([Extent4].[Name] = @p__linq__1) AND ( NOT ([Extent4].[Name] IS NULL OR @p__linq__1 IS NULL))) OR (([Extent4].[Name] IS NULL) AND (@p__linq__1 IS NULL))
            )  AS [Distinct1] ) AS [GroupBy2]
        CROSS JOIN  (SELECT 
            COUNT(1) AS [A1]
            FROM ( SELECT DISTINCT 
                [Extent7].[RuleInstance_Id] AS [RuleInstance_Id]
                FROM  [dbo].[Group] AS [Extent6]
                INNER JOIN [dbo].[GroupRuleInstance] AS [Extent7] ON [Extent6].[Id] = [Extent7].[Group_Id]
                WHERE (([Extent6].[Name] = @p__linq__1) AND ( NOT ([Extent6].[Name] IS NULL OR @p__linq__1 IS NULL))) OR (([Extent6].[Name] IS NULL) AND (@p__linq__1 IS NULL))
            )  AS [Distinct2] ) AS [GroupBy3]
        CROSS JOIN  (SELECT 
            COUNT(1) AS [A1]
            FROM ( SELECT DISTINCT 
                [Extent9].[RuleInstance_Id] AS [RuleInstance_Id]
                FROM  [dbo].[Group] AS [Extent8]
                INNER JOIN [dbo].[GroupRuleInstance] AS [Extent9] ON [Extent8].[Id] = [Extent9].[Group_Id]
                WHERE (([Extent8].[Name] = @p__linq__1) AND ( NOT ([Extent8].[Name] IS NULL OR @p__linq__1 IS NULL))) OR (([Extent8].[Name] IS NULL) AND (@p__linq__1 IS NULL))
            )  AS [Distinct3] ) AS [GroupBy4]
        WHERE (([GroupBy1].[A1] = [GroupBy2].[A1]) AND ( NOT ([GroupBy1].[A2] IS NULL OR [GroupBy3].[A1] IS NULL))) OR (([GroupBy1].[A3] IS NULL) AND ([GroupBy4].[A1] IS NULL))
    )  AS [Project4]
    ORDER BY [Project4].[EntityKey] ASC
    

2 个答案:

答案 0 :(得分:2)

您的LINQ与SQL的不同之处。首先,在您的SQL中,您有两个查询,但在LINQ中,您尝试将它们合并为一个。为什么?我试图将您的SQL转换为LINQ,我认为,生成的SQL将与原始SQL类似:

var ruleInstanceCount = (
    from g in Group
    join gri in GroupRuleInstance on g.id equals gri.Group_Id into gris
    from gri in gris.DefaultIfEmpty()
    where g.name == groupName
    group gri by gri.RuleInstance_Id into grp
    select new 
        {
            Id = grp.Key
        }
    ).Count();

var items = (
    from cache in RuleInstanceCurrentMembershipCacheItem
    join ri from RuleInstance on cache.RuleInstanceId equals ri.id into ris
    from ri in ris.DefaultIfEmpty()
    join gri from GroupRuleInstance on ri.id equals gri.RuleInstance_Id into gris
    from gri in gris.DefaultIfEmpty()
    join g from Group on gri.Group_Id equals g.id into gs
    from g in gs.DefaultIfEmpty()
    where cache.IsMember == 1 && g.Name = groupName
    group cache by cache.EntityKey into grp
    select new 
        {
            Count = grp.Count(x => x.RuleInstanceId),
            EntityKey = grp.Key
        })
        .Where(x => x.Count == ruleInstanceCount)
        .OrderBy(x => x.EntityKey);

答案 1 :(得分:1)

我会尝试以下内容:

var ctx = new Context();

var groupName = "something";

var ruleInstances = from g in ctx.Groups
                    from gri in g.Rules.DefaultIfEmpty()
                    where g.Name == groupName
                    select gri.Id;

var keys = from c in ctx.CurrentMembership
           let ri = c.RuleInstance
           from g in ri.Groups.DefaultIfEmpty()
           where c.IsMember && g.Name == groupName
           group c by c.EntityKey into g
           where g.Select(x => x.RuleInstanceId).Count() == ruleInstances.Distinct().Count()
           orderby g.Key
           select g.Key;

它应该给你非常接近的SQL:

SELECT cache.EntityKey
from RuleInstanceCurrentMembershipCacheItem cache
left join RuleInstance ri on ri.id = cache.RuleInstanceId 
left join GroupRuleInstance gri on ri.id = gri.RuleInstance_Id
left join [Group] g on g.id = gri.Group_Id 
where cache.IsMember = 1 and g.Name = @groupName 
group by cache.EntityKey
HAVING  count(cache.RuleInstanceId) =
       (select count(distinct(gri.RuleInstance_Id))
       from [Group] g  
       left join GroupRuleInstance gri on g.id = gri.Group_Id
       where g.name= @groupName)
order by cache.EntityKey

我认为你的背景看起来接近那个:

public class Context
{
    public IQueryable<Group> Groups { get; set; }
    public IQueryable<RuleInstance> Rules { get; set; }

    public IQueryable<RuleInstanceCurrentMembershipCacheItem> CurrentMembership { get; set; }
}