【问题标题】:What would be a reasonably fast way to code this sql query in c#?在 c# 中编写这个 sql 查询的一种相当快速的方法是什么?
【发布时间】:2013-04-05 19:17:22
【问题描述】:

我有这个 SQL 查询:

select 
    sum(h.nbHeures) 
from 
    Heures h
join 
    HeuresProjets hp on h.HpGuid=hp.HPId
join 
    ActivityCodes ac on h.Code=ac.ActivityId
join 
    MainDoeuvre mdo on ac.ActivityId=mdo.CodeGuid
where 
    hp.ExtraGuid = '61E931C8-3268-4C9C-9FF5-ED0213D348D0' 
    and mdo.NoType = 1

它在不到一秒的时间内运行,这很好。我的项目使用 LINQ to 实体来获取数据。这个(非常类似于 sql)查询非常慢,需要一分钟以上。

  var result = (from hp in this.HeuresProjets
                join h in ctx.Heures on hp.HPId equals h.HpGuid
                join ac in ctx.ActivityCodes on h.Code equals ac.ActivityId
                join mdo in ctx.MainDoeuvre on ac.ActivityId equals mdo.CodeGuid
                where hp.ExtraGuid == this.EntityGuid && mdo.NoType == (int)spType
                select h.NbHeures).Sum();
  total = result; 

我尝试使用嵌套循环。它更快但仍然很慢(约 15 秒)。

foreach (HeuresProjets item in this.HeuresProjets)
{
         foreach (Heures h in ctx.Heures.Where(x => x.HpGuid == item.HPId))
         {
               if (h.ActivityCodes != null && h.ActivityCodes.MainDoeuvre.FirstOrDefault() != null && h.ActivityCodes.MainDoeuvre.First().NoType == (int)type)
               {
                      total += h.NbHeures;
               }
          }
}

我做错了什么吗?如果没有办法对此进行优化,我将只调用一个存储过程,但我真的希望将逻辑保留在代码中。

编辑

我根据 IronMan84 的建议修改了我的查询。

decimal total = 0;

var result = (from hp in ctx.HeuresProjets
              join h in ctx.Heures on hp.HPId equals h.HpGuid
              join ac in ctx.ActivityCodes on h.Code equals ac.ActivityId
              join mdo in ctx.MainDoeuvre on ac.ActivityId equals mdo.CodeGuid
              where hp.ExtraGuid == this.EntityGuid && mdo.NoType == (int)spType
              select h);

if(result.Any())
  total = result.Sum(x=>x.NbHeures);

这几乎可行。它运行速度很快并返回一个小数但是:
1. 这不是正确的值
2. 结果被清晰地缓存,因为它返回完全相同的值但参数不同。

【问题讨论】:

  • 您是否查看过 SQL Profiler 以了解 LINQ 查询在后台执行的 SQL?
  • @Pete SQL Profiler 未安装,'下载完成后我看看它
  • 您可以阅读帖子stackoverflow.com/questions/696431/… 来解决您的可空和问题。

标签: sql linq linq-to-entities


【解决方案1】:

通过查看您的代码,我认为您的查询正在从您要加入的那些表中获取每条记录(因此需要很长时间)。我看到您使用this.HeuresProjets,我假设它是您已经从数据库中获取的数据库对象的集合(这就是您不使用ctx.HeuresProjets 的原因)。那么,当您进行联接查询时,该集合可能已经被水合了。在这种情况下,它变成了一个 LINQ-To-Objects 查询,需要 EF 去抓取所有其他表的记录才能完成连接。

假设我的假设是正确的(如果我错了,请告诉我),你可能想试试这个:

var result = (from hp in ctx.HeuresProjets
                join h in ctx.Heures on hp.HPId equals h.HpGuid
                join ac in ctx.ActivityCodes on h.Code equals ac.ActivityId
                join mdo in ctx.MainDoeuvre on ac.ActivityId equals mdo.CodeGuid
                where hp.ExtraGuid == this.EntityGuid && mdo.NoType == (int)spType
                select h).Sum(h => h.NbHeures);
total = result; 

此外,如果this.HeuresProjets 是仅包含特定对象的过滤列表,则您只需将其添加到查询的where 子句中即可确保ID 在this.HeuresProjets.Select(hp => hp.HPId)

【讨论】:

  • Changing 'this' for 'ctx' 给我这个错误:“转换为值类型 'Decimal' 失败,因为物化值为 null。”,这很奇怪,因为其中唯一的小数是h.NbHeures 并且它不能为空。
  • 表示查询结果为空。
  • 好的,但不应该为空。不过速度真的很快,我希望我们能解决它
  • 好的,我尝试只“选择 h”,然后执行 if (result.Any()) total = result.Sum(x=>x.NbHeures);它有点工作,但查询被清楚地缓存了,因为我为不同的项目(“this”)得到了相同的值。
  • 您的最新编辑再次给了我“The cast to value [...]”错误。让我编辑我的帖子以更清晰
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-17
  • 1970-01-01
  • 2011-11-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多