Linq连接按时间戳排序的三个表

Linq join three tables orderd by Timstamp

我有三个table:

Sites:
Id
Timezone (string)
SiteName

Vehicles:
Id
SiteId
Name

Positions:
Id
TimestampLocal (DateTimeOffset)
VehicleId
Data1
Data2
...
Data50

一辆车有多个位置。位置 table 非常大(100 多条记录) 我需要获取每辆车的最后位置(通过时间戳,因为它们可以发送旧数据)及其时区,以便我可以根据时区进行进一步的数据处理。像 {PositionId, VehicleId, Timezone, Data1}

我试过:

var result = 
from ot in entities.Positions
join v in entities.Vehicles on ot.VehicleId equals v.Id
join s in entities.Sites on v.SiteId equals s.Id
group ot by ot.VehicleId into grp
select grp.OrderByDescending(g=>g.TimestampLocal).FirstOrDefault();

然后我用以下方法处理数据:

foreach (var rr in result){... update Data1 field ...    }

这获取了最后的值,但它确实带来了位置中的所有字段(大量数据)并且没有时区。此外,foreach 部分非常 CPU 密集(因为它可能会带来数据),因为它会在几秒钟内达到 100% CPU。

这如何在 Linq 中完成...并且对于数据库及其传输来说是轻量级的?

检查以下内容,它与您所做的相同,但结果包含 Sites Timezone 预计的列,它预计在 Join 本身

var result =
S.Join(V,s1=>s1.Id,v1=>v1.SiteId,(s1,v1)=>new {v1.Id,s1.Timezone})
 .Join(P,v1=>v1.Id,p1=>p1.VehicleId,(v1,p1)=>new {p1,v1.Timezone})
 .GroupBy(g=>g.p1.VehicleId)
 .Select(x=>x.OrderByDescending(y=>y.p1.TimestampLocal).FirstOrDefault())
 .Select(y=>new {y.p1,y.Timezone});

下面是与您提出的问题相关的要点:

  1. 要减少提取的列数,因为您可能不想要所有的位置列,需要完成以下操作:

    • 这一行 - Join(P,v1=>v1.Id,p1=>p1.VehicleId,(v1,p1)=>new {p1,v1.Timezone}) 投影字段,这是加入的结果,类似于:

      new {p1.Id,p1.TimestampLocal,p1.VehicleId,p1.Data1,p1...,v1.Timezone}
      

      将仅提供投影字段,但随后 GroupBy 将更改为 GroupBy(g=>g.VehicleId)

  2. 相同的其他选项是更改 GroupBy 投影,如下所示而不是 Join 语句

    GroupBy(g=>g.p1.VehicleId, 
    g=>new {g.p1.Id,g.p1.TimestampLocal,g.p1.VehicleId,g.p1.Data1,g.p1...,g.Timezone})
    
  3. 现在剩余的部分过程 CPU 密集且使用 100% CPU,可以进行以下优化:

    • 每个 foreach 循环迭代是否执行网络 Update 调用,那么它必然会使其成为一个网络密集型过程,因此速度较慢,最好是在内存中进行所有必要的更改然后一次性更新数据库,如果您有数百万条记录
    • ,这仍然会很密集

即使对百万条记录做同样的事情也永远不是一个好主意,因为那将是一个相当大的网络并且 CPU 密集,从而使其变慢,您的选择是:

  • 将内存分成更小的组件,因为我不确定是否有人需要一次性更新百万条记录,所以让它成为多个更小的更新,这些更新由用户,但对系统资源的负担要小得多。

  • 在内存中引入较小的数据集,使用参数在数据库级别进行过滤,并将修改所需的数据传递到内存中进行更新。

  • 使用如上Linq所示的projection,只引入需要的列,这样会减少整体数据内存占用,势必会有影响。

  • 如果逻辑是各种更新是互斥的,那么在线程安全结构中使用Parallel API进行,这样可以确保高效快速地利用CPU在所有核心中,因此速度更快,尽管它会飙升至 100% CPU 但会达到非并行执行的一小部分

除此之外,请提供具体细节以帮助您了解更多细节,这些是基本建议,没有解决此类优化问题的黄金法则