【问题标题】:How to write this SQL query in Entity Framework?如何在实体框架中编写此 SQL 查询?
【发布时间】:2013-01-06 10:42:43
【问题描述】:

我有这个查询,我想将其从 Entity Framework 1:1 翻译成 SQL:

SELECT GroupId, ItemId, count(*) as total
  FROM [TESTDB].[dbo].[TestTable]
  WHERE GroupId = '64025'
  GROUP BY GroupId, ItemId
  ORDER BY GroupId, total DESC

此 SQL 查询应根据相同 ItemId(针对该组)的出现次数进行排序。

我现在有这个:

from x in dataContext.TestTable.AsNoTracking()
where x.GroupId = 64025
group x by new {x.GroupId, x.ItemId}
into g
orderby g.Key.GroupId, g.Count() descending 
select new {g.Key.GroupId, g.Key.ItemId, Count = g.Count()};

但这会生成以下 SQL 代码:

SELECT 
  [GroupBy1].[K1] AS [GroupId], 
  [GroupBy1].[K2] AS [ItemId], 
  [GroupBy1].[A2] AS [C1]
FROM ( SELECT 
         [Extent1].[GroupId] AS [K1], 
         [Extent1].[ItemId] AS [K2], 
         COUNT(1) AS [A1], 
         COUNT(1) AS [A2]
       FROM [dbo].[TestTable] AS [Extent1]
       WHERE 64025 = [Extent1].[GroupId]
       GROUP BY [Extent1].[GroupId], [Extent1].[ItemId]
     )  AS [GroupBy1]
ORDER BY [GroupBy1].[K1] ASC, [GroupBy1].[A1] DESC

这也有效,但比我创建的 SQL 慢 2 倍。

我一直在摆弄 linq 代码,但我还没有设法创建类似于我的查询的东西。

执行计划(只有最后两项,前两项相同):

FIRST:   |--Stream Aggregate(GROUP BY:([Extent1].[ItemId]) DEFINE:([Expr1006]=Count(*), [Extent1].[GroupId]=ANY([TESTDB].[dbo].[TestTable].[GroupId] as [Extent1].[GroupId])))
           |--Index Seek(OBJECT:([TESTDB].[dbo].[TestTable].[IX_Group]), SEEK:([TESTDB].[dbo].[TestTable].[GroupId]=(64034)) ORDERED FORWARD)

SECOND:  |--Stream Aggregate(GROUP BY:([TESTDB].[dbo].[TestTable].[ItemId]) DEFINE:([Expr1007]=Count(*), [TESTDB].[dbo].[TestTable].[GroupId]=ANY([TESTDB].[dbo].[TestTable].[GroupId])))
           |--Index Seek(OBJECT:([TESTDB].[dbo].[TestTable].[IX_Group] AS [Extent1]), SEEK:([Extent1].[GroupId]=(64034)) ORDERED FORWARD)

【问题讨论】:

  • 为什么不在 LINQ 中使用 TOP 功能?在 Lambdas 中至少存在(顶部,跳过函数)。您的速度差异可能会拉动所有元素 - 而不仅仅是前 1000 个元素。 EF版?他们致力于制作更好的 SQL。
  • @TomTom,我知道它存在,我需要所有数据,但使用 TOP 的查询只是我自己的快速测试。我从问题中删除了它,所以请忽略:)
  • 嗯,闻起来像糟糕的 SQL - EF 以它而闻名。不确定可以做很多事情。您使用哪个 EF 版本?使用 5 adand mabe 6 会更好,否则您可以在 codeplex 的 EF 端询问,开发人员可能会加入。
  • 执行计划是什么?糟糕的统计数据可能会导致等效查询的不同计划。
  • 执行计划相同。只有名称不同。

标签: c# sql-server sql-server-2008 entity-framework


【解决方案1】:

Entity Framework 生成的查询和您手工制作的查询在语义上是相同的,并且会给出相同的计划。

派生表定义在查询优化期间内联,因此唯一的区别可能是解析和编译期间的一些极小的额外开销。

你发的SHOWPLAN_TEXT的sn-ps是同一个方案。唯一的区别是别名。看起来你的表定义是这样的。

CREATE TABLE [dbo].[TestTable] 
(
[GroupId] INT,
[ItemId] INT
)

CREATE NONCLUSTERED INDEX IX_Group ON  [dbo].[TestTable] ([GroupId], [ItemId]) 

你得到了这样的计划

从所有意图和目的来看,这些计划都是相同的。您的性能测试方法可能存在缺陷。例如,也许您的第一个查询将页面带入缓存,然后使第二个查询受益。

【讨论】:

  • 谢谢,很有趣。我用 10000 次迭代多次测试了这两种变体,我自己的 sql 代码总是快 2 倍。 TestTable 仅包含另一列(仅整数,名为 SetId),我不怀疑这会导致差异吗? PK 在所有三个列(SetId、GroupId、ItemId)上设置,非聚集索引在 GroupId、SetId 上。您发布的执行计划图形看起来确实与我在这里看到的相似。由于您的帖子,我再次对此进行了测试,现在我确实看到了类似的结果。也许这毕竟只是某个地方的温度差异。
  • @Areius - 您是在测试实际的原始查询还是 EF 的性能与从 C# 发送的原始查询的对比? EF 有编译查询的开销,除非您要使用已编译的查询。
  • 都来自 EF,我自己使用 EF 的 'SqlQuery' 方法。
猜你喜欢
  • 1970-01-01
  • 2016-06-05
  • 1970-01-01
  • 2020-11-09
  • 1970-01-01
  • 2022-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多