Skip to content

Translate Count(x => p(x)) more efficiently if the SUM(IIF(P, 1, 0)) technique applies #2651

@GSPP

Description

@GSPP

Count(x => somePredicate) is being translated as a subquery at the moment (EF6). If somePredicate is merely a scalar computation over x (and really whatever else is in scope at that point) EF can use a much better SQL pattern:

SUM(IIF(somePredicate, 1, 0))

(Or anything equivalent).

The same ideas applies to conditional sums:

grouping.Where(x => p(x)).Sum(x => s(x))

Should become:

grouping.Sum(x => p(x) ? s(x) : 0)

Another rewrite:

grouping.Select(x => f(x)).Sum(x => s(x))

Should become:

grouping.Sum(x => s(f(x)))

I don't see how those rewrites could ever do harm. They should be applies successively until everything has been moved into the sum or count. The rewrites should be added to make conditional counts and sum, even over computed values, a lot more efficient.

Test query:

                var results = (from o in db.Orders
                               group o by o.CustomerID into g
                               select new
                               {
                                   CustomerID = g.Key,
                                   Count = g.Count(x => x.ID >= 0),
                               }).ToList();

SQL:

SELECT 
[Distinct1].[CustomerID] AS [CustomerID], 
(SELECT 
    COUNT(1) AS [A1]
    FROM [dbo].[Orders] AS [Extent2]
    WHERE ([Distinct1].[CustomerID] = [Extent2].[CustomerID]) AND ([Extent2].[ID] >= 0)) AS [C1]
FROM ( SELECT DISTINCT 
    [Extent1].[CustomerID] AS [CustomerID]
    FROM [dbo].[Orders] AS [Extent1]
)  AS [Distinct1]

Model:

public class Customer
{
    public int ID { get; set; }
    public string Name { get; set; }
    public bool? HasFreeShipping { get; set; }

    public virtual IList<Order> Orders { get; set; }
}

public class Order
{
    public int ID { get; set; }
    public int CustomerID { get; set; }
    public Customer Customer { get; set; }
    public DateTime CreateDateTime { get; set; }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions