加速LINQ查询 - EF5

时间:2013-06-08 13:10:02

标签: linq entity-framework optimization entity-framework-5

我有以下LINQ查询使用EF5和通用存储库,工作模式到SQL Server 2008 db

        var countriesArr = GetIdsFromDelimStr(countries);
        var competitionsArr = GetIdsFromDelimStr(competitions);
        var filterTeamName = string.Empty;

        if (teamName != null)
        {
            filterTeamName = teamName.ToUpper();
        }

        using (var unitOfWork = new FootballUnitOfWork(ConnFooty))
        {

            // give us our selection of teams
            var teams =
                (from team in
                     unitOfWork.TeamRepository.Find()
                 where ((string.IsNullOrEmpty(filterTeamName) || team.Name.ToUpper().Contains(filterTeamName)) &&
                        (countriesArr.Contains(team.Venue.Country.Id) || countriesArr.Count() == 0))
                 select new
                            {
                                tId = team.Id
                            }).Distinct();

            // give us our selection of contests
            var conts = (
                            from cont in
                                unitOfWork.ContestRepository.Find(
                                    c =>
                                    ((c.ContestType == ContestType.League && competitionsArr.Count() == 0) ||
                                     (competitionsArr.Contains(c.Competition.Id) && competitionsArr.Count() == 0)))
                            select new
                                       {
                                           contId = cont.Id
                                       }
                        ).Distinct();

            // get selection of home teams based on contest
            var homecomps = (from fixt in unitOfWork.FixtureDetailsRepository.Find()
                             where
                                 teams.Any(t => t.tId == fixt.HomeTeam.Id) &&
                                 conts.Any(c => c.contId == fixt.Contest.Id)
                             select new
                                        {
                                            teamId = fixt.HomeTeam.Id,
                                            teamName = fixt.HomeTeam.Name,
                                            countryId = fixt.HomeTeam.Venue.Country.Id != null ? fixt.HomeTeam.Venue.Country.Id : 0,
                                            countryName = fixt.HomeTeam.Venue.Country.Id != null ? fixt.HomeTeam.Venue.Country.Name : string.Empty,
                                            compId = fixt.Contest.Competition.Id,
                                            compDesc = fixt.Contest.Competition.Description
                                        }).Distinct();

            // get selection of away teams based on contest
            var awaycomps = (from fixt in unitOfWork.FixtureDetailsRepository.Find()
                             where
                                 teams.Any(t => t.tId == fixt.AwayTeam.Id) &&
                                 conts.Any(c => c.contId == fixt.Contest.Id)
                             select new
                             {
                                 teamId = fixt.AwayTeam.Id,
                                 teamName = fixt.AwayTeam.Name,
                                 countryId = fixt.AwayTeam.Venue.Country.Id != null ? fixt.AwayTeam.Venue.Country.Id : 0,
                                 countryName = fixt.AwayTeam.Venue.Country.Id != null ? fixt.AwayTeam.Venue.Country.Name : string.Empty,
                                 compId = fixt.Contest.Competition.Id,
                                 compDesc = fixt.Contest.Competition.Description
                             }).Distinct();

            // ensure that we return the max competition based on id for home teams
            var homemax = (from t in homecomps
                           group t by t.teamId
                               into grp
                               let maxcomp = grp.Max(g => g.compId)
                               from g in grp
                               where g.compId == maxcomp
                               select g).Distinct();

            // ensure that we return the max competition based on id for away teams
            var awaymax = (from t in awaycomps
                           group t by t.teamId
                               into grp
                               let maxcomp = grp.Max(g => g.compId)
                               from g in grp
                               where g.compId == maxcomp
                               select g).Distinct();

            var filteredteams = homemax.Union(awaymax).OrderBy(t => t.teamName).AsQueryable();

正如您所看到的,我们希望返回传递给WebAPI的以下格式,因此我们将结果转换为UI中可以关联的类型。

基本上我们要做的就是让主场和客场球队从比赛中获得,这些赛程有一场与比赛有关的比赛。然后我们从分组中获得最高的竞争ID,然后与该团队一起返回。这个国家是根据场地ID与球队有关的,当我最初这样做的时候,我在找到怎么做或加入linq时遇到了问题,这就是为什么我把它拆分为主队和客队然后根据他们分组在竞争中然后将它们结合在一起。

当前表格大小的想法是灯具有7840行,团队有8581行,比赛有337行,比赛有96行。可能会迅速增加的表是固定表,因为这与足球有关。

我们想要的结果是

球队ID,球队名称,国家ID,国家/地区名称,比赛ID,比赛名称

不使用过滤这个查询平均需要大约5秒,只是想知道是否有人对如何更快地提出任何想法/指示。

提前感谢马克

1 个答案:

答案 0 :(得分:1)

我无法判断它是否能加快速度,但您的homemaxawaymax查询可能

var homemax = from t in homecomps
              group t by t.teamId into grp
              select grp.OrderByDescending(x => x.compId).FirstOrDefault();

var awaymax = from t in awaycomps
              group t by t.teamId into grp
              select grp.OrderByDescending(x => x.compId).FirstOrDefault();

此外,当您编写一个非常大的查询时,当您在一些获取中间结果的较小查询中将其剪切时,它可能会表现得更好。有时,对数据库的一些往返次数比一个非常大的查询要好,因为数据库引擎无法找到一个好的执行计划。

另一件事是所有这些Distinct()。你总是需要它们吗?我认为你可以不用,因为你总是从一个表中获取数据而不加入子集合。删除它们可能会节省很多。

另一个优化可能是删除ToUpper。比较由SQL中的数据库引擎完成,可能是数据库具有不区分大小写的排序规则。如果是这样,即使您想要它,对比也不会区分大小写!像Name.ToUpper这样的构造取消了Name上任何索引的使用(它不是sargable)。