核心数据量大

Posted

技术标签:

【中文标题】核心数据量大【英文标题】:Core data large quantity 【发布时间】:2016-09-27 14:35:33 【问题描述】:

每次应用程序启动时,我都会从 Web 服务中检索 25000 条记录。 在初始化阶段,我想将所有这些项目保存到核心数据中。 此操作的时间约为 20 分钟。 是否可以更快地将所有项目保存到核心数据中? 使用 sqlite 工具将它们保存到 sqlite 数据库中然后实例化核心数据是一个好主意吗?

编辑:

保存到核心数据需要 20 分钟。

func storeDevices(_ dataStack: DATAStack,value: [JSON]) -> Bool

    dataStack.performInNewBackgroundContext  backgroundContext in
    let entityDevices = NSEntityDescription.entity(forEntityName: "Devices", in: backgroundContext)

    for item in value
    
        if !item["event_id"].stringValue.isEmpty
        
            let id = item["id"].stringValue
            let predicate = NSPredicate(format: "%K == %@", "id", id)
            let typesFetchRequest = NSFetchRequest<Devices>(entityName: "Devices")
            typesFetchRequest.predicate = predicate
            do 
                let fetchedTypesResults = try backgroundContext.fetch(typesFetchRequest) as! [Devices]
                if (fetchedTypesResults.count > 0)
                
                    let typeUpdate = fetchedTypesResults[0]
                    switch item["is_Deleted"].stringValue
                    
                    case "true":
                        typeUpdate.setValue(true, forKey: "deletedStatus")
                    case "false":
                        typeUpdate.setValue(false, forKey: "deletedStatus")
                    default:
                        typeUpdate.setValue(false, forKey: "deletedStatus")
                    

                    if let intVersion = Int(item["last_modified"].stringValue) 
                        typeUpdate.setValue(intVersion, forKey: "lastModified")
                     else 
                        typeUpdate.setValue(NSNumber(value: 0 as Int32), forKey: "lastModified")
                    

                    typeUpdate.setValue(NSNumber(value: 0 as Int32), forKey: "syncStatus")

                    typeUpdate.setValue(item["deviceUUID"].stringValue, forKey: "deviceUUID")
                    typeUpdate.setValue(item["deviceLocation"].stringValue, forKey: "deviceLocation")

                    let event_id = item["event_id"].stringValue
                    if !event_id.isEmpty
                    

                        let predicate = NSPredicate(format: "%K == %@", "id", event_id)
                        let typesFetchRequest = NSFetchRequest<Events>(entityName: "Events")
                        typesFetchRequest.predicate = predicate

                        do 
                            let fetchedTypesResults = try backgroundContext.fetch(typesFetchRequest) as! [Events]
                            if (fetchedTypesResults.count > 0)
                            
                                typeUpdate.setValue(fetchedTypesResults[0], forKey: "event")
                            
                            else
                            
                                continue
                            
                         catch 
                            let saveError = error as NSError
                            print("Failed to fetch events in Devices: \(saveError)")
                        
                    


                    continue
                

             catch 
                fatalError("Failed to fetch devices: \(error)")
            

            let deviceNewElement = Devices(entity: entityDevices!, insertInto: backgroundContext)
            deviceNewElement.id = id
            switch item["is_Deleted"].stringValue
            
            case "true":
                deviceNewElement.deletedStatus = true
            case "false":
                deviceNewElement.deletedStatus = false
            default:
                deviceNewElement.deletedStatus = false
            

            if let intVersion = Int(item["last_modified"].stringValue) 
                deviceNewElement.lastModified = intVersion as NSNumber?
             else 
                deviceNewElement.lastModified = NSNumber(value: 0 as Int32)
            

            deviceNewElement.deviceUUID = item["deviceUUID"].stringValue
            deviceNewElement.deviceLocation = item["deviceLocation"].stringValue

            let event_id = item["event_id"].stringValue
            if !event_id.isEmpty
            
                let predicate = NSPredicate(format: "%K == %@", "id", event_id)
                let typesFetchRequest = NSFetchRequest<Events>(entityName: "Events")
                typesFetchRequest.predicate = predicate

                do 
                    let fetchedTypesResults = try backgroundContext.fetch(typesFetchRequest) as! [Events]
                    if (fetchedTypesResults.count > 0)
                    
                        deviceNewElement.event = fetchedTypesResults[0]
                    
                    else
                    
                        continue
                    
                 catch 
                    let saveError = error as NSError
                    print("Failed to fetch events in Devices: \(saveError)")
                
            

            deviceNewElement.syncStatus = NSNumber(value: 0 as Int32)
        
       
        try! backgroundContext.save()
    
    return true


【问题讨论】:

两点操作需要20分钟,就是20分钟检索和存储数据,如果是这样的话,20分钟的哪一部分被占用只是检索数据。第二点是我相信 core-data 使用 sqlite 进行存储,所以我看不出最初使用 sqlite 数据库然后转换为 core-data 会如何节省您的时间。但是存储为 sqlite db 然后使用它而不是 core-data 可能会给您带来优势 “将它们保存到 sqlite 数据库中”是什么意思?什么sqlite数据库?在许多情况下,Core Data 是在 sqlite 之上实现的,但您不应该直接修改该数据库。它不是公共架构。 Core Data 是一个持久的对象图。它不是数据库(它没有“行”和“列”,即使它可以存储在可以存储的东西中)。如果您想使用数据库(如 sqlite),那很好,但不要尝试像使用原始 SQL 一样使用 Core Data。 Core Data Instrument 为您提供了哪些关于您的时间花在哪里的信息? 是的,应该可以更快地做到这一点。但是你需要描述(或者更好地,展示)你的代码在做什么。没有看到它是不可能帮助优化代码的。 【参考方案1】:

您需要优化使用 CoreData 的方式。

处理您的数据并找出需要触及的 ManagedObjects,在循环之外批量预取这些数据。注意可能还需要预取的任何关系。您不希望故障不断触发。

现在进行所有更改。最后保存一次。

如果内存压力很大,将数据分成几千块并按上述方式处理它们。使用@autoreleasepool。

【讨论】:

【参考方案2】:

是的,最好使用sqlite3 函数进行批量插入。因为在核心数据中不可能这样做。

【讨论】:

【参考方案3】:

保存 25000 条记录不应该需要 20 分钟,您是否尝试过启动多个线程和上下文并将它们保存到 coredata。请分享您的示例代码,我们可以提供帮助。下面是一个示例元代码,可以减少保存到磁盘的时间

loop and create threads for every 1000 records using dispatch_async etc
on each thread, call dispatch_enter, create a thread context taken from parent root context
loop the 1000 records of this thread and upsert (update or insert) them into the context
save the context and call dispatch_leave
Finally know that everything is saved in dispatch_notify

【讨论】:

以上是关于核心数据量大的主要内容,如果未能解决你的问题,请参考以下文章

数据量大,列比较多,请问数据库表该如何设计?

mysql 数据量大 加了索引 聚类查询还是慢

MySQL主从配置中,忽略数据量大的表

NPOI导出EXCEL数据量大,分多个sheet显示数据

redis 数据量大,异常停机导致全量同步问题

oracle 数据量大时如何快速查找需要数据