5

SQLServerデータベースに対するかなり複雑なSQLクエリによって駆動されるレポートを作成するように依頼されました。レポートのサイトはすでにEntityFramework4.1を使用していたので、EFとLINQを使用してクエリを作成しようと思いました。

var q = from r in ctx.Responses
                    .Where(x => ctx.Responses.Where(u => u.UserId == x.UserId).Count() >= VALID_RESPONSES)
                    .GroupBy(x => new { x.User.AwardCity, x.Category.Label, x.ResponseText })
         orderby r.FirstOrDefault().User.AwardCity, r.FirstOrDefault().Category.Label, r.Count() descending
         select new
         {
             City = r.FirstOrDefault().User.AwardCity,
             Category = r.FirstOrDefault().Category.Label,
             Response = r.FirstOrDefault().ResponseText,
             Votes = r.Count()
         };

このクエリは投票を集計しますが、必要な最小投票数を送信したユーザーからのみです。

このアプローチはパフォーマンスの観点からは完全な災害であったため、ADO.NETに切り替えて、クエリを非常に迅速に実行しました。私はSQLプロファイラーを使用してLINQで生成されたSQLを調べましたが、いつものようにひどいように見えましたが、LINQステートメントを最適化して効率を上げる方法についての手がかりは見当たりませんでした。

ストレートTSQLバージョンは次のとおりです。

WITH ValidUsers(UserId)
AS
(
    SELECT UserId
    FROM Responses
    GROUP BY UserId
    HAVING COUNT(*) >= 103
)
SELECT d.AwardCity
    , c.Label
    , r.ResponseText
    , COUNT(*) AS Votes
FROM ValidUsers u
JOIN Responses r ON r.UserId = u.UserId
JOIN Categories c ON r.CategoryId = c.CategoryId
JOIN Demographics d ON r.UserId = d.Id
GROUP BY d.AwardCity, c.Label, r.ResponseText
ORDER BY d.AwardCity, s.SectionName, COUNT(*) DESC

私が疑問に思っているのは、このクエリはEFとLINQが効率的に処理するには複雑すぎるのか、それともトリックを見逃したのかということです。

4

2 に答える 2

4

let を使用して r.First() の数を減らすと、おそらくパフォーマンスが向上します。おそらくまだ十分ではありません。

 var q = from r in ctx.Responses
                .Where()
                .GroupBy()
     let response = r.First()
     orderby response.User.AwardCity, response.Category.Label, r.Count() descending
     select new
     {
         City = response.User.AwardCity,
         Category = response.Category.Label,
         Response = response.ResponseText,
         Votes = r.Count()
     };
于 2013-01-18T01:23:25.573 に答える
1

おそらく、この変更によりパフォーマンスが向上し、結果のネストされた sql 選択が where 句で削除されます

最初に各ユーザーの投票を取得し、それらをDictionary

var userVotes = ctx.Responses.GroupBy(x => x.UserId )
                             .ToDictionary(a => a.Key.UserId,  b => b.Count());

var cityQuery = ctx.Responses.ToList().Where(x => userVotes[x.UserId] >= VALID_RESPONSES)
               .GroupBy(x => new { x.User.AwardCity, x.Category.Label, x.ResponseText })
               .Select(r => new
                       {
                           City = r.First().User.AwardCity,
                           Category = r.First().Category.Label,
                           Response = r.First().ResponseText,
                           Votes = r.Count()
                       })
               .OrderByDescending(r => r.City, r.Category, r.Votes());
于 2013-01-18T01:01:06.277 に答える