2012-03-15 19 views
1

I持っタイムアウト次のコード:私はSQL Serverプロファイラを使用してSQLをプロファイリングし、実行されたSQLをつかん奇妙なLINQ()

 using (var ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted })) 
     { 
      ECWSDataContext dc = new ECWSDataContext(); 

      IQueryable<Ticket> results = dc.Tickets; 
      Business.TicketStatistic statistic = results 
       .Select(r => new 
       { 
        GroupID = 1, 
        IsVoided = r.IsVoided ? 1 : 0, 
        IsWarning = r.TicketFilingTypeID == 5 ? 1 : 0, 
        TotalFelonies = r.TotalFelonies, 
        TotalMisdemeanors = r.TotalMisdemeanors, 
        TotalInfractions = r.TotalInfractions, 
        TotalOrdinances = r.TotalOrdinances, 
        TotalWarnings = r.TotalWarnings 
       }) 
       .GroupBy(t => t.GroupID) 
       .Select(g => new Business.TicketStatistic() 
       { 
        TotalTickets = g.Count(), 
        TotalVoids = g.Sum(x => x.IsVoided), 
        TotalTicketWarnings = g.Sum(x => x.IsWarning), 
        TotalFelonies = g.Sum(x => x.TotalFelonies), 
        TotalMisdemeanors = g.Sum(x => x.TotalMisdemeanors), 
        TotalInfractions = g.Sum(x => x.TotalInfractions), 
        TotalOrdinances = g.Sum(x => x.TotalOrdinances), 
        TotalOffenseWarnings = g.Sum(x => x.TotalWarnings) 
       }).FirstOrDefault(); 
     } 

。予想通り、TOP 1が含まれています。SQL Management Studioで正確なSQLを実行すると、まったく時間がかかりません。それでも、コード内でタイムアウトし続けます。驚くべきことに、うまく次のような作品にそれを変える:

 using (var ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted })) 
     { 
      ECWSDataContext dc = new ECWSDataContext(); 

      IQueryable<Ticket> results = dc.Tickets; 

      var stats = results 
       .Select(r => new 
       { 
        GroupID = 1, 
        IsVoided = r.IsVoided ? 1 : 0, 
        IsWarning = r.TicketFilingTypeID == 5 ? 1 : 0, 
        TotalFelonies = r.TotalFelonies, 
        TotalMisdemeanors = r.TotalMisdemeanors, 
        TotalInfractions = r.TotalInfractions, 
        TotalOrdinances = r.TotalOrdinances, 
        TotalWarnings = r.TotalWarnings 
       }) 
       .GroupBy(t => t.GroupID) 
       .Select(g => new Business.TicketStatistic() 
       { 
        TotalTickets = g.Count(), 
        TotalVoids = g.Sum(x => x.IsVoided), 
        TotalTicketWarnings = g.Sum(x => x.IsWarning), 
        TotalFelonies = g.Sum(x => x.TotalFelonies), 
        TotalMisdemeanors = g.Sum(x => x.TotalMisdemeanors), 
        TotalInfractions = g.Sum(x => x.TotalInfractions), 
        TotalOrdinances = g.Sum(x => x.TotalOrdinances), 
        TotalOffenseWarnings = g.Sum(x => x.TotalWarnings) 
       }).ToArray(); 

      Business.TicketStatistic statistic = stats.FirstOrDefault(); 
     } 

は、私は今、私は今、メモリ内のコレクションにFirstOrDefault()を適用する前に結果を列挙していますことを理解しています。しかし、SQL Serverで直接最初のシナリオで同じSQL出力を実行することは問題ありませんでした。

誰かがここで何が起こっているか説明できますか?この例では、それは常に1つの行を返すグループクエリでした。 FirstOrDefault()を適用する前に列挙できることは幸運です。

SELECT TOP 1 Field1, Field2... 
FROM 
(
    SELECT SUM(Field) as Field1, ... 
    FROM ... 
) SUB 

:しかし、将来の参考のため、そのクエリは、数千行がどの私が唯一のTOP 1.

ADDITION INFO

.FirstOrDefaultを使用してSQLを()望んでいたために何を返した場合.ToArrayを使用してSQL():

SELECT SUM(Field) as Field1, ... 
FROM ... 

SQL MGT Studioで直接的に実行するには、トンでも同じ結果になりました彼は同じ時間量。しかし、LINQが最初のものを実行すると、タイムアウトになります。

+0

最初の結果を取得する前に、あなたがToArray()を呼び出したという違いがありますか? –

+0

だから、すべての結果を元に戻すことはうまくいきますが、LINQクエリにTOP 1を追加するとタイムアウトすると言っていますか? – Jeff

+0

これは唯一の違いです。生成されたSQLの違いは、期待どおりです。後者では、グループ化されたSQLを期待どおりに取得します。最初にToArray()を使用せずに、SELECT TOP 1ラッパーを使用してサブSELECTと同じSQLを取得します。どちらの方法でも、mgt studioで両方のSQL文を手動で実行すると、同じ結果が得られました。 –

答えて

0

これは、linq to sqlを使用する場合の一般的な問題です。あなたがsqlについて考えるなら、あなたがグループを作成してから最初のデフォルトを行うときには、SQLに集計してから集計するように求めています。 SQLでは、個々の要素に到達するために複数のクエリを実行するので、グループ内の個々の要素を処理するのは難しいです。

ToArrayを実行すると、実際にデータをメモリに戻すことができ、グループの要素は個々の要素を持つメモリに実際に格納されるため、これらの到達は非常に高速になります。