Linq query has a bug? - c#

Just look at the linq query and the SQL profiler resulting query. Linq repeats the subquery which it shouldn't. Is this a bug or am I doing something wrong? By the way, I know how to write this linq to give me a satisfying result, but I want to know why is this one badly interpreted?
return (from k in ctx.UzajamnaKasa
join p in ctx.UzajamnaKasaPozajmice
on k.UzajamnaKasaId equals p.UzajamnaKasaId
where k.ClanId == clanId
select p.Iznos + p.Donos -
(from ot in ctx.UzajamnaKasaPozajmiceOtplate
where p.PozajmicaId == ot.PozajmicaId
group ot.Iznos by ot.PozajmicaId into g
select g.Sum()).FirstOrDefault()
).Sum();
select [GroupBy3].[A1] as [C1]
from
(
select sum([Project2].[A1]) as [A1]
from
(
select ([Project2].[Iznos] + [Project2].[Donos])
- (case
when ([Project2].[C1] is null) then
cast(0 as decimal(18))
else
(
select top (1)
[GroupBy2].[A1] as [C1]
from
(
select [Extent4].[PozajmicaId] as [K1]
, sum([Extent4].[Iznos]) as [A1]
from [dbo].[UzajamnaKasaPozajmiceOtplate] as [Extent4]
where [Project2].[PozajmicaId] = [Extent4].[PozajmicaId]
group by [Extent4].[PozajmicaId]
) as [GroupBy2]
)
end
) as [A1]
from
(
select [Extent2].[PozajmicaId] as [PozajmicaId]
, [Extent2].[Iznos] as [Iznos]
, [Extent2].[Donos] as [Donos]
, (
select top (1)
[GroupBy1].[A1] as [C1]
from
(
select [Extent3].[PozajmicaId] as [K1]
, sum([Extent3].[Iznos]) as [A1]
from [dbo].[UzajamnaKasaPozajmiceOtplate] as [Extent3]
where [Extent2].[PozajmicaId] = [Extent3].[PozajmicaId]
group by [Extent3].[PozajmicaId]
) as [GroupBy1]
) as [C1]
from [dbo].[UzajamnaKasa] as [Extent1]
inner join [dbo].[UzajamnaKasaPozajmice] as [Extent2]
on [Extent1].[UzajamnaKasaId] = [Extent2].[UzajamnaKasaId]
where [Extent1].[ClanId] = 1303
) as [Project2]
) as [Project2]
) as [GroupBy3];
Why is he duplicating this select? It's bad for performace.:
select top (1)
[GroupBy2].[A1] as [C1]
from
(
select [Extent4].[PozajmicaId] as [K1]
, sum([Extent4].[Iznos]) as [A1]
from [dbo].[UzajamnaKasaPozajmiceOtplate] as [Extent4]
where [Project2].[PozajmicaId] = [Extent4].[PozajmicaId]
group by [Extent4].[PozajmicaId]
) as [GroupBy2]

(from ot in ctx.UzajamnaKasaPozajmiceOtplate
where p.PozajmicaId == ot.PozajmicaId
group ot.Iznos by ot.PozajmicaId into g
select g.Sum()).FirstOrDefault()
Due to the FirstOrDefault(), this sub-query will be executed for every p.PozajmicaId founded.

Related

How to improve LINQ statement to use INNER JOIN in resulting SQL statement?

