使用子查询高效获取核心数据

Posted

技术标签:

【中文标题】使用子查询高效获取核心数据【英文标题】:Efficient CoreData fetches using subqueries 【发布时间】:2013-10-01 23:17:21 【问题描述】:

我遇到了 ios Core Data 性能问题。

假设我们有 2 个类:“Class_A”和“Class_B”。他们都有自己的id,并且彼此之间是一对一的关系。

现在让我们假设我正在从网络上下载允许我创建这些类的数据(数据包含 A 类和 B 类的 id,以及关于它们的关系的信息)。例如:

“会有 id=1 的 Class_A 实例” “会有 id=2 的 Class_A 实例” “会有 id=3 的 Class_A 实例” “会有 id=10 的 Class_B 实例” “会有 id=11 的 Class_B 实例” “会有 id=12 的 Class_B 实例” "id=1 的 Class_A 将与 id = 12 的 Class_B 连接" “id=2 的 Class_A 将与 id = 11 的 Class_B 连接” “id=3 的 Class_A 将与 id = 10 的 Class_B 连接”

因为所有这些信息都可以按随机顺序获取(例如,X 和 Y 类之间的连接信息可以在 X 和 Y 类的存在信息之前下载),所以我使用了另一种实体:关系。

关系包含 2 个字段:class_A_id 和 class_b_id

每次收到关于 ClassA 和 ClassB 之间关系的数据时,我都会创建具有相应属性值的关系实体实例。

每隔一段时间,我都会遍历“关系”实体的所有实例,并尝试像这样创建适当的关系:

    获取“关系”实体的所有实例 根据存储在 Relationsip 中的“class_A_id”和“class_B_id”ID,为每个获取的关系获取 ClassA 和 ClassB 的实例 如果 ClassA 和 ClassB 的实例都存在,则在它们之间创建关系。 从 CoreData 中删除实例关系

在实现这个算法之后,我发现它在使用 Core Data 中相当少量的对象时效果很好。 问题是我存储了数千个“关系”实体(首先下载有关它们的信息),而有关“ClassA”和“ClassB”存在的信息的下载频率较低。

结果是,每次我尝试使用“关系”实体创建关系时,我都会获取数千个包含不存在的类 ID 的对象!

所以我对这个问题的解决方案是增强所提出算法的第一步:

不要获取 CoreData 中的所有关系,而是仅获取那些包含系统中存在的类的 id 的关系。

在 SQL 中,它可能看起来像这样:

SELECT * from 'Relationship' where
    (SELECT * from 'ClassA' where id == class_A_id).count == 1
  AND
    (SELECT * from 'ClassB' where id == class_B_id).count == 1

我的问题是 - 如何在 CoreData 中实现这样的查询?在那里使用子查询?是 - 怎么样? :)

【问题讨论】:

不这样做,您是否可以丢弃您的关系实体,而只是创建 ClassA 和 ClassB 的实例并通过它们的关系将它们链接在一起?您可以向这些实体添加一个属性以指示它是占位符而不是完全填充的实体? 你也可以模仿你的SQL方式:当你收到class X和class Y时,你可以检查Relationship。当您收到关系数据时,您可以检查 Class_A 和 Class_B。但 AE 的建议可能效果更好。 好吧,你可能已经猜到了,我的真实应用中的模型有点复杂——类“ClassA”和“ClassB”比“id”有更多的属性,并且需要填充数据这些属性不会出现在仅包含它们之间关系的 Web 响应中。由于我的应用程序的结构,我无法创建这些分类的“假”实体(仅填充“id”字段) - 只有在获得有关它们的完整信息时,我才需要创建它们。我已经简化了我的问题,以便更清楚地提出我的问题 【参考方案1】:

如果我理解正确,如果你不想过多修改你的模型,你有两种选择:

第一个选项:修改请求流程以仅询问您已经拥有的实体的关系,如果您没有那么多类型 A、B 的实体,这可以轻松完成。否则实施某种“增量”,这将避免拥有数千个您不需要的关系(除非您出于其他目的需要它)。 第二个选项:当您下载项目时,我想它是一个后台进程,在这种情况下,我会立即在那里进行检查,而不是时不时批处理。比如你正在下载关系,检查你是否已经有A或B,并将关系表标记为完整或不完整(可能添加两个属性aExists bExists)。实体 A 进入后,立即将关系中的所有实体标记为 aExists,B 进入也是如此,这是一个正常的获取请求,其中 class_A_id 存在。然后批处理可以轻松扫描并仅获取标记为完成的那些实体,并创建关系。您必须实现一些逻辑,但在我看来,事情会变得更快。

新的关系是:

Relationships 
  class_A_id,
  class_B_id,
  classAexists BOOL,
  classBexists BOOL,
  batchRelationshipCreated BOOL,

好吧,无论如何你都可以实现这两个选项:-)

【讨论】:

以上是关于使用子查询高效获取核心数据的主要内容,如果未能解决你的问题,请参考以下文章

如何高效地从多个表中查询子记录?

使用来自 SELECT 子查询的值的 UPDATE 查询,高效

核心数据子查询:没有这样的列

使用“相关”子查询进行高效连接

基于日期时间值的相同表上的高效sql子查询

mssql sql高效关联子查询的update 批量更新