0

I have realized that SQL Server is unable efficiently process some basic SQL queries, such as:

SELECT TOP (1) [t0].[Id], [t0].[L1], [t0].[L2], [t0].[Value]
FROM [Foos] AS [t0]
INNER JOIN [Lookup1] AS [t1] ON [t1].[Id] = [t0].[L2]
INNER JOIN [Lookup2] AS [t2] ON [t2].[Id] = [t0].[L1]
WHERE ([t1].[Name] = 'a') AND ([t2].[Name] = 'b')
ORDER BY [t0].[Value]

which is generated from LINQ expression:

// query 1

Foos
.Where(f => f.Lookup1.Name == "a" && f.Lookup2.Name == "b")
.OrderBy(f => f.Value)
.Take(1)

The schema definition is in question 'Index over multiple lookup tables in SQL Server'. @Hoots in the answer shows that the SQL query must look like:

SELECT TOP (1) [t0].[Id], [t0].[L1], [t0].[L2], [t0].[Value]
FROM [Foos] AS [t0]
CROSS JOIN (
    SELECT TOP (1) [t1].[Id], [t2].[Id] AS [Id2]
    FROM [Lookup1] AS [t1], [Lookup2] AS [t2]
    WHERE ([t1].[Name] = 'a') AND ([t2].[Name] = 'b')
    ) AS [t3]
WHERE ([t0].[L1] = [t3].[Id]) AND ([t0].[L2] = [t3].[Id2])
ORDER BY [t0].[Value] DESC

which could be generated from the following LINQ expression:

// query 2

(from f in Foos
from l in (
    from l1 in Lookup1s
    from l2 in Lookup2s
    where l1.Name == "a"
        && l2.Name == "b"
    select new { L1 = l1.Id, L2 = l2.Id }).Take(1)
where f.L1 == l.L1 && f.L2 == l.L2
orderby f.Value descending
select f).Take(1)

My question is how to automatically rewrite the query 1 into query 2? So I could compose queries in multiple steps:

void Do()
{
    var x = ListFoos("a", "b").OrderBy(f => f.Value).Take(2);
    // ...
}

IQueryable<Foos> ListFoos(string l1, string l2)
{
    var foos = Foos.AsQueryable();
    if (l1 != null)
        foos = foos.Where(f => f.Lookup1.Name == l1);
    if (l2 != null)
        foos = foos.Where(f => f.Lookup2.Name == l2);
    return foos;
}

Has someone done that already? Is there a library simplifying the task?

Clarification:

The resulting expression of IQueryable<> is translated into SQL statement which SQL Server is unable efficiently evaluate. So I need to transform the expression into an expression which is translated into better SQL statement for SQL Server.

I think that I am not the first who has encountered this issue. LINQ is a longer time here and the SQL statements are pretty basic, so other developers might already have been solving this problem with SQL Server.

Community
  • 1
  • 1
TN.
  • 18,874
  • 30
  • 99
  • 157
  • I need to do it in runtime. So I could rewrite the query formed in multiple function calls. (l1 and l2 are variables provided by users.) – TN. May 07 '14 at 15:01
  • 1
    There is no automatic way, but when you say `SQL Server is unable efficiently process some basic SQL queries` I wonder why you came to this conclusion – crthompson May 07 '14 at 15:01
  • See http://stackoverflow.com/questions/23386540/index-over-multiple-lookup-tables-in-sql-server. – TN. May 07 '14 at 15:02

1 Answers1

0

I'm not 100% certain I know what you're asking for, but if I am right, you should look at PredicateBuilder. It's very useful. Link here:

http://www.albahari.com/nutshell/predicatebuilder.aspx

It's part of LinqKit:

http://www.albahari.com/nutshell/linqkit.aspx

and here's some info on how it's used:

How does PredicateBuilder work

It will basically let you do something like this:

var predicate = PredicateBuilder.True<Foo>();
            if (l1 != null)
                predicate = predicate.And(f => f.Lookup1.Name == l1);
            if (l2 != null)
                predicate = predicate.Or(f => f.Lookup2.Name == l2);

            return Foos.Where(predicate);

Note the above is from memory.. I have not tested this...so might have some typos...

Community
  • 1
  • 1
Matt
  • 6,787
  • 11
  • 65
  • 112
  • "I'm not 100% certain I know what you're asking for". So ask for clarification. Your answer is off the mark. – Gert Arnold May 07 '14 at 15:19
  • @GertArnold: Thanks for your comment, but the OP's words were "So I could compose queries in multiple steps" and then the final code sample seems to point to my conclusion being correct. Perhaps I am wrong though. TN, please feel free to clarify – Matt May 07 '14 at 15:22
  • As I see it the OP is looking for an automated way to shape a query into a form that produces better SQL, so that he can compose queries first and then reshape them. It's mainly about the reshaping. But ask if your not certain. – Gert Arnold May 07 '14 at 15:28
  • @GertArnold is right. I have a `IQueryable<>` that produces SQL which SQL Server cannot efficiently evaluate. So I am looking for a library which helps me to translate the `IQueryable<>'s` expression which produces better SQL. – TN. May 07 '14 at 17:14