Assuming the following code that applies filtering logic to a passed on collection.
private IQueryable<Customer> ApplyCustomerFilter(CustomerFilter filter, IQueryable<Customer> customers)
{
...
if (filter.HasProductInBackOrder == true)
{
customers = customers.Where(c => c.Orders.Any(o => o.Products.Any(p => p.Status == ProductStatus.BackOrder)))
}
....
return customers;
}
Results in this SQL statement:
SELECT [Extent1].[CustomerId] AS [CustomerId],
[Extent1].[Status] AS [Status]
FROM [Customers] AS [Extent1]
WHERE
(
EXISTS
(
SELECT 1 AS [C1]
FROM
(
SELECT [Extent3].[OrderId] AS [OrderId]
FROM [Orders] AS [Extent3]
WHERE [Extent1].[CustomerId] = [Extent3].[CustomerId]
) AS [Project1]
WHERE EXISTS
(
SELECT 1 AS [C1]
FROM [Products] AS [Extent4]
WHERE ([Project1].[OrderId] = [Extent4].[OrderId])
AND ([Extent4].[Status] = #p__linq__6)
)
)
)
However, I would like to optimize this by forcing to use INNER JOINS so that the result will be similar to this:
SELECT [Extent1].[CustomerId] AS [CustomerId],
[Extent1].[Status] AS [Status]
FROM [Customers] AS [Extent1]
INNER JOIN [Orders] AS [Extent2] ON [Extent1].[CustomerId] = [Extent2].[CustomerId]
INNER JOIN [Products] AS [Extent3] ON [Extent2].[OrderId] = [Extent3].[OrderId]
WHERE [Extent3].[Status] = #p__linq__6
I've tried multiple approaches, but I was unable to accomplish the desired result. Any suggestions on how to force the correct joins and avoiding subselects?

LINQ to SQL LEFT JOIN, GROUP BY, COUNT, MAX and subquery

I have 3 tables: Users, Roles, Bids.
Two of them is created by ASP.NET Identity, Bids is my custom table (it is secondary to Users table)
I'm trying to get all users that aren't in specific role (all non admin users) and show number of bids (they can be null - I have left join), show highest bid per user and show if that bid is max.
SQL query was quire easy:
SELECT
U.Id
,U.UserName
,U.Email
,ISNULL(MAX(B.PriceInPLN), 0)
,COUNT(B.BidID)
,IIF(MAX(B.PriceInPLN)=(SELECT TOP 1 PriceInPLN FROM Bids B2 (NOLOCK) ORDER BY PriceInPLN DESC),1,0 ) AS Max
FROM
AspNetUsers U ( NOLOCK )
JOIN AspNetUserRoles UR ( NOLOCK ) ON U.Id = UR.UserId
LEFT JOIN Bids B ( NOLOCK ) ON B.ApplicationUserId = U.Id
WHERE
UR.RoleId != '9508f9d2-12fb-4175-89a7-3275cb7616ae'
GROUP BY
U.Id
,U.UserName
,U.Email
But I have trouble creating correct LINQ query. Here is what I have so far:
var users =(
from u in db.Users
where !u.Roles.Select(r => r.RoleId).Contains(adminRoleId)//everyone except admins
join b in db.Bids on u equals b.ApplicationUser into ub
from subset in ub.DefaultIfEmpty()//LEFT JOIN
group subset by new { u.Id, u.UserName, u.Email, u.EmailConfirmed, u.Online } into grouped
select new UserReturnModel
{
Id = grouped.Key.Id,
Name = grouped.Key.UserName,
Email = grouped.Key.Email,
EmailConfirmed = grouped.Key.EmailConfirmed,
Online = grouped.Key.Online,
BidsCount = grouped.Count(c => c.ApplicationUserId == grouped.Key.Id),
PriceInPLN = grouped.Max(c => c.PriceInPLN),
IsMax = (grouped.Max(c=>c.PriceInPLN) == db.Bids.Max(b=>b.PriceInPLN))
}).ToList();
I can't get Max column to work correctly - it always says true.
Here are column definitions to easily show what I want to get:
Id = user id,
Name = user name,
Email = user email,
BidsCount = number of bids created by that user,
PriceInPLN = max price for that user,
IsMax = is this user offer highest comparing to other offers, if there are no offers this should be false
I'm using that in ASP.NET, when debugging I've noticed that SQL query created by LINQ is large:
SELECT
1 AS [C1],
[Project6].[Id] AS [Id],
[Project6].[UserName] AS [UserName],
[Project6].[Email] AS [Email],
[Project6].[EmailConfirmed] AS [EmailConfirmed],
[Project6].[Online] AS [Online],
[Project6].[C4] AS [C2],
[Project6].[C1] AS [C3],
CASE WHEN (([Project6].[C2] = [GroupBy3].[A1]) OR (([Project6].[C2] IS NULL) AND ([GroupBy3].[A1] IS NULL))) THEN cast(1 as bit) WHEN ( NOT (([Project6].[C3] = [GroupBy4].[A1]) AND ((CASE WHEN ([Project6].[C3] IS NULL) THEN cast(1 as bit) ELSE cast(0 as bit) END) = (CASE WHEN ([GroupBy4].[A1] IS NULL) THEN cast(1 as bit) ELSE cast(0 as bit) END)))) THEN cast(0 as bit) END AS [C4]
FROM (SELECT
[Project3].[C1] AS [C1],
[Project3].[C2] AS [C2],
[Project3].[C3] AS [C3],
[Project3].[Id] AS [Id],
[Project3].[Online] AS [Online],
[Project3].[Email] AS [Email],
[Project3].[EmailConfirmed] AS [EmailConfirmed],
[Project3].[UserName] AS [UserName],
(SELECT
COUNT(1) AS [A1]
FROM ( SELECT
[Extent4].[Id] AS [Id],
[Extent4].[Online] AS [Online],
[Extent4].[Email] AS [Email],
[Extent4].[EmailConfirmed] AS [EmailConfirmed],
[Extent4].[UserName] AS [UserName],
[Extent5].[ApplicationUserId] AS [ApplicationUserId]
FROM [dbo].[AspNetUsers] AS [Extent4]
INNER JOIN [dbo].[Bids] AS [Extent5] ON [Extent5].[ApplicationUserId] = [Extent4].[Id]
WHERE ( NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[AspNetUserRoles] AS [Extent6]
WHERE ([Extent4].[Id] = [Extent6].[UserId]) AND ([Extent6].[RoleId] = #p__linq__0)
)) AND ([Project3].[Id] = [Extent4].[Id]) AND ([Project3].[UserName] = [Extent4].[UserName]) AND (([Project3].[Email] = [Extent4].[Email]) OR (([Project3].[Email] IS NULL) AND ([Extent4].[Email] IS NULL))) AND ([Project3].[EmailConfirmed] = [Extent4].[EmailConfirmed]) AND ([Project3].[Online] = [Extent4].[Online]) AND ([Extent5].[ApplicationUserId] = [Project3].[Id])
) AS [Project5]) AS [C4]
FROM ( SELECT
[GroupBy1].[A1] AS [C1],
[GroupBy1].[A2] AS [C2],
[GroupBy1].[A3] AS [C3],
[GroupBy1].[K1] AS [Id],
[GroupBy1].[K2] AS [Online],
[GroupBy1].[K3] AS [Email],
[GroupBy1].[K4] AS [EmailConfirmed],
[GroupBy1].[K5] AS [UserName]
FROM ( SELECT
[Project2].[Id] AS [K1],
[Project2].[Online] AS [K2],
[Project2].[Email] AS [K3],
[Project2].[EmailConfirmed] AS [K4],
[Project2].[UserName] AS [K5],
MAX([Project2].[PriceInPLN]) AS [A1],
MAX([Project2].[PriceInPLN]) AS [A2],
MAX([Project2].[PriceInPLN]) AS [A3]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Online] AS [Online],
[Extent1].[Email] AS [Email],
[Extent1].[EmailConfirmed] AS [EmailConfirmed],
[Extent1].[UserName] AS [UserName],
[Extent2].[PriceInPLN] AS [PriceInPLN],
[Extent2].[ApplicationUserId] AS [ApplicationUserId]
FROM [dbo].[AspNetUsers] AS [Extent1]
LEFT OUTER JOIN [dbo].[Bids] AS [Extent2] ON [Extent1].[Id] = [Extent2].[ApplicationUserId]
WHERE NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[AspNetUserRoles] AS [Extent3]
WHERE ([Extent1].[Id] = [Extent3].[UserId]) AND ([Extent3].[RoleId] = #p__linq__0)
)
) AS [Project2]
GROUP BY [Project2].[Id], [Project2].[Online], [Project2].[Email], [Project2].[EmailConfirmed], [Project2].[UserName]
) AS [GroupBy1]
) AS [Project3] ) AS [Project6]
CROSS JOIN (SELECT
MAX([Extent7].[PriceInPLN]) AS [A1]
FROM [dbo].[Bids] AS [Extent7] ) AS [GroupBy3]
CROSS JOIN (SELECT
MAX([Extent8].[PriceInPLN]) AS [A1]
FROM [dbo].[Bids] AS [Extent8] ) AS [GroupBy4]
Can this be simplified?
Here is model of my my database generated by Entity Framework Power Tools:
I'm not sure why you modified your LINQ query so much from the original SQL query, but translating the SQL query closer to literally using the rules from my SQL to LINQ Recipe I get
var MaxPriceInPLN = db.Bids.Max(b => b.PriceInPLN);
var ans = from U in db.Users
where !U.Roles.Any(r => r.RoleId == adminRoleId)
join b in db.Bids on U.Id equals b.ApplicationUserId into bj
from b in bj.DefaultIfEmpty()
group new { U, b } by new { U.Id, U.UserName, U.Email } into Ubg
let maxBidPriceInPLN = Ubg.Max(Ub => Ub.b.PriceInPLN)
select new {
Ubg.Key.Id,
Ubg.Key.UserName,
Ubg.Key.Email,
PriceInPLN = maxBidPriceInPLN ?? 0,
BidsCount = Ubg.Count(Ub => Ub.b != null),
IsMax = maxBidPriceInPLN == MaxPriceInPLN
};
You can simplify the LINQ query by using the EF navigation properties to hide the join from your query:
var MaxPriceInPLN = db.Bids.Max(b => b.PriceInPLN);
var ans = from U in db.Users
where !U.Roles.Any(r => r.RoleId == adminRoleId)
let maxBidPriceInPLN = U.Bids.Max(b => b.PriceInPLN)
select new {
U.Id,
U.UserName,
U.Email,
PriceInPLN = maxBidPriceInPLN ?? 0,
BidsCount = U.Bids.Count(),
IsMax = maxBidPriceInPLN == MaxPriceInPLN
};

How to group by int null values in IQueryable LINQ

