5

次の疑似クエリで問題が発生しています。

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 ステートメントはばかげています。実際の実装は、それぞれが .Sum() 計算を持つ 7 つ以上の列を使用して、上記と同様のセットアップに従います。生成された SQL には、INNER JOIN のない入れ子になった SELECT ステートメントが約 10 ~ 11 個含まれており、もちろん、実行に時間がかかります。

クエリの別の実装をテストしました。

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 クエリは IMHO よりもはるかに単純で簡潔であるのに対し、2 番目のクエリは、table1 から必要なすべての列を 2 回定義する必要があるため、かなり冗長に見えることです。

これら 2 つの類似したクエリがサーバー上で非常に異なるパフォーマンスを発揮するのはなぜですか? また、コードの表現力がはるかに低いにもかかわらず、クエリ 2 のほうがはるかに効率的である理由は何ですか?

最初のクエリを 2 番目のクエリと同じくらい効率的に書き直す方法はありますか?

4

1 に答える 1

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 結合は、GroupJoinSQL では表現できないことに注意してください。考えてみてください。私の例のクエリをどのように翻訳しますか? 非常識な冗長性を引き起こす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構文によって削除されます。

于 2012-12-28T00:16:58.423 に答える