gpt4 book ai didi

c# - 提高 linq 查询的性能

转载 作者:太空宇宙 更新时间:2023-11-03 11:11:29 24 4
gpt4 key购买 nike

我正在使用多个 Linq 查询优化一个方法。到目前为止,执行时间约为 3 秒,我正在努力减少它。该方法中发生了相当多的操作和计算,但没有什么太复杂的。

对于如何提高性能和优化代码的任何建议和想法,我将不胜感激。


方法的全部代码(下面我会指出我延迟最大的地方):

public ActionResult DataRead([DataSourceRequest] DataSourceRequest request)
{
CTX.Configuration.AutoDetectChangesEnabled = false;

var repoKomfortaktion = new KomfortaktionRepository();
var komfortaktionen = CTX.Komfortaktionen.ToList();

var result = new List<AqGeplantViewModel>();

var gruppen = new HashSet<Guid?>(komfortaktionen.Select(c => c.KomfortaktionsGruppeId).ToList());

var hochgeladeneKomplettabzuege = CTX.Komplettabzug.Where(c => gruppen.Contains(c.KomfortaktionsGruppeId)).GroupBy(c => new { c.BetriebId, c.KomfortaktionsGruppeId }).Select(x => new { data = x.Key }).ToList();
var teilnehmendeBetriebe = repoKomfortaktion.GetTeilnehmendeBetriebe(CTX, gruppen);
var hochgeladeneSperrlistenPlz = CTX.SperrlistePlz.Where(c => gruppen.Contains(c.KomfortaktionsGruppeId) && c.AktionsKuerzel != null)
.GroupBy(c => new { c.AktionsKuerzel, c.BetriebId, c.KomfortaktionsGruppeId }).Select(x => new { data = x.Key }).ToList();

var hochgeladeneSperrlistenKdnr = CTX.SperrlisteKdnr.Where(c => gruppen.Contains(c.KomfortaktionsGruppeId) && c.AktionsKuerzel != null)
.GroupBy(c => new { c.AktionsKuerzel, c.BetriebId, c.KomfortaktionsGruppeId }).Select(x => new { data = x.Key }).ToList();

var konfigsProAktion = CTX.Order.GroupBy(c => new { c.Vfnr, c.AktionsId }).Select(c => new { count = c.Count(), c.Key.AktionsId, data = c.Key }).ToList();
foreach (var komfortaktion in komfortaktionen)
{
var item = new AqGeplantViewModel();

var zentraleTeilnehmer = teilnehmendeBetriebe.Where(c => c.TeilnahmeStatus.Any(x => x.KomfortaktionId == komfortaktion.Id && x.AktionsTypeId == 1)).ToList();
var lokaleTeilnehmer = teilnehmendeBetriebe.Where(c => c.TeilnahmeStatus.Any(x => x.KomfortaktionId == komfortaktion.Id && x.AktionsTypeId == 2)).ToList();

var hochgeladeneSperrlistenGesamt =
hochgeladeneSperrlistenPlz.Count(c => c.data.AktionsKuerzel == komfortaktion.Kuerzel && c.data.KomfortaktionsGruppeId == komfortaktion.KomfortaktionsGruppeId) +
hochgeladeneSperrlistenKdnr.Count(c => c.data.AktionsKuerzel == komfortaktion.Kuerzel && c.data.KomfortaktionsGruppeId == komfortaktion.KomfortaktionsGruppeId);

item.KomfortaktionId = komfortaktion.KomfortaktionId;
item.KomfortaktionName = komfortaktion.Aktionsname;
item.Start = komfortaktion.KomfortaktionsGruppe.StartAdressQualifizierung.HasValue ? komfortaktion.KomfortaktionsGruppe.StartAdressQualifizierung.Value.ToString("dd.MM.yyyy") : string.Empty;
item.LokalAngemeldet = lokaleTeilnehmer.Count();
item.ZentralAngemeldet = zentraleTeilnehmer.Count();

var anzHochgelandenerKomplettabzuege = hochgeladeneKomplettabzuege.Count(c => zentraleTeilnehmer.Count(x => x.BetriebId == c.data.BetriebId) == 1) +
hochgeladeneKomplettabzuege.Count(c => lokaleTeilnehmer.Count(x => x.BetriebId == c.data.BetriebId) == 1);

item.KomplettabzugOffen = (zentraleTeilnehmer.Count() + lokaleTeilnehmer.Count()) - anzHochgelandenerKomplettabzuege;

item.SperrlisteOffen = (zentraleTeilnehmer.Count() + lokaleTeilnehmer.Count()) - hochgeladeneSperrlistenGesamt;

item.KonfigurationOffen = zentraleTeilnehmer.Count() - konfigsProAktion.Count(c => c.AktionsId == komfortaktion.KomfortaktionId && zentraleTeilnehmer.Any(x => x.Betrieb.Vfnr == c.data.Vfnr));

item.KomfortaktionsGruppeId = komfortaktion.KomfortaktionsGruppeId;
result.Add(item);
}

return Json(result.ToDataSourceResult(request));
}

