如何通过join来加速这个LINQ查询?

3

我有两个对象模型的集合,我需要逐个属性进行比较以检测它们是否相等。

ObservableCollection<LayerModel> SourceDrawingLayers

...以及:

ObservableCollection<LayerModel> TargetDrawingLayers

我已经得到了一些很好的关于创建非等值连接LINQ查询的建议,并且在我的应用程序中取得了很好的效果,但现在我想加速它:

var onOffQuery = from target in TargetDrawingLayers
                 from source in SourceDrawingLayers
                 where target.Name == source.Name && target.OnOff != source.OnOff
                 select target;

我的理解是,我将查询乘以源图中的项目数 * 目标图中的项目数 * 我填入 TargetDrawingLayers 的目标图数。

我想使用 Join来加快此操作,但在 !=部分遇到了问题。

我尝试着做了一些调整:

var newQuery = from source in SourceDrawingLayers
    join target in TargetDrawingLayers
    on target.name
    where target.OnOff != source.OnOff
    select target;

但是我对语法感到困惑。有人能为我指点迷津吗?

此外,这是否会显著提高性能?


1
如果target.OnOff != source.OnOff,那么对于每一行不匹配的数据,都会进行一次乘法操作,这是一个很大的数据集。 - Train
1
是的,这就是折磨我的东西。在我们的网络环境中,每个图纸构建这个比较需要大约30秒的时间。老实说,这还不错,将节省大量QA的时间,但如果可能的话,我想缩短这个时间。一些集合将包含200张或更多的图纸,因此显然这是我们要尽量减少的事情。 - Kefka
1
缓存是一个选项吗?或者你可以每隔1分钟(只是一个示例时间)单独运行查询,存储数据并获取最新的数据集? - Train
为什么不在创建层时进行这样的链接呢?甚至可以在单独的线程上订阅可观察集合的事件并在后台进程中添加它们。通过放置一个 public object Tag { get; set; } 或者直接命名一个类,就可以完成链接,需要时只需引用 Tag。不再需要 30 秒的处理时间,而是实时访问。 - ΩmegaMan
2个回答

5

on target.name替换为on source.name equals target.name

var newQuery = from source in SourceDrawingLayers
         join target in TargetDrawingLayers
         on source.name equals target.name
         where target.OnOff != source.OnOff
         select target;

在Linq-to-objects中,连接将在连接属性上创建一个Lookup<TKey,TElement>,这将在匹配sourcetarget时导致性能提高。假设这会产生一个受限制的结果集,它应该会显著改进原始代码。当然,如果它导致许多匹配,因为name在两侧都包含非常有限的值范围,那么性能就不会受到太大影响。

请参考下面juharr提供的可枚举.cs链接源代码。


1
谢谢,我会尝试一下。你认为这会有意义的性能提升吗? - Kefka
2
具体来说,这将在名称上创建哈希,以帮助匹配两个集合中的值(因此名称的类型也会影响此操作,我假设它是一个字符串,这将完全正常)。然后,它将根据OnOff不同来过滤这些匹配项。 - juharr
4
请告诉我更多关于问题中没有涉及语法的信息,@Çöđěxěŕ说:“但是我在语法方面遇到了困难。有人能帮我找到正确的方向吗?” - Matti Price
@Çöđěxěŕ,很高兴我们都认为这是问题的一部分,并且这个答案提供了一个答案!我相信你现在会取消你的反对票。 - Matti Price
2
@Igor,你可以查看源代码并了解它创建了一个“Lookup”,以便使用https://referencesource.microsoft.com/#system.core/system/linq/Enumerable.cs,aecc63c3873b5c1a。 - juharr
显示剩余9条评论

0
也许你需要根据属性 NameOnOff 的组合进行连接。这个组合可以表示为一个 ValueTuple
var newQuery = from source in SourceDrawingLayers
               join target in TargetDrawingLayers
               on (source.Name, source.OnOff) equals (target.Name, !target.OnOff)
               select target;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接