I have a list of StudentGrades which contains TermNumber, I want to group them by TermNumber. However, when I look at the results, the ones with null TermNumbers are not returned/grouped.
IQueryable<StudentGradeDm> query = GetListQuery().Where(m => m.StudentId == studentId);
IQueryable<StudentGradeDto> groupedQuery = query.GroupBy(m => m.TermNumber)
.Select(m => new StudentGradeDto
{
TermNumber = m.Key,
StudentGrades = m.ToList()
});
return groupedQuery;
As you can see from the lovely screenshot i've taken here .. there are 3 groups, however, the first group is null because their TermNumber is null. But theoretically, who cares if its null? The StudentGrades with null TermNumber should still be a group.
I understand that one fix to this would be to call
query.ToList().GroupBy ......
But this is not an option for me, as the streamlined application will take a query such as the one above, and feed it into a generic pagination and sort function, in which only a subset of records will be fetched from the database to improve performance.
Any expert inputs would be greatly appreciated!
Update: Here is the generated SQL
{SELECT
[Project2].[C2] AS [C1],
[Project2].[C1] AS [C2],
[Project2].[C3] AS [C3],
[Project2].[Id] AS [Id],
[Project2].[StudentId] AS [StudentId],
[Project2].[Year] AS [Year],
[Project2].[TermTypeId] AS [TermTypeId],
[Project2].[TermNumber] AS [TermNumber],
[Project2].[ClassId] AS [ClassId],
[Project2].[GradeId] AS [GradeId],
[Project2].[FileId] AS [FileId],
[Project2].[CreatedById] AS [CreatedById],
[Project2].[CreatedDate] AS [CreatedDate],
[Project2].[ModifiedById] AS [ModifiedById],
[Project2].[ModifiedDate] AS [ModifiedDate],
[Project2].[Deleted] AS [Deleted]
FROM ( SELECT
[Distinct1].[C1] AS [C1],
1 AS [C2],
[Extent2].[Id] AS [Id],
[Extent2].[StudentId] AS [StudentId],
[Extent2].[Year] AS [Year],
[Extent2].[TermTypeId] AS [TermTypeId],
[Extent2].[TermNumber] AS [TermNumber],
[Extent2].[ClassId] AS [ClassId],
[Extent2].[GradeId] AS [GradeId],
[Extent2].[FileId] AS [FileId],
[Extent2].[CreatedById] AS [CreatedById],
[Extent2].[CreatedDate] AS [CreatedDate],
[Extent2].[ModifiedById] AS [ModifiedById],
[Extent2].[ModifiedDate] AS [ModifiedDate],
[Extent2].[Deleted] AS [Deleted],
CASE WHEN ([Extent2].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C3]
FROM (SELECT DISTINCT
[Extent1].[TermNumber] AS [C1]
FROM [dbo].[StudentGrade] AS [Extent1]
WHERE ([Extent1].[Deleted] <> 1) AND ([Extent1].[StudentId] = #p__linq__0) ) AS [Distinct1]
LEFT OUTER JOIN [dbo].[StudentGrade] AS [Extent2] ON ([Extent2].[Deleted] <> 1) AND ([Extent2].[StudentId] = #p__linq__0) AND ([Distinct1].[C1] = [Extent2].[TermNumber])
) AS [Project2]
ORDER BY [Project2].[C1] ASC, [Project2].[C3] ASC}

Limit results from multiple individual tables in a single LINQ-to-Entities query. Resultant T-SQL is wrong

I need to query multiple tables with one query, and I need to limit the results from each table individually.
An example ...
I have a ContentItem, Retailer, and Product table.
ContentItem has a Type (int) field that corresponds to an enum of content types like "Retailer" and "Product." I am filtering ContentItem using this field for each sub-subquery.
ContentItem has an Id (pkey) field.
Retailer and Product have an Id (pkey) field. Id is also an FK to ContentItem.Id.
I can select from all three tables with a LEFT JOIN query. From there, I can then limit the total number of rows returned, let's say 6 rows total.
What I want to do is limit the number of rows returned from Retailer and Product individually. This way, I will have 12 rows (max) total: 6 from Retailer, and 6 from Product.
I can already accomplish this with SQL, but I am having a difficult time getting LINQ-to-Entities to "do the right thing."
Here's my SQL
SELECT * From
(
(SELECT * FROM (SELECT * FROM [dbo].[ContentItem] WHERE Type = 0 ORDER BY ContentItem.mtime OFFSET 0 ROWS FETCH NEXT 6 ROWS ONLY) Retailers)
UNION ALL
(SELECT * FROM (SELECT * FROM [dbo].[ContentItem] WHERE Type = 1 ORDER BY ContentItem.mtime OFFSET 0 ROWS FETCH NEXT 6 ROWS ONLY) Brands)
UNION ALL
(SELECT * FROM (SELECT * FROM [dbo].[ContentItem] WHERE Type = 2 ORDER BY ContentItem.mtime OFFSET 0 ROWS FETCH NEXT 6 ROWS ONLY) Products)
UNION ALL
(SELECT * FROM (SELECT * FROM [dbo].[ContentItem] WHERE Type = 3 ORDER BY ContentItem.mtime OFFSET 0 ROWS FETCH NEXT 6 ROWS ONLY) Certifications)
UNION ALL
(SELECT * FROM (SELECT * FROM [dbo].[ContentItem] WHERE Type = 4 ORDER BY ContentItem.mtime OFFSET 0 ROWS FETCH NEXT 6 ROWS ONLY) Claims)
) as ContentItem
LEFT JOIN [dbo].[Retailer] ON (Retailer.Id = ContentItem.Id)
LEFT JOIN [dbo].[Brand] ON (Brand.Id = ContentItem.Id)
LEFT JOIN [dbo].[Product] ON (Product.Id = ContentItem.Id)
LEFT JOIN [dbo].[Certification] ON (Certification.Id = ContentItem.Id)
LEFT JOIN [dbo].[Claim] ON (Claim.Id = ContentItem.Id);
Here's one of my many iterations of LINQ queries (which is not returning the desired result).
var queryRetailers = contentItemModel
.Where(contentItem => contentItem.Type == ContentTypeEnum.Retailer)
.OrderByDescending(o => o.mtime).Skip(skip).Take(take).Select(o => new { Id = o.Id });
var queryBrands = contentItemModel
.Where(contentItem => contentItem.Type == ContentTypeEnum.Brand)
.OrderByDescending(o => o.mtime).Skip(skip).Take(take).Select(o => new { Id = o.Id });
var queryProducts = contentItemModel
.Where(contentItem => contentItem.Type == ContentTypeEnum.Product)
.OrderByDescending(o => o.mtime).Skip(skip).Take(take).Select(o => new { Id = o.Id });
var queryCertifications = contentItemModel
.Where(contentItem => contentItem.Type == ContentTypeEnum.Certification)
.OrderByDescending(o => o.mtime).Skip(skip).Take(take).Select(o => new { Id = o.Id });
var queryClaims = contentItemModel
.Where(contentItem => contentItem.Type == ContentTypeEnum.Claim)
.OrderByDescending(o => o.mtime).Skip(skip).Take(take).Select(o => new { Id = o.Id });
var query = from contentItem in
queryRetailers
.Concat(queryBrands)
.Concat(queryProducts)
.Concat(queryCertifications)
.Concat(queryClaims)
join item in context.Retailer on contentItem.Id equals item.Id into retailerGroup
from retailer in retailerGroup.DefaultIfEmpty(null)
join item in context.Brand on contentItem.Id equals item.Id into brandGroup
from brand in brandGroup.DefaultIfEmpty(null)
join item in context.Product on contentItem.Id equals item.Id into productGroup
from product in productGroup.DefaultIfEmpty(null)
join item in context.Certification on contentItem.Id equals item.Id into certificationGroup
from certification in certificationGroup.DefaultIfEmpty(null)
join item in context.Claim on contentItem.Id equals item.Id into claimGroup
from claim in claimGroup.DefaultIfEmpty(null)
select new
{
contentItem,
retailer,
brand,
product,
certification,
claim
};
var results = query.ToList();
This query returns SQL that essentially "nests" my UNION ALL statements, and the server returns all rows from the database.
SELECT
[Distinct4].[C1] AS [C1],
[Distinct4].[C2] AS [C2],
[Extent6].[Id] AS [Id],
[Extent6].[RowVersion] AS [RowVersion],
[Extent6].[ctime] AS [ctime],
[Extent6].[mtime] AS [mtime],
[Extent7].[Id] AS [Id1],
[Extent7].[Recommended] AS [Recommended],
[Extent7].[RowVersion] AS [RowVersion1],
[Extent7].[ctime] AS [ctime1],
[Extent7].[mtime] AS [mtime1],
[Extent8].[Id] AS [Id2],
[Extent8].[OverrideGrade] AS [OverrideGrade],
[Extent8].[PlantBased] AS [PlantBased],
[Extent8].[Recommended] AS [Recommended1],
[Extent8].[RowVersion] AS [RowVersion2],
[Extent8].[ctime] AS [ctime2],
[Extent8].[mtime] AS [mtime2],
[Extent8].[Brand_Id] AS [Brand_Id],
[Extent8].[Grade_Name] AS [Grade_Name],
[Extent8].[Grade_Value] AS [Grade_Value],
[Extent9].[Id] AS [Id3],
[Extent9].[RowVersion] AS [RowVersion3],
[Extent9].[ctime] AS [ctime3],
[Extent9].[mtime] AS [mtime3],
[Extent9].[Grade_Name] AS [Grade_Name1],
[Extent9].[Grade_Value] AS [Grade_Value1],
[Extent10].[Id] AS [Id4],
[Extent10].[RowVersion] AS [RowVersion4],
[Extent10].[ctime] AS [ctime4],
[Extent10].[mtime] AS [mtime4],
[Extent10].[Grade_Name] AS [Grade_Name2],
[Extent10].[Grade_Value] AS [Grade_Value2]
FROM (SELECT DISTINCT
[UnionAll4].[C1] AS [C1],
[UnionAll4].[C2] AS [C2]
FROM (SELECT
[Distinct3].[C1] AS [C1],
[Distinct3].[C2] AS [C2]
FROM ( SELECT DISTINCT
[UnionAll3].[C1] AS [C1],
[UnionAll3].[C2] AS [C2]
FROM (SELECT
[Distinct2].[C1] AS [C1],
[Distinct2].[C2] AS [C2]
FROM ( SELECT DISTINCT
[UnionAll2].[C1] AS [C1],
[UnionAll2].[C2] AS [C2]
FROM (SELECT
[Distinct1].[C1] AS [C1],
[Distinct1].[C2] AS [C2]
FROM ( SELECT DISTINCT
[UnionAll1].[C1] AS [C1],
[UnionAll1].[Id] AS [C2]
FROM (SELECT TOP (1000)
[Project1].[C1] AS [C1],
[Project1].[Id] AS [Id]
FROM ( SELECT [Project1].[Id] AS [Id], [Project1].[mtime] AS [mtime], [Project1].[C1] AS [C1], row_number() OVER (ORDER BY [Project1].[mtime] DESC) AS [row_number]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Extent1].[mtime] AS [mtime],
1 AS [C1]
FROM [dbo].[ContentItem] AS [Extent1]
WHERE 0 = CAST( [Extent1].[Type] AS int)
) AS [Project1]
) AS [Project1]
WHERE [Project1].[row_number] > 0
ORDER BY [Project1].[mtime] DESC
UNION ALL
SELECT TOP (1000)
[Project3].[C1] AS [C1],
[Project3].[Id] AS [Id]
FROM ( SELECT [Project3].[Id] AS [Id], [Project3].[mtime] AS [mtime], [Project3].[C1] AS [C1], row_number() OVER (ORDER BY [Project3].[mtime] DESC) AS [row_number]
FROM ( SELECT
[Extent2].[Id] AS [Id],
[Extent2].[mtime] AS [mtime],
1 AS [C1]
FROM [dbo].[ContentItem] AS [Extent2]
WHERE 1 = CAST( [Extent2].[Type] AS int)
) AS [Project3]
) AS [Project3]
WHERE [Project3].[row_number] > 0
ORDER BY [Project3].[mtime] DESC) AS [UnionAll1]
) AS [Distinct1]
UNION ALL
SELECT TOP (1000)
[Project7].[C1] AS [C1],
[Project7].[Id] AS [Id]
FROM ( SELECT [Project7].[Id] AS [Id], [Project7].[mtime] AS [mtime], [Project7].[C1] AS [C1], row_number() OVER (ORDER BY [Project7].[mtime] DESC) AS [row_number]
FROM ( SELECT
[Extent3].[Id] AS [Id],
[Extent3].[mtime] AS [mtime],
1 AS [C1]
FROM [dbo].[ContentItem] AS [Extent3]
WHERE 2 = CAST( [Extent3].[Type] AS int)
) AS [Project7]
) AS [Project7]
WHERE [Project7].[row_number] > 0
ORDER BY [Project7].[mtime] DESC) AS [UnionAll2]
) AS [Distinct2]
UNION ALL
SELECT TOP (1000)
[Project11].[C1] AS [C1],
[Project11].[Id] AS [Id]
FROM ( SELECT [Project11].[Id] AS [Id], [Project11].[mtime] AS [mtime], [Project11].[C1] AS [C1], row_number() OVER (ORDER BY [Project11].[mtime] DESC) AS [row_number]
FROM ( SELECT
[Extent4].[Id] AS [Id],
[Extent4].[mtime] AS [mtime],
1 AS [C1]
FROM [dbo].[ContentItem] AS [Extent4]
WHERE 3 = CAST( [Extent4].[Type] AS int)
) AS [Project11]
) AS [Project11]
WHERE [Project11].[row_number] > 0
ORDER BY [Project11].[mtime] DESC) AS [UnionAll3]
) AS [Distinct3]
UNION ALL
SELECT TOP (1000)
[Project15].[C1] AS [C1],
[Project15].[Id] AS [Id]
FROM ( SELECT [Project15].[Id] AS [Id], [Project15].[mtime] AS [mtime], [Project15].[C1] AS [C1], row_number() OVER (ORDER BY [Project15].[mtime] DESC) AS [row_number]
FROM ( SELECT
[Extent5].[Id] AS [Id],
[Extent5].[mtime] AS [mtime],
1 AS [C1]
FROM [dbo].[ContentItem] AS [Extent5]
WHERE 4 = CAST( [Extent5].[Type] AS int)
) AS [Project15]
) AS [Project15]
WHERE [Project15].[row_number] > 0
ORDER BY [Project15].[mtime] DESC) AS [UnionAll4] ) AS [Distinct4]
LEFT OUTER JOIN [dbo].[Retailer] AS [Extent6] ON [Distinct4].[C2] = [Extent6].[Id]
LEFT OUTER JOIN [dbo].[Brand] AS [Extent7] ON [Distinct4].[C2] = [Extent7].[Id]
LEFT OUTER JOIN [dbo].[Product] AS [Extent8] ON [Distinct4].[C2] = [Extent8].[Id]
LEFT OUTER JOIN [dbo].[Certification] AS [Extent9] ON [Distinct4].[C2] = [Extent9].[Id]
LEFT OUTER JOIN [dbo].[Claim] AS [Extent10] ON [Distinct4].[C2] = [Extent10].[Id]
So my overall questions are:
1) Is there a simpler SQL query I can execute to get the same results? I know that T-SQL doesn't support offsets per table in a subquery, hence the subquery wrapping.
2) If there isn't, what am I doing wrong in my LINQ query? Is this even possible with LINQ?
I wanted to add the SQL from #radar here all nice and formatted. It at least appears to be an elegant solution to avoid the sub-subqueries, and still accomplishes the offset/fetch.
SELECT *
FROM (SELECT
[ContentItem].*,
row_number() OVER ( PARTITION BY Type ORDER BY ContentItem.mtime ) as rn
FROM [dbo].[ContentItem]
LEFT JOIN [dbo].[Retailer] ON (Retailer.Id = ContentItem.Id)
LEFT JOIN [dbo].[Brand] ON (Brand.Id = ContentItem.Id)
LEFT JOIN [dbo].[Product] ON (Product.Id = ContentItem.Id)
LEFT JOIN [dbo].[Certification] ON (Certification.Id = ContentItem.Id)
LEFT JOIN [dbo].[Claim] ON (Claim.Id = ContentItem.Id)
) as x
WHERE x.rn >= a AND x.rn <= b;
a is the lower threshold (offset) and b is the upper threshold (fetch-ish). The only catch is that b now equals fetch + a instead of just fetch. The first set of results would be WHERE x.rn >= 0 AND x.rn <= 6, the second set WHERE x.rn >= 6 AND x.rn <= 12, third WHERE x.rn >= 12 AND x.rn <= 18, and so on.
As you are looking simpler SQL, you can use row_number analytic function, which would be faster
You need to try and see as there are many left joins and also proper index need to exists in these tables.
select *
from (
select *, row_number() over ( partition by Type order by ContentItem.mtime ) as rn
from [dbo].[ContentItem]
LEFT JOIN [dbo].[Retailer] ON (Retailer.Id = ContentItem.Id)
LEFT JOIN [dbo].[Brand] ON (Brand.Id = ContentItem.Id)
LEFT JOIN [dbo].[Product] ON (Product.Id = ContentItem.Id)
LEFT JOIN [dbo].[Certification] ON (Certification.Id = ContentItem.Id)
LEFT JOIN [dbo].[Claim] ON (Claim.Id = ContentItem.Id);
)
where rn <= 6
Well, it appears that I'm an idiot. That TOP(1000) call should have tipped me off. I assumed that my take variable was set to 6 but it was, in fact, set to 1000. Turns out my giant LINQ query works as expected, but the nested UNION ALL statements threw me off.
Still, I'm going to investigate #radar's answer further. It's hard to argue with better performance.

