C# 两个相似的LINQ查询,生成的SQL完全不同

C# 两个相似的LINQ查询,生成的SQL完全不同,c#,sql-server,linq,entity-framework,C#,Sql Server,Linq,Entity Framework,我遇到以下伪查询的问题: var daily = from p in db.table1 group p by new { key1, key2 } into g join d in db.table2 on new { p.key1, p.key2 } equals { d.key1, d.key2 }

我遇到以下伪查询的问题:

var daily = from p in db.table1
            group p by new
            {
                key1,
                key2
            } into g
            join d in db.table2
            on new { p.key1, p.key2 } equals { d.key1, d.key2 }
            select new
            {
                col1 = g.Key.key1
                col2 = g.Sum(a => a.column2)
                col3 = d.column3
            };
它运行,但LINQ发送给SQL Server的生成的SQL语句是荒谬的。实际的实现遵循与上面类似的设置,其中有7个或更多的列,每个列都有一个.Sum()计算。生成的SQL大约有10-11条嵌套的SELECT语句,没有内部连接,当然,运行起来需要很长时间

我测试了该查询的另一个实现:

var daily = from p in
                (from p in db.table1
                 group p by new
                 {
                     key1,
                     key2
                 } into g
                 select new
                 {
                     col1 = g.Key.key1,
                     col2 = g.Sum(a => a.column2)
                 })
            join d in db.table2
            on new { p.key1, p.key2 } equals new { d.key1, d.key2 }
            select new
            {
                col1 = p.col1,
                col2 = p.col2,
                col3 = d.column3
            };
这个版本通过一个子SELECT和一个内部JOIN语句生成更合理的SQL(它也可以立即运行)。我讨厌的是,第一个LINQ查询,IMHO,更直接、更简洁,而第二个似乎是多余的,因为我不得不从表1中两次定义我想要的所有列

为什么这两个相似的查询在服务器上的执行情况如此不同,为什么查询2最终会更加高效,尽管它的代码表达能力要差得多


有没有办法重写第一个查询,使其与第二个查询一样高效?

LINQ 2 SQL在以下模式中存在问题:

from t in table
group t by key into g
from t in g //"ungroup" the grouping - this is causing a problem
select ...
我认为您的加入触发了这一点,因为它“解组”了分组。请注意,LINQ连接是在SQL中不可表示的
GroupJoin
。想一想:您将如何翻译我的示例查询?您必须将
table
加入到
table
的分组版本中,从而导致不合理的冗余

这个问题我已经见过好几次了。您已经找到了正确的解决方法:强制投影以防止出现这种模式

有一个稍微不那么尴尬的版本:

var daily = from p in db.table1
            group p by new
            {
                key1,
                key2
            } into g
            select new
            {
                col1 = g.Key.key1,
                col2 = g.Sum(a => a.column2)
            } into p
            join d in db.table2 on new { p.key1, p.key2 } equals new { d.key1, d.key2 }
            select new
            {
                col1 = p.col1,
                col2 = p.col2,
                col3 = d.column3
            };

嵌套被鲜为人知的
select x to y
语法删除。

您能发布两个版本的SQL吗?@usr当然,让我先尝试清理一下,就像我对LINQ查询所做的那样。@Kittoes您可以使用它来编写LINQ并获取Lambda和SQLcode@balexandre我使用
query.ToString()
获得了SQL代码。我只是想在发布之前让它更具用户可读性。你没有使用EF,对吗?标签与L2S标签相矛盾。请移开一个。该死,我真的希望那不是答案。我真的很讨厌为了从表2中得到一列而在表1中定义所有列两次。但我想在这件事上我似乎没有任何选择。@Kittoes这也是我的感受。另一方面,LINQ节省了大量工作,值得容忍这些恶劣的边缘情况。我希望EF团队能够提供称职的LINQ支持,否则L2S不会被放弃……哦,当然。LINQ省下的其他工作量绝对是荒谬的,所以当这种事情发生时,完全值得容忍。只是让我发疯定义10列+两次没有真正的原因。非常感谢你解释为什么会这样。