两个类似的LINQ查询,完全不同的生成SQL

时间:2012-12-28 00:01:25

标签: 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 }
            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语句,没有INNER JOIN,当然,需要永远运行。

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

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
            };

这个版本使用单个SUB-SELECT和一个INNER JOIN语句生成更合理的SQL(它也会立即运行)。我讨厌这个问题的是,第一个LINQ查询是,恕我直言,更直接和简洁,而第二个看起来相当多余,因为我最终必须两次从table1定义我想要的所有列。

为什么这两个类似的查询在服务器上执行的方式有很大不同?为什么查询2最终效率更高,即使它的代码表达性差得多?

有没有办法可以将第一个查询重写为与第二个查询一样有效?

1 个答案:

答案 0 :(得分:6)

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连接是GroupJoin,在SQL中无法表示。想一想:你会如何翻译我的示例查询?您必须将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 into y语法删除嵌套。