【发布时间】:2013-06-13 02:59:20
【问题描述】:
我有以下使用 EF5 和通用存储库的 LINQ 查询,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 秒,只是想知道是否有人对如何使其更快有任何想法/指示。
提前谢谢马克
【问题讨论】:
-
在我看来,EF 不是此类查询的正确工具。可能生成的 sql 语句很糟糕。我建议使用存储过程和/或视图。当然你可以从 EF 调用它。
-
分析查询计划以确定是否缺少任何索引
-
您的工作单元模式是否支持延迟加载?如果没有,那将大大提高速度。
-
@DavideIcardi 无论您选择用什么编写查询,如果您做得不好,它在 SQL 中将无法正常工作。 EF 和 SP 也是如此。您应该始终检查生成的 SQL/查询计划,如果它不好,请修复您的查询...
标签: linq entity-framework optimization entity-framework-5