【发布时间】:2016-11-19 12:30:46
【问题描述】:
我有这个架构:
Lists ( ListId, Name, DateCreated, ... )
ListItems( ListId, Text, Foo, Baz, Qux, ... )
我有一个 IQueryable<List> 代表另一个 Linq 查询,它返回一些 List 实体。
我想用ListItems 的一些聚合数据来JOIN 它,但事实证明这很困难,因为 Linq 生成的 SQL 效率低下 - 但我也想让查询可组合。
这是类似于我希望 Linq 生成的 SQL:
选择
*
从
(
-- 这部分代表 IQueryable:
选择
列表 ID,
姓名,
...
从
列表
订购方式
Lists.DateCreated
抵消
0 ROWS 仅获取下一个 25 行——Linq 的 .Skip(0).Take(25)
) AS ListsResult
左连接
(
-- 这是我希望 Linq 生成的聚合数据查询:
选择
列表 ID,
计数(1)作为[计数],
计数(当 Foo = 'bar' THEN 1 ELSE NULL END 时的情况)作为 CountFooBar,
计数(当 Baz > 5 然后 1 ELSE NULL END 时的情况)作为 CountBaz5
从
列表项
在哪里
Qux 不为空
通过...分组
列表 ID
) AS ItemsStats ON ListResults.ListId = ItemsStats.ListId
这是我拥有的 Linq - 我更喜欢扩展方法语法:
IQueryable 列表 = GetLists(0, 25);
var stats = this.dbContext.ListItems
.Where( (ListItem li) => li.Qux != null )
.GroupBy( (ListItem li) => li.ListId )
.Select(grp => 新
{
grp.Key,
计数 = grp.Count(),
CountFooBar = grp.Count( (ListItem li) => li.Foo == "bar" )
CountBaz5 = grp.Count( (ListItem li) => li.Baz > 5 )
})
返回列表
。加入(
内部:统计数据,
outerKeySelector: (List l) => l.ListId,
innerKeySelector: grp => grp.Key,
resultSelector: (list, itemStats) => new { list, itemsStats }
)
但是,这会生成如下所示的 SQL(此查询显示了我的真实表和列名,这比我之前发布的架构要复杂一些:)
选择 [项目 13].[C2] 作为 [C1], [Project13].[ListId] AS [ListId], [项目 13].[C1] 作为 [C2], [项目 13].[C3] 作为 [C3], [项目 13].[C4] 作为 [C4], [项目 13].[C5] 作为 [C5], [项目 13].[C6] 作为 [C6], [项目 13].[C7] 作为 [C7] 从(选择 [项目 11].[C1] 作为 [C1], [Project11].[ListId] AS [ListId], [项目 11].[C2] 作为 [C2], [项目 11].[C3] 作为 [C3], [项目 11].[C4] 作为 [C4], [项目 11].[C5] 作为 [C5], [项目11].[C6] AS [C6], (选择 计数(1) 作为 [A1] FROM (SELECT [Project12].[ListId] AS [ListId] 从(选择 [Extent11].[ListId] AS [ListId], [Extent11].[已创建] AS [已创建] FROM [dbo].[Lists] AS [Extent11] WHERE ([Extent11].[TenantId] = 8) AND ([Extent11].[BlarghId] = 8) ) 作为 [项目 12] ORDER BY [Project12].[Created] DESC 偏移量 0 行仅获取下一个 25 行)作为 [Limit6] INNER JOIN [dbo].[ListItems] AS [Extent12] ON ([Limit6].[TenantId] = [Extent12].[TenantId]) AND ([Limit6].[BlarghId] = [Extent12].[BlarghId]) AND ([Limit6].[ListId] = [Extent12].[ListId]) WHERE (([Extent12].[Baz] > 0) OR ((LEN([Extent12].[Notes])) > 0) OR ((LEN([Extent12].[Value])) > 0)) AND ( [Project11].[TenantId] = [Extent12].[TenantId]) AND ([Project11].[BlarghId] = [Extent12].[BlarghId]) AND ([Project11].[ListId] = [Extent12].[ListId ]) AND ([Extent12].[RecommendationRevision] 不为空)) 作为 [C7] 从(选择 [项目 9].[C1] 作为 [C1], [Project9].[TenantId] 作为 [TenantId], [项目 9].[BlarghId] 作为 [BlarghId], [Project9].[ListId] AS [ListId], [项目 9].[C2] 作为 [C2], [项目 9].[C3] 作为 [C3], [项目 9].[C4] 作为 [C4], [项目 9].[C5] 作为 [C5], (选择 计数(1) 作为 [A1] FROM (SELECT [Project10].[TenantId] AS [TenantId], [Project10].[BlarghId] AS [BlarghId], [Project10].[ListId] AS [ListId] 从(选择 [Extent9].[TenantId] AS [TenantId], [Extent9].[BlarghId] 作为 [BlarghId], [Extent9].[ListId] AS [ListId], [Extent9].[已创建] AS [已创建] FROM [dbo].[Lists] AS [Extent9] WHERE ([Extent9].[TenantId] = 8) AND ([Extent9].[BlarghId] = 8) ) 作为 [Project10] ORDER BY [Project10].[Created] DESC 偏移量 0 行仅获取下一个 25 行)作为 [Limit5] INNER JOIN [dbo].[ListItems] AS [Extent10] ON ([Limit5].[TenantId] = [Extent10].[TenantId]) AND ([Limit5].[BlarghId] = [Extent10].[BlarghId]) AND ([Limit5].[ListId] = [Extent10].[ListId]) WHERE (([Extent10].[Baz] > 0) OR ((LEN([Extent10].[Notes])) > 0) OR ((LEN([Extent10].[Value])) > 0)) AND ( [Project9].[TenantId] = [Extent10].[TenantId]) AND ([Project9].[BlarghId] = [Extent10].[BlarghId]) AND ([Project9].[ListId] = [Extent10].[ListId ]) AND (3 = [Extent10].[Baz])) AS [C6] 从(选择 [项目 7].[C1] 作为 [C1], [Project7].[TenantId] 作为 [TenantId], [项目 7].[BlarghId] 作为 [BlarghId], [Project7].[ListId] AS [ListId], [项目7].[C2] AS [C2], [项目 7].[C3] 作为 [C3], [项目 7].[C4] 作为 [C4], (选择 计数(1) 作为 [A1] FROM (SELECT [Project8].[TenantId] AS [TenantId], [Project8].[BlarghId] AS [BlarghId], [Project8].[ListId] AS [ListId] 从(选择 [Extent7].[TenantId] 作为 [TenantId], [Extent7].[BlarghId] 作为 [BlarghId], [Extent7].[ListId] AS [ListId], [Extent7].[已创建] AS [已创建] FROM [dbo].[Lists] AS [Extent7] WHERE ([Extent7].[TenantId] = 8) AND ([Extent7].[BlarghId] = 8) ) 作为 [项目8] ORDER BY [Project8].[Created] DESC 偏移量 0 行仅获取下一个 25 行)作为 [Limit4] INNER JOIN [dbo].[ListItems] AS [Extent8] ON ([Limit4].[TenantId] = [Extent8].[TenantId]) AND ([Limit4].[BlarghId] = [Extent8].[BlarghId]) AND ([Limit4].[ListId] = [Extent8].[ListId]) WHERE (([Extent8].[Baz] > 0) OR ((LEN([Extent8].[Notes])) > 0) OR ((LEN([Extent8].[Value])) > 0)) AND ( [Project7].[TenantId] = [Extent8].[TenantId]) AND ([Project7].[BlarghId] = [Extent8].[BlarghId]) AND ([Project7].[ListId] = [Extent8].[ListId ]) AND (2 = [Extent8].[Baz])) AS [C5] 从(选择 [项目 5].[C1] 作为 [C1], [Project5].[TenantId] 作为 [TenantId], [项目 5].[BlarghId] 作为 [BlarghId], [Project5].[ListId] AS [ListId], [项目5].[C2] AS [C2], [项目 5].[C3] 作为 [C3], (选择 计数(1) 作为 [A1] FROM (SELECT [Project6].[TenantId] AS [TenantId], [Project6].[BlarghId] AS [BlarghId], [Project6].[ListId] AS [ListId] 从(选择 [Extent5].[TenantId] AS [TenantId], [Extent5].[BlarghId] 作为 [BlarghId], [Extent5].[ListId] AS [ListId], [Extent5].[已创建] AS [已创建] FROM [dbo].[Lists] AS [Extent5] WHERE ([Extent5].[TenantId] = 8) AND ([Extent5].[BlarghId] = 8) ) 作为 [项目6] ORDER BY [Project6].[Created] DESC 偏移量 0 行仅获取下一个 25 行)作为 [限制 3] INNER JOIN [dbo].[ListItems] AS [Extent6] ON ([Limit3].[TenantId] = [Extent6].[TenantId]) AND ([Limit3].[BlarghId] = [Extent6].[BlarghId]) AND ([Limit3].[ListId] = [Extent6].[ListId]) WHERE (([Extent6].[Baz] > 0) OR ((LEN([Extent6].[Notes])) > 0) OR ((LEN([Extent6].[Value])) > 0)) AND ( [Project5].[TenantId] = [Extent6].[TenantId]) AND ([Project5].[BlarghId] = [Extent6].[BlarghId]) AND ([Project5].[ListId] = [Extent6].[ListId ]) AND (1 = [Extent6].[Baz])) AS [C4] 从(选择 [项目 3].[C1] 作为 [C1], [Project3].[TenantId] 作为 [TenantId], [项目 3].[BlarghId] 作为 [BlarghId], [Project3].[ListId] AS [ListId], [项目3].[C2] AS [C2], (选择 计数(1) 作为 [A1] FROM (SELECT [Project4].[TenantId] AS [TenantId], [Project4].[BlarghId] AS [BlarghId], [Project4].[ListId] AS [ListId] 从(选择 [Extent3].[TenantId] AS [TenantId], [Extent3].[BlarghId] 作为 [BlarghId], [Extent3].[ListId] AS [ListId], [Extent3].[已创建] AS [已创建] FROM [dbo].[Lists] AS [Extent3] WHERE ([Extent3].[TenantId] = 8) AND ([Extent3].[BlarghId] = 8) ) 作为 [项目4] ORDER BY [Project4].[Created] DESC 偏移量 0 行仅获取下一个 25 行)作为 [Limit2] INNER JOIN [dbo].[ListItems] AS [Extent4] ON ([Limit2].[TenantId] = [Extent4].[TenantId]) AND ([Limit2].[BlarghId] = [Extent4].[BlarghId]) AND ([Limit2].[ListId] = [Extent4].[ListId]) WHERE (([Extent4].[Baz] > 0) OR ((LEN([Extent4].[Notes])) > 0) OR ((LEN([Extent4].[Value])) > 0)) AND ( [Project3].[TenantId] = [Extent4].[TenantId]) AND ([Project3].[BlarghId] = [Extent4].[BlarghId]) AND ([Project3].[ListId] = [Extent4].[ListId ]) AND ([Extent4].[Foo] = 1)) AS [C3] 从(选择 [GroupBy1].[A1] AS [C1], [GroupBy1].[K1] AS [TenantId], [GroupBy1].[K2] AS [BlarghId], [GroupBy1].[K3] AS [ListId], [GroupBy1].[K4] AS [C2] 从(选择 [项目2].[K1] AS [K1], [项目2].[K2] AS [K2], [项目2].[K3] AS [K3], [项目2].[K4] AS [K4], 计数([项目 2].[A1])作为 [A1] 从(选择 [Project2].[TenantId] AS [K1], [项目2].[BlarghId] AS [K2], [Project2].[ListId] AS [K3], 1 AS [K4], 1 作为 [A1] 从(选择 [Extent2].[ListId] AS [ListId] FROM (SELECT [Project1].[ListId] AS [ListId] 从(选择 [Extent1].[ListId] AS [ListId], [Extent1].[已创建] AS [已创建] FROM [dbo].[Lists] AS [Extent1] WHERE ([Extent1].[TenantId] = 8) AND ([Extent1].[BlarghId] = 8) ) 作为 [项目1] ORDER BY [Project1].[Created] DESC 偏移量 0 行仅获取下一个 25 行)作为 [Limit1] 内部联接 [dbo].[ListItems] AS [Extent2] ON (([Limit1].[ListId] = [Extent2].[ListId]) WHERE ([Extent2].[Baz] > 0) OR ((LEN([Extent2].[Notes])) > 0) OR ((LEN([Extent2].[Value])) > 0) ) 作为 [项目2] ) 作为 [项目2] 按 [K1]、[K2]、[K3]、[K4] 分组 ) AS [GroupBy1] ) 作为 [项目3] ) 作为 [项目5] ) 作为 [项目7] ) 作为 [项目 9] ) 作为 [Project11] ) 作为 [项目 13]它根本不会将COUNT() 语句组合在一起,而是将COUNT 谓词移动到单独的WHERE 子句中。还要注意重复的分页子查询(其中使用了OFFSET 0 ROW FETCH NEXT 25),而我的手写查询只执行一次。
【问题讨论】:
标签: sql linq linq-to-entities