前半部分(在 foreach 之前)需要半秒,这没关系。最大的延迟发生在 第一次 迭代中的 foreach 语句内部,特别是在这些行中,第一次执行 zentraleTeilnehmer 需要 1.5 秒。

var zentraleTeilnehmer = teilnehmendeBetriebe.Where(c => c.TeilnahmeStatus.Any(x => x.KomfortaktionId == komfortaktion.Id && x.AktionsTypeId == 1)).ToList();
var lokaleTeilnehmer = teilnehmendeBetriebe.Where(c => c.TeilnahmeStatus.Any(x => x.KomfortaktionId == komfortaktion.Id && x.AktionsTypeId == 2)).ToList();

TeilnehmendeBetriebe 有超过 800 行,其中 TeilnahmeStatus 属性通常有大约 4 个项目。所以,最多 800*4 次迭代,毕竟这不是一个很大的数字...

因此,我主要关注优化这些行,希望将执行时间减少到半秒左右。

我尝试过的:

  1. 将 Linq 重写为 foreach:没有帮助,同时...可能不足为奇,但值得一试。

    foreach (var tb in teilnehmendeBetriebe) //836 items
    {
    foreach (var ts in tb.TeilnahmeStatus) //3377 items
    {
    if (ts.KomfortaktionId == komfortaktion.Id && ts.AktionsTypeId == 1)
    {
    testResult.Add(tb);
    break;
    }
    }
    }
  2. 使用 .Select() 为 teilnehmendeBetriebe 选择特定的列。也没有帮助。

我尝试过的其他小操作都没有帮助。

有趣的是 - 虽然 foreach 的第一次迭代最多可能需要 2 秒,但第二次和进一步只需要几毫秒,因此 .net 能够优化或重用计算数据。

非常欢迎任何有关可以更改以提高性能的建议!

编辑:
TeilnahmeBetriebKomfortaktion.TeilnahmeStatus 在方法 GetTeilnehmendeBetriebe 中急切加载:

    public List<TeilnahmeBetriebKomfortaktion> GetTeilnehmendeBetriebe(Connection ctx, HashSet<Guid?> gruppen)
{
return ctx.TeilnahmeBetriebKomfortaktion.Include(
c => c.TeilnahmeStatus).ToList();
}

编辑2:执行 GetTeilnehmendeBetriebe 时发送的查询:

    SELECT 
[Extent1].[Id] AS [Id],
[Extent1].[BetriebId] AS [BetriebId],
[Extent1].[MandantenId] AS [MandantenId],
[Extent1].[CreatedUser] AS [CreatedUser],
[Extent1].[UpdatedUser] AS [UpdatedUser],
[Extent1].[CreatedDate] AS [CreatedDate],
[Extent1].[UpdatedDate] AS [UpdatedDate],
[Extent1].[IsDeleted] AS [IsDeleted]
FROM [Semas].[TeilnahmeBetriebKomfortaktion] AS [Extent1]
WHERE [Extent1].[IsDeleted] <> cast(1 as bit)

最佳答案

我的假设是 TeilnahmeBetriebKomfortaktion.TeilnahmeStatus 是一个延迟加载的集合,导致 N + 1 problem .您应该急切地获取该集合以提高性能。

foreach 循环的后续迭代很快,因为在第一次迭代之后,这些对象不再从数据库服务器请求,而是从内存服务器请求。

关于c# - 提高 linq 查询的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13878161/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com