linq 更新1400万行的过程缓慢

e1xvtsh3  于 2022-12-06  发布在  其他
关注(0)|答案(2)|浏览(90)

我需要更新1400万条记录的值和位置/其他信息。我在interval_list中有1400万条记录。每次迭代我都使用Interval对象中的MeterID来获得正确的位置和乘数。然后更新位置并基于乘数更新值。此代码需要4个多小时来运行。有更好的方法来完成此操作吗?- 谢谢-谢谢

foreach (Interval interval in interval_list)
{       
    var result = from m in meterList
                 where m.MeterID.Equals(interval.MeterID)
                 where m.StartDate < (interval.UTCDateTime.ToLocalTime())
                 where m.FinalDate > (interval.UTCDateTime.ToLocalTime())
                 select m;

    if (result.Count() == 1) //Ignore if > 1
    {
        int mult1 = result.ElementAt(0).Mult1;
        int mult2 = result.ElementAt(0).Mult2;
        interval.ServiceID = result.ElementAt(0).Locserv;
                                       
        // With updating check to see if value is already adjusted by mult

        if (interval.Mult1 > 1)
        {
            interval.Value = interval.Value / interval.Mult1;
            interval.Value = interval.Value * mult1;
        }

        interval.Mult1 = mult1; //MULT1
        interval.Mult2 = mult2; //MULT2
    }
}

public class Interval
{
    public string MeterID { get; set; }
    public DateTime UTCDateTime { get; set; }
    public float Value { get; set; }
    public DateTime LocalDateTime { get; set; }
    public string ServiceID { get; set; }
    public string Account { get; set; }
    public string Rate { get; set; }
    public int Mult1 { get; set; }
    public int Mult2 { get; set; }
}

public class Meters
    {
        public string MeterID { get; set; }
        public string Locserv { get; set; }
        public DateTime StartDate { get; set; }
        public DateTime FinalDate { get; set; }
        public int Mult1 { get; set; }
        public int Mult2 { get; set; }

    }
rt4zxlrg

rt4zxlrg1#

您必须了解使用此linq select可以做什么:

var result = from m in meterList
             where m.MeterID.Equals(interval.MeterID)
             where m.StartDate < (interval.UTCDateTime.ToLocalTime())
             where m.FinalDate > (interval.UTCDateTime.ToLocalTime())
             select m;

正如我之前所说的,result.Count()将检查meterList中的所有项。(每个都有三个where检查),这要做1400万次。meterList中每个项的合计要检查308,000,000,000次。在那个linq查询中也有三个where,为什么不直接使用&&呢?我不太了解linq查询的内部结构,但是如果没有在内部进行优化,它看起来会创建三个状态机来处理查询。
我会考虑优化meterList。在1400万次循环之前,我会将其转换为Dictionary<MeterId, List<MeterItem>>。这样,您几乎可以立即获得该MeterId的项目。同时,要检查StartDate/EndDate的列表也会减少。
如果MeterIdmeterListinterval_list中的交集明显小于完整列表,您可以过滤列表,使其仅包含将在结果中产生命中的MeterId。但我不认为这与上述想法相比会产生如此大的差异。
另外,如果Count()发现多条记录,它不应该继续计数。这可能会产生很大的差异,这取决于数据的外观。
但如果不了解数据的更多情况,这些想法可能都帮不上什么忙。

jrcvhitl

jrcvhitl2#

LINQ/Entity Framework在批量操作方面很差。你最好使用一个空的SQL查询来做这件事。
根据现有代码推测,它可能如下所示

UPDATE il
SET
-- alternatively use SELECT
    ServiceID = m.Locserv,
    Value = CASE WHEN i.Mult1 > 1
        THEN (i.Value / i.Mult1) * m.Mult1
        ELSE i.Value
        END
    Mult1 = m.Mult1,
    Mult2 = m.Mult2
FROM interval_list i
CROSS APPLY (
    SELECT
      Mult1 = MIN(m.Mult1),
      Mult2 = MIN(m.Mult2),
      Locserv = MIN(m.Locserv)
    FROM meterList m
    WHERE m.MeterID = i.MeterID
      AND m.StartDate < GETDATE()
      AND m.FinalDate > GETDATE()
    HAVING COUNT(*) = 1
) m;

相关问题