我有一个适用于 iPad 的现成企业(非 AppStore)遗留 iOS 应用程序,我需要对其进行重构(它是由另一位开发人员编写的,我目前工作的前任)。
此应用程序通过 JSON 从具有 MSSQL 数据库的服务器获取其数据。数据库模式有大约 30 个表,最大容量是:Client、City、Agency,每个表都有大约 10.000 条记录,预计未来会进一步增长。收到 JSON 后(每个表有一个 JSON 请求和响应对) - 它被映射到 CoreData - 该过程还包括将相应的 CoreData 实体(客户、城市、代理机构等)彼此粘合在一起,即在 CoreData 层上设置这些实体之间的关系。
该项目的CoreData fetch-part(或read-part)本身已经过大量优化 - 我猜它使用CoreData几乎所有可能的性能和内存调整,这就是为什么应用程序的UI层非常快速和响应,所以我认为其工作完全令人满意和充分。
问题是CoreData层的准备过程,即服务器到客户端的同步过程:耗时太长。考虑 30 个网络请求产生 30 个 JSON 包(“包”我的意思是“一个表 - 一个 JSON”),然后映射到 30 个 CoreData 实体,然后将它们粘合在一起(在它们之间设置适当的 CoreData 关系)。当我第一次看到这一切是如何在这个项目中完成的(太慢了)时,我脑海中浮现的第一个想法是:
“第一次执行完整的同步(应用程序的第一次启动时间) -在一个存档文件(类似于数据库转储)中执行整个数据库数据的获取,然后以某种方式将其作为一个整体导入核心数据土地”。
但后来我意识到,即使这种单一文件转储的传输是可能的,CoreData 仍然需要我对相应的 CoreData 实体进行粘合以设置它们之间的适当关系,因此很难想象我可以如果我依赖这个方案,性能上会受益。
另外,我的同事建议我将 SQLite 视为 Core Data 的完整替代品,但不幸的是我没有使用它的经验,这就是为什么我完全无法预见如此严肃的设计决策的所有后果(即使有同步过程很慢,我的应用程序确实可以工作,尤其是它的 UI 性能现在非常好)。关于 SQLite,我唯一能想象到的是,与 Core Data 相比,它不会促使我在客户端粘合一些额外的关系,因为 SQLite 有其良好的旧外键系统,不是吗?
以下是问题(受访者,请不要在回答时混淆这些观点——我对所有这些观点都感到困惑):
有没有人有像我上面描述的那样采取“首次大量导入整个数据库”方法的经验?如果他们是否利用 JSON<->CoreData 对,我将非常感谢了解任何解决方案。
Core Data 是否有一些全局导入机制,可以允许大量创建相应的 30 个表模式(可能使用上述“30 包 JSON”以外的某些特定源),而无需为 30 个实体设置对应关系?
如果2)不可能,是否有可能加快同步过程?这里我指的是我的应用程序使用的当前 JSON<->CoreData 方案的改进。
迁移到 SQLite:我应该考虑这种迁移吗?我会从中得到什么好处?复制->传输->客户端准备的整个过程会是什么样子呢?
CoreData 和 SQLite 的其他替代品——它们可能是什么或看起来像什么?
对于我所描述的情况,您可能还有其他想法或愿景吗?
更新 1
尽管 Mundi 写的答案很好(一个大的 JSON,对于使用 SQLite “否”),如果对我所描述的问题有任何其他见解,我仍然很感兴趣。
更新 2
我确实尝试使用我的俄语英语以最好的方式来描述我的情况,希望我的问题对所有阅读它的人来说都非常清楚。通过第二次更新,我将尝试为其提供更多指南,以使我的问题更加清晰。
请考虑两个二分法:
- 我可以/应该使用什么作为 iOS 客户端上的数据层 - CoreData vs SQLite?
- 我可以/应该使用什么作为传输层 - JSON(如答案中所建议的一次性单个 JSON,甚至可能压缩)或一些 DB-itself-dumps(如果它甚至可能的话,当然 - 请注意我是在我的问题中也问这个)。
我认为由这两个二分法的交集形成的“扇区”很明显,从第一个中选择 CoreData,从第二个中选择 JSON 是 iOS 开发世界中最广泛使用的默认值,我的应用程序也使用它从这个问题。
话虽如此,我声称我会很高兴看到有关 CoreData-JSON 对的任何答案以及考虑使用任何其他“部门”的答案(选择 SQLite 及其某种转储方法怎么样,为什么不呢?)
另外,需要注意的是,我不想仅仅放弃当前选项以获取其他一些替代方案,我只想让解决方案在其使用的同步和 UI 阶段都快速运行。因此,欢迎提供有关改进当前方案的答案以及建议其他方案的答案!
现在,请查看以下更新 #3,它提供了我当前 CoreData-JSON 情况的更多详细信息:
更新 3
正如我所说,目前我的应用程序收到 30 包 JSON - 整张桌子一包。让我们以大容量表为例:Client、Agency、City。
它是核心数据,所以如果一个client
记录有非空agency_id
字段,我需要创建一个新的核心数据实体类Agency (NSManagedObject subclass)
并用这个记录的JSON数据填充它,这就是为什么我需要已经有这个类代理的相应核心数据实体Agency (NSManagedObject's subclass)
,最后我需要做一些事情client.agency = agency;
,然后调用[currentManagedObjectContext save:&error]
. 以这种方式完成后,稍后我可以要求获取此客户端并要求其.agency
属性找到相应的实体。我希望当我这样做时我是完全清醒的。
现在想象一下这种模式应用于以下情况:
我刚刚收到以下 3 个单独的 JSON 包:10000 个客户和 4000 个城市和 6000 个代理(客户有一个城市,城市有很多客户;客户有代理,代理有很多客户,代理有一个城市,城市有很多代理)。
现在我想在核心数据级别设置以下关系:我希望我的客户实体client
连接到相应的城市和相应的机构。
当前在项目中的实现做了非常丑陋的事情:
由于依赖顺序如下: City -> Agency -> Client 即首先需要烘焙 City,应用程序开始为 City 创建实体并将它们持久化到 Core Data。
然后它处理机构的 JSON:它遍历每个 JSON 记录 - 对于每个机构,它创建一个新实体
agency
,并通过city_id
它的 获取相应的实体city
并使用agency.city = city
. 在完成整个机构 JSON 数组的迭代后,保存当前的托管对象上下文(实际上 -[managedObjectContext save:] 会执行多次,每次处理 500 条记录后)。在这一步,很明显,为 6000 个代理机构中的每一个的每个客户获取 4000 个城市中的一个对整个同步过程有巨大的性能影响。然后,最后处理客户端的 JSON:和前 2 阶段一样,遍历整个 10000 元素的 JSON 数组,并逐个执行相应机构和 ZOMG 城市的 fetch,这会影响相同的整体性能就像之前的第 2 阶段一样。
这一切都非常糟糕。
我可以在这里看到的唯一性能优化是,第一阶段可以留下一个带有城市 ID 的大字典(我的意思是 NSNumber 的真实 ID)和错误的城市实体作为值),因此可以防止以下丑陋的查找过程第 2 阶段,然后使用类似的缓存技巧在第 3 阶段做同样的事情,但问题是在刚刚描述的所有 30 个表之间有更多的关系 [Client-City, Client-Agency, Agency-City] 所以涉及缓存所有实体的最终过程很可能会影响 iPad 设备为我的应用程序保留的资源。
更新 4
给未来受访者的信息:我已尽力使这个答案详细且格式正确,我真的希望您能用冗长的答案来回答。如果您的回答能够真正解决此处讨论的问题的复杂性,并补充我为使我的问题尽可能清晰和笼统而做出的努力,那就太好了。谢谢。
更新 5
相关主题:客户端 (iOS) 上的 Core Data 缓存来自服务器的数据 Strategy,尝试使用 RestKit 发出 POST 请求并将响应映射到 Core Data。
更新 6
即使不再可能打开新的赏金并且有接受的答案,我仍然很高兴看到任何其他答案,其中包含有关本主题解决的问题的其他信息。提前致谢。