How can paging a query be *slower*?

I'm timing the execution time of both a query, and the same query, paged.
foreach (var x in productSource.OrderBy(p => p.AdminDisplayName)
.Where(p => allIds.Any(val => val == p.SiteProductId))) ;
foreach (var x in productSource.OrderBy(p => p.AdminDisplayName)
.Where(p => allIds.Any(val => val == p.SiteProductId)).Skip(20).Take(20)) ;
Somehow, the first query is taking 0.5 seconds, and the second is taking three times that long. How is that possible? Unfortunately allIds is fairly complex, so the SQL generated is quite long. I'm using Linq-to-SQL, which is why I used Any instead of Contains, since the latter causes an error for complex queries like this.
EDIT
It looks like the paged query runs faster (in absolute times) when the returned result set is larger. When the base query returns 6,000 rows (before paging) the paged version runs at 1.7 seconds. When the base query returns 200 rows (before paging) the paged version runs at 1.7 seconds. This seems crazy to me.
EDIT 2
I was asked to supply query execution plans. I've looked through both of them, and they appear to be identical, except for the very beginning. Here are the parts that actually differ.
NOT PAGED
PAGED
END EDIT
SELECT [t0].[SiteProductId], [t0].[SiteId], [t0].[SiteDivisionId], [t0].[ProductDisplayId], [t0].[ItemId], [t0].[SiteProductTypeId], [t0].[PrimaryParentSiteCategoryId], [t0].[PrimaryParentSiteProductId], [t0].[PrimaryChildSiteProductId], [t0].[UsesMasterPrice], [t0].[ListPrice], [t0].[SalePrice], [t0].[ShowWasIsPricing], [t0].[ArrivalDate], [t0].[SiteUrlKey], [t0].[IsDisplayedOnIndexPages], [t0].[HasDetailPage], [t0].[IsPersonalizable], [t0].[RequiresPersonalization], [t0].[ShowPersonalizationInline], [t0].[PzTemplateId], [t0].[AdminDisplayName], [t0].[DetailPageHeading], [t0].[SiteLabelForIndex], [t0].[SiteLabelForDetail], [t0].[UsesVariantAttributes], [t0].[VariantSelectionPrompt], [t0].[VariantSelectionOptionLabel], [t0].[VariantSortOrder], [t0].[VariantSelectionImageAssignmentId], [t0].[IndexImageAssignmentId], [t0].[DetailImageAssignmentId], [t0].[SiteProductDescription], [t0].[SiteTargetSearchTerms], [t0].[SiteWebPageTitle], [t0].[SiteWebPageKeywords], [t0].[SiteWebPageDescription], [t0].[ItemStatusId], [t0].[UsesMasterInventory], [t0].[CurrentInventory], [t0].[RestockDate], [t0].[IsBackorderable], [t0].[IsPreorderable], [t0].[OutOfStockLevel], [t0].[CreatedBy], [t0].[CreatedDT], [t0].[ModifiedBy], [t0].[ModifiedDT], [t0].[UsesPixamiPreview], [t0].[ShowsDynamicPreview], [t0].[IsNewProduct], [t0].[IsExclusiveProduct], [t0].[IsInternetOnlyProduct], [t0].[IsCustomerFavorite], [t0].[StartDate], [t0].[EndDate], [t0].[InternalKeywords], [t0].[ProductAlert], [t0].[AdditionalProductInfo], [t0].[UsesPixamiPz], [t0].[IsFreeGift], [t2].[test], [t2].[ItemId] AS [ItemId2], [t2].[ItemSku], [t2].[ErpItemId], [t2].[SupplierSku], [t2].[VendorSku], [t2].[UPC], [t2].[SerialNumber], [t2].[DisplayName], [t2].[IsPersonalizable] AS [IsPersonalizable2], [t2].[RequiresPersonalization] AS [RequiresPersonalization2], [t2].[ListPrice] AS [ListPrice2], [t2].[ItemTypeId], [t2].[ItemTypeCode], [t2].[DisplayIndividuallyOnSite], [t2].[ItemStatusId] AS [ItemStatusId2], [t2].[ItemStatusCode], [t2].[ParentItemId], [t2].[VariantTemplateCode], [t2].[PzFormatCode], [t2].[OmsPzTemplateId], [t2].[Height], [t2].[Width], [t2].[Depth], [t2].[Weight], [t2].[CurrentInventory] AS [CurrentInventory2], [t2].[RestockDate] AS [RestockDate2], [t2].[IsTaxable], [t2].[PostHand], [t2].[LastSyncDate], [t2].[CreatedBy] AS [CreatedBy2], [t2].[CreatedDT] AS [CreatedDT2], [t2].[ModifiedBy] AS [ModifiedBy2], [t2].[ModifiedDT] AS [ModifiedDT2]
FROM [dbo].[SiteProduct] AS [t0]
LEFT OUTER JOIN (
SELECT 1 AS [test], [t1].[ItemId], [t1].[ItemSku], [t1].[ErpItemId], [t1].[SupplierSku], [t1].[VendorSku], [t1].[UPC], [t1].[SerialNumber], [t1].[DisplayName], [t1].[IsPersonalizable], [t1].[RequiresPersonalization], [t1].[ListPrice], [t1].[ItemTypeId], [t1].[ItemTypeCode], [t1].[DisplayIndividuallyOnSite], [t1].[ItemStatusId], [t1].[ItemStatusCode], [t1].[ParentItemId], [t1].[VariantTemplateCode], [t1].[PzFormatCode], [t1].[OmsPzTemplateId], [t1].[Height], [t1].[Width], [t1].[Depth], [t1].[Weight], [t1].[CurrentInventory], [t1].[RestockDate], [t1].[IsTaxable], [t1].[PostHand], [t1].[LastSyncDate], [t1].[CreatedBy], [t1].[CreatedDT], [t1].[ModifiedBy], [t1].[ModifiedDT]
FROM [dbo].[ItemMaster] AS [t1]
) AS [t2] ON [t2].[ItemId] = [t0].[ItemId]
WHERE EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT [t43].[SiteProductId]
FROM (
SELECT [t28].[SiteProductId]
FROM (
SELECT [t13].[SiteProductId]
FROM (
SELECT [t3].[SiteProductId]
FROM [dbo].[SiteProduct] AS [t3]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t4] ON [t4].[ItemId] = [t3].[ItemId]
WHERE ([t3].[SiteProductTypeId] <> #p0) AND (([t3].[AdminDisplayName] LIKE #p1) OR ([t4].[ItemSku] LIKE #p2)) AND ([t3].[SiteId] = #p3)
UNION
SELECT [t12].[SiteProductId]
FROM (
SELECT [t5].[SiteProductId]
FROM [dbo].[SiteProduct] AS [t5]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t6] ON [t6].[ItemId] = [t5].[ItemId]
WHERE ([t5].[PrimaryParentSiteProductId] IS NOT NULL) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT [t7].[PrimaryParentSiteProductId] AS [value], [t7].[PrimaryParentSiteProductId], [t7].[SiteProductTypeId], [t7].[AdminDisplayName], [t8].[ItemSku], [t7].[SiteId]
FROM [dbo].[SiteProduct] AS [t7]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t8] ON [t8].[ItemId] = [t7].[ItemId]
) AS [t9]
WHERE ([t9].[value] = ([t5].[PrimaryParentSiteProductId])) AND ([t9].[PrimaryParentSiteProductId] IS NOT NULL) AND ([t9].[SiteProductTypeId] <> #p4) AND (([t9].[AdminDisplayName] LIKE #p5) OR ([t9].[ItemSku] LIKE #p6)) AND ([t9].[SiteId] = #p7)
))
UNION
SELECT [t10].[PrimaryParentSiteProductId] AS [value]
FROM [dbo].[SiteProduct] AS [t10]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t11] ON [t11].[ItemId] = [t10].[ItemId]
WHERE ([t10].[PrimaryParentSiteProductId] IS NOT NULL) AND ([t10].[SiteProductTypeId] <> #p8) AND (([t10].[AdminDisplayName] LIKE #p9) OR ([t11].[ItemSku] LIKE #p10)) AND ([t10].[SiteId] = #p11)
) AS [t12]
) AS [t13]
UNION
SELECT [t14].[ParentSiteProductId]
FROM [dbo].[SiteProductAssociation] AS [t14]
INNER JOIN [dbo].[SiteProductAssociationType] AS [t15] ON [t15].[SiteProductAssociationTypeId] = [t14].[SiteProductAssociationTypeId]
WHERE (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT [t26].[SiteProductId]
FROM (
SELECT [t16].[SiteProductId]
FROM [dbo].[SiteProduct] AS [t16]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t17] ON [t17].[ItemId] = [t16].[ItemId]
WHERE ([t16].[SiteProductTypeId] <> #p12) AND (([t16].[AdminDisplayName] LIKE #p13) OR ([t17].[ItemSku] LIKE #p14)) AND ([t16].[SiteId] = #p15)
UNION
SELECT [t25].[SiteProductId]
FROM (
SELECT [t18].[SiteProductId]
FROM [dbo].[SiteProduct] AS [t18]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t19] ON [t19].[ItemId] = [t18].[ItemId]
WHERE ([t18].[PrimaryParentSiteProductId] IS NOT NULL) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT [t20].[PrimaryParentSiteProductId] AS [value], [t20].[PrimaryParentSiteProductId], [t20].[SiteProductTypeId], [t20].[AdminDisplayName], [t21].[ItemSku], [t20].[SiteId]
FROM [dbo].[SiteProduct] AS [t20]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t21] ON [t21].[ItemId] = [t20].[ItemId]
) AS [t22]
WHERE ([t22].[value] = ([t18].[PrimaryParentSiteProductId])) AND ([t22].[PrimaryParentSiteProductId] IS NOT NULL) AND ([t22].[SiteProductTypeId] <> #p16) AND (([t22].[AdminDisplayName] LIKE #p17) OR ([t22].[ItemSku] LIKE #p18)) AND ([t22].[SiteId] = #p19)
))
UNION
SELECT [t23].[PrimaryParentSiteProductId] AS [value]
FROM [dbo].[SiteProduct] AS [t23]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t24] ON [t24].[ItemId] = [t23].[ItemId]
WHERE ([t23].[PrimaryParentSiteProductId] IS NOT NULL) AND ([t23].[SiteProductTypeId] <> #p20) AND (([t23].[AdminDisplayName] LIKE #p21) OR ([t24].[ItemSku] LIKE #p22)) AND ([t23].[SiteId] = #p23)
) AS [t25]
) AS [t26]
) AS [t27]
WHERE [t27].[SiteProductId] = [t14].[ChildSiteProductId]
)) AND ([t14].[SiteProductAssociationTypeId] = #p24)
) AS [t28]
UNION
SELECT [t29].[ChildSiteProductId]
FROM [dbo].[SiteProductAssociation] AS [t29]
INNER JOIN [dbo].[SiteProductAssociationType] AS [t30] ON [t30].[SiteProductAssociationTypeId] = [t29].[SiteProductAssociationTypeId]
WHERE (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT [t41].[SiteProductId]
FROM (
SELECT [t31].[SiteProductId]
FROM [dbo].[SiteProduct] AS [t31]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t32] ON [t32].[ItemId] = [t31].[ItemId]
WHERE ([t31].[SiteProductTypeId] <> #p25) AND (([t31].[AdminDisplayName] LIKE #p26) OR ([t32].[ItemSku] LIKE #p27)) AND ([t31].[SiteId] = #p28)
UNION
SELECT [t40].[SiteProductId]
FROM (
SELECT [t33].[SiteProductId]
FROM [dbo].[SiteProduct] AS [t33]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t34] ON [t34].[ItemId] = [t33].[ItemId]
WHERE ([t33].[PrimaryParentSiteProductId] IS NOT NULL) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT [t35].[PrimaryParentSiteProductId] AS [value], [t35].[PrimaryParentSiteProductId], [t35].[SiteProductTypeId], [t35].[AdminDisplayName], [t36].[ItemSku], [t35].[SiteId]
FROM [dbo].[SiteProduct] AS [t35]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t36] ON [t36].[ItemId] = [t35].[ItemId]
) AS [t37]
WHERE ([t37].[value] = ([t33].[PrimaryParentSiteProductId])) AND ([t37].[PrimaryParentSiteProductId] IS NOT NULL) AND ([t37].[SiteProductTypeId] <> #p29) AND (([t37].[AdminDisplayName] LIKE #p30) OR ([t37].[ItemSku] LIKE #p31)) AND ([t37].[SiteId] = #p32)
))
UNION
SELECT [t38].[PrimaryParentSiteProductId] AS [value]
FROM [dbo].[SiteProduct] AS [t38]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t39] ON [t39].[ItemId] = [t38].[ItemId]
WHERE ([t38].[PrimaryParentSiteProductId] IS NOT NULL) AND ([t38].[SiteProductTypeId] <> #p33) AND (([t38].[AdminDisplayName] LIKE #p34) OR ([t39].[ItemSku] LIKE #p35)) AND ([t38].[SiteId] = #p36)
) AS [t40]
) AS [t41]
) AS [t42]
WHERE [t42].[SiteProductId] = [t29].[ParentSiteProductId]
)) AND ([t29].[SiteProductAssociationTypeId] = #p37)
) AS [t43]
) AS [t44]
WHERE [t44].[SiteProductId] = [t0].[SiteProductId]
)
ORDER BY [t0].[AdminDisplayName]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1
SELECT [t45].[SiteProductId], [t45].[SiteId], [t45].[SiteDivisionId], [t45].[ProductDisplayId], [t45].[ItemId], [t45].[SiteProductTypeId], [t45].[PrimaryParentSiteCategoryId], [t45].[PrimaryParentSiteProductId], [t45].[PrimaryChildSiteProductId], [t45].[UsesMasterPrice], [t45].[ListPrice], [t45].[SalePrice], [t45].[ShowWasIsPricing], [t45].[ArrivalDate], [t45].[SiteUrlKey], [t45].[IsDisplayedOnIndexPages], [t45].[HasDetailPage], [t45].[IsPersonalizable], [t45].[RequiresPersonalization], [t45].[ShowPersonalizationInline], [t45].[PzTemplateId], [t45].[AdminDisplayName], [t45].[DetailPageHeading], [t45].[SiteLabelForIndex], [t45].[SiteLabelForDetail], [t45].[UsesVariantAttributes], [t45].[VariantSelectionPrompt], [t45].[VariantSelectionOptionLabel], [t45].[VariantSortOrder], [t45].[VariantSelectionImageAssignmentId], [t45].[IndexImageAssignmentId], [t45].[DetailImageAssignmentId], [t45].[SiteProductDescription], [t45].[SiteTargetSearchTerms], [t45].[SiteWebPageTitle], [t45].[SiteWebPageKeywords], [t45].[SiteWebPageDescription], [t45].[ItemStatusId], [t45].[UsesMasterInventory], [t45].[CurrentInventory], [t45].[RestockDate], [t45].[IsBackorderable], [t45].[IsPreorderable], [t45].[OutOfStockLevel], [t45].[CreatedBy], [t45].[CreatedDT], [t45].[ModifiedBy], [t45].[ModifiedDT], [t45].[UsesPixamiPreview], [t45].[ShowsDynamicPreview], [t45].[IsNewProduct], [t45].[IsExclusiveProduct], [t45].[IsInternetOnlyProduct], [t45].[IsCustomerFavorite], [t45].[StartDate], [t45].[EndDate], [t45].[InternalKeywords], [t45].[ProductAlert], [t45].[AdditionalProductInfo], [t45].[UsesPixamiPz], [t45].[IsFreeGift], [t45].[test], [t45].[ItemId2], [t45].[ItemSku], [t45].[ErpItemId], [t45].[SupplierSku], [t45].[VendorSku], [t45].[UPC], [t45].[SerialNumber], [t45].[DisplayName], [t45].[IsPersonalizable2], [t45].[RequiresPersonalization2], [t45].[ListPrice2], [t45].[ItemTypeId], [t45].[ItemTypeCode], [t45].[DisplayIndividuallyOnSite], [t45].[ItemStatusId2], [t45].[ItemStatusCode], [t45].[ParentItemId], [t45].[VariantTemplateCode], [t45].[PzFormatCode], [t45].[OmsPzTemplateId], [t45].[Height], [t45].[Width], [t45].[Depth], [t45].[Weight], [t45].[CurrentInventory2], [t45].[RestockDate2], [t45].[IsTaxable], [t45].[PostHand], [t45].[LastSyncDate], [t45].[CreatedBy2], [t45].[CreatedDT2], [t45].[ModifiedBy2], [t45].[ModifiedDT2]
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [t0].[AdminDisplayName]) AS [ROW_NUMBER], [t0].[SiteProductId], [t0].[SiteId], [t0].[SiteDivisionId], [t0].[ProductDisplayId], [t0].[ItemId], [t0].[SiteProductTypeId], [t0].[PrimaryParentSiteCategoryId], [t0].[PrimaryParentSiteProductId], [t0].[PrimaryChildSiteProductId], [t0].[UsesMasterPrice], [t0].[ListPrice], [t0].[SalePrice], [t0].[ShowWasIsPricing], [t0].[ArrivalDate], [t0].[SiteUrlKey], [t0].[IsDisplayedOnIndexPages], [t0].[HasDetailPage], [t0].[IsPersonalizable], [t0].[RequiresPersonalization], [t0].[ShowPersonalizationInline], [t0].[PzTemplateId], [t0].[AdminDisplayName], [t0].[DetailPageHeading], [t0].[SiteLabelForIndex], [t0].[SiteLabelForDetail], [t0].[UsesVariantAttributes], [t0].[VariantSelectionPrompt], [t0].[VariantSelectionOptionLabel], [t0].[VariantSortOrder], [t0].[VariantSelectionImageAssignmentId], [t0].[IndexImageAssignmentId], [t0].[DetailImageAssignmentId], [t0].[SiteProductDescription], [t0].[SiteTargetSearchTerms], [t0].[SiteWebPageTitle], [t0].[SiteWebPageKeywords], [t0].[SiteWebPageDescription], [t0].[ItemStatusId], [t0].[UsesMasterInventory], [t0].[CurrentInventory], [t0].[RestockDate], [t0].[IsBackorderable], [t0].[IsPreorderable], [t0].[OutOfStockLevel], [t0].[CreatedBy], [t0].[CreatedDT], [t0].[ModifiedBy], [t0].[ModifiedDT], [t0].[UsesPixamiPreview], [t0].[ShowsDynamicPreview], [t0].[IsNewProduct], [t0].[IsExclusiveProduct], [t0].[IsInternetOnlyProduct], [t0].[IsCustomerFavorite], [t0].[StartDate], [t0].[EndDate], [t0].[InternalKeywords], [t0].[ProductAlert], [t0].[AdditionalProductInfo], [t0].[UsesPixamiPz], [t0].[IsFreeGift], [t2].[test], [t2].[ItemId] AS [ItemId2], [t2].[ItemSku], [t2].[ErpItemId], [t2].[SupplierSku], [t2].[VendorSku], [t2].[UPC], [t2].[SerialNumber], [t2].[DisplayName], [t2].[IsPersonalizable] AS [IsPersonalizable2], [t2].[RequiresPersonalization] AS [RequiresPersonalization2], [t2].[ListPrice] AS [ListPrice2], [t2].[ItemTypeId], [t2].[ItemTypeCode], [t2].[DisplayIndividuallyOnSite], [t2].[ItemStatusId] AS [ItemStatusId2], [t2].[ItemStatusCode], [t2].[ParentItemId], [t2].[VariantTemplateCode], [t2].[PzFormatCode], [t2].[OmsPzTemplateId], [t2].[Height], [t2].[Width], [t2].[Depth], [t2].[Weight], [t2].[CurrentInventory] AS [CurrentInventory2], [t2].[RestockDate] AS [RestockDate2], [t2].[IsTaxable], [t2].[PostHand], [t2].[LastSyncDate], [t2].[CreatedBy] AS [CreatedBy2], [t2].[CreatedDT] AS [CreatedDT2], [t2].[ModifiedBy] AS [ModifiedBy2], [t2].[ModifiedDT] AS [ModifiedDT2]
FROM [dbo].[SiteProduct] AS [t0]
LEFT OUTER JOIN (
SELECT 1 AS [test], [t1].[ItemId], [t1].[ItemSku], [t1].[ErpItemId], [t1].[SupplierSku], [t1].[VendorSku], [t1].[UPC], [t1].[SerialNumber], [t1].[DisplayName], [t1].[IsPersonalizable], [t1].[RequiresPersonalization], [t1].[ListPrice], [t1].[ItemTypeId], [t1].[ItemTypeCode], [t1].[DisplayIndividuallyOnSite], [t1].[ItemStatusId], [t1].[ItemStatusCode], [t1].[ParentItemId], [t1].[VariantTemplateCode], [t1].[PzFormatCode], [t1].[OmsPzTemplateId], [t1].[Height], [t1].[Width], [t1].[Depth], [t1].[Weight], [t1].[CurrentInventory], [t1].[RestockDate], [t1].[IsTaxable], [t1].[PostHand], [t1].[LastSyncDate], [t1].[CreatedBy], [t1].[CreatedDT], [t1].[ModifiedBy], [t1].[ModifiedDT]
FROM [dbo].[ItemMaster] AS [t1]
) AS [t2] ON [t2].[ItemId] = [t0].[ItemId]
WHERE EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT [t43].[SiteProductId]
FROM (
SELECT [t28].[SiteProductId]
FROM (
SELECT [t13].[SiteProductId]
FROM (
SELECT [t3].[SiteProductId]
FROM [dbo].[SiteProduct] AS [t3]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t4] ON [t4].[ItemId] = [t3].[ItemId]
WHERE ([t3].[SiteProductTypeId] <> #p0) AND (([t3].[AdminDisplayName] LIKE #p1) OR ([t4].[ItemSku] LIKE #p2)) AND ([t3].[SiteId] = #p3)
UNION
SELECT [t12].[SiteProductId]
FROM (
SELECT [t5].[SiteProductId]
FROM [dbo].[SiteProduct] AS [t5]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t6] ON [t6].[ItemId] = [t5].[ItemId]
WHERE ([t5].[PrimaryParentSiteProductId] IS NOT NULL) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT [t7].[PrimaryParentSiteProductId] AS [value], [t7].[PrimaryParentSiteProductId], [t7].[SiteProductTypeId], [t7].[AdminDisplayName], [t8].[ItemSku], [t7].[SiteId]
FROM [dbo].[SiteProduct] AS [t7]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t8] ON [t8].[ItemId] = [t7].[ItemId]
) AS [t9]
WHERE ([t9].[value] = ([t5].[PrimaryParentSiteProductId])) AND ([t9].[PrimaryParentSiteProductId] IS NOT NULL) AND ([t9].[SiteProductTypeId] <> #p4) AND (([t9].[AdminDisplayName] LIKE #p5) OR ([t9].[ItemSku] LIKE #p6)) AND ([t9].[SiteId] = #p7)
))
UNION
SELECT [t10].[PrimaryParentSiteProductId] AS [value]
FROM [dbo].[SiteProduct] AS [t10]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t11] ON [t11].[ItemId] = [t10].[ItemId]
WHERE ([t10].[PrimaryParentSiteProductId] IS NOT NULL) AND ([t10].[SiteProductTypeId] <> #p8) AND (([t10].[AdminDisplayName] LIKE #p9) OR ([t11].[ItemSku] LIKE #p10)) AND ([t10].[SiteId] = #p11)
) AS [t12]
) AS [t13]
UNION
SELECT [t14].[ParentSiteProductId]
FROM [dbo].[SiteProductAssociation] AS [t14]
INNER JOIN [dbo].[SiteProductAssociationType] AS [t15] ON [t15].[SiteProductAssociationTypeId] = [t14].[SiteProductAssociationTypeId]
WHERE (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT [t26].[SiteProductId]
FROM (
SELECT [t16].[SiteProductId]
FROM [dbo].[SiteProduct] AS [t16]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t17] ON [t17].[ItemId] = [t16].[ItemId]
WHERE ([t16].[SiteProductTypeId] <> #p12) AND (([t16].[AdminDisplayName] LIKE #p13) OR ([t17].[ItemSku] LIKE #p14)) AND ([t16].[SiteId] = #p15)
UNION
SELECT [t25].[SiteProductId]
FROM (
SELECT [t18].[SiteProductId]
FROM [dbo].[SiteProduct] AS [t18]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t19] ON [t19].[ItemId] = [t18].[ItemId]
WHERE ([t18].[PrimaryParentSiteProductId] IS NOT NULL) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT [t20].[PrimaryParentSiteProductId] AS [value], [t20].[PrimaryParentSiteProductId], [t20].[SiteProductTypeId], [t20].[AdminDisplayName], [t21].[ItemSku], [t20].[SiteId]
FROM [dbo].[SiteProduct] AS [t20]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t21] ON [t21].[ItemId] = [t20].[ItemId]
) AS [t22]
WHERE ([t22].[value] = ([t18].[PrimaryParentSiteProductId])) AND ([t22].[PrimaryParentSiteProductId] IS NOT NULL) AND ([t22].[SiteProductTypeId] <> #p16) AND (([t22].[AdminDisplayName] LIKE #p17) OR ([t22].[ItemSku] LIKE #p18)) AND ([t22].[SiteId] = #p19)
))
UNION
SELECT [t23].[PrimaryParentSiteProductId] AS [value]
FROM [dbo].[SiteProduct] AS [t23]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t24] ON [t24].[ItemId] = [t23].[ItemId]
WHERE ([t23].[PrimaryParentSiteProductId] IS NOT NULL) AND ([t23].[SiteProductTypeId] <> #p20) AND (([t23].[AdminDisplayName] LIKE #p21) OR ([t24].[ItemSku] LIKE #p22)) AND ([t23].[SiteId] = #p23)
) AS [t25]
) AS [t26]
) AS [t27]
WHERE [t27].[SiteProductId] = [t14].[ChildSiteProductId]
)) AND ([t14].[SiteProductAssociationTypeId] = #p24)
) AS [t28]
UNION
SELECT [t29].[ChildSiteProductId]
FROM [dbo].[SiteProductAssociation] AS [t29]
INNER JOIN [dbo].[SiteProductAssociationType] AS [t30] ON [t30].[SiteProductAssociationTypeId] = [t29].[SiteProductAssociationTypeId]
WHERE (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT [t41].[SiteProductId]
FROM (
SELECT [t31].[SiteProductId]
FROM [dbo].[SiteProduct] AS [t31]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t32] ON [t32].[ItemId] = [t31].[ItemId]
WHERE ([t31].[SiteProductTypeId] <> #p25) AND (([t31].[AdminDisplayName] LIKE #p26) OR ([t32].[ItemSku] LIKE #p27)) AND ([t31].[SiteId] = #p28)
UNION
SELECT [t40].[SiteProductId]
FROM (
SELECT [t33].[SiteProductId]
FROM [dbo].[SiteProduct] AS [t33]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t34] ON [t34].[ItemId] = [t33].[ItemId]
WHERE ([t33].[PrimaryParentSiteProductId] IS NOT NULL) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT [t35].[PrimaryParentSiteProductId] AS [value], [t35].[PrimaryParentSiteProductId], [t35].[SiteProductTypeId], [t35].[AdminDisplayName], [t36].[ItemSku], [t35].[SiteId]
FROM [dbo].[SiteProduct] AS [t35]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t36] ON [t36].[ItemId] = [t35].[ItemId]
) AS [t37]
WHERE ([t37].[value] = ([t33].[PrimaryParentSiteProductId])) AND ([t37].[PrimaryParentSiteProductId] IS NOT NULL) AND ([t37].[SiteProductTypeId] <> #p29) AND (([t37].[AdminDisplayName] LIKE #p30) OR ([t37].[ItemSku] LIKE #p31)) AND ([t37].[SiteId] = #p32)
))
UNION
SELECT [t38].[PrimaryParentSiteProductId] AS [value]
FROM [dbo].[SiteProduct] AS [t38]
LEFT OUTER JOIN [dbo].[ItemMaster] AS [t39] ON [t39].[ItemId] = [t38].[ItemId]
WHERE ([t38].[PrimaryParentSiteProductId] IS NOT NULL) AND ([t38].[SiteProductTypeId] <> #p33) AND (([t38].[AdminDisplayName] LIKE #p34) OR ([t39].[ItemSku] LIKE #p35)) AND ([t38].[SiteId] = #p36)
) AS [t40]
) AS [t41]
) AS [t42]
WHERE [t42].[SiteProductId] = [t29].[ParentSiteProductId]
)) AND ([t29].[SiteProductAssociationTypeId] = #p37)
) AS [t43]
) AS [t44]
WHERE [t44].[SiteProductId] = [t0].[SiteProductId]
)
) AS [t45]
WHERE [t45].[ROW_NUMBER] BETWEEN #p38 + 1 AND #p38 + #p39
ORDER BY [t45].[ROW_NUMBER]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1
Instead of using the "select top X from" syntax, the generated SQL uses the ROW_NUMBER() function, and than selects based on it.
It is of course a very heavy operation, as the function is called for every row, and only then is the "WHERE" clause evaluated, while the "SELECT TOP X" syntax just stops execution after X rows are selected.
I can't tell you if it's possible to fix this in LINQ2SQL, but I am quite sure Entity Framework uses "SELECT TOP X FROM" syntax, although I can't tell you for sure.
I don't know how complicated is it for you to move to Entity Framework, but I can tell you for sure it will make your life easier in many ways, and will perform much better, provided you use the .NET 4.0 Entity Framework and not .NET 3.5 SP1.

Categories

Resources