使用 UUID 的现代核心数据性能

ada*_*mek 3 iphone uuid core-data ios swift

我有一个核心数据应用程序:

  • 549 个具有 myJournals 关系的帐户实体(一对多)
  • 24000 个具有 myJournals 关系的账本实体(一对多)
  • 57000 个具有 myAccount 和 myLedger(一对一)反向关系的日记帐实体

每个实体都有一个带有从在线数据库导入的 UUID 字符串的 uuidKey 字符串属性。

我正在尝试在 iPhone 5S 上运行该应用程序。插入对象相对较快,但查找和链接关系的时间比预期的要长。

let debugTime = NSDate()
let thisRequest = NSFetchRequest(entityName: "Ledgers")
let keyLeft = NSExpression(forKeyPath: "uuidKey")
let keyRight = NSExpression(forConstantValue: ledgerKey)
let keyPredicate = NSComparisonPredicate(leftExpression: keyLeft, rightExpression: keyRight, modifier: NSComparisonPredicateModifier.DirectPredicateModifier, type: NSPredicateOperatorType.EqualToPredicateOperatorType, options: NSComparisonPredicateOptions.allZeros)
thisRequest.predicate = keyPredicate
thisRequest.fetchBatchSize = 1
thisRequest.fetchLimit = 1
println("DEBUG COMMENT: \(debugTime.timeIntervalSinceNow) time to create thisRequest.")
var keyError: NSError? = nil
if let keyArray = self.managedObjectContext!.executeFetchRequest(thisRequest, error: &keyError) {
    if keyArray.isEmpty {
        myLedger = nil
    } else {
        if let thisLedger = keyArray[0] as? Ledgers {
            println("DEBUG COMMENT: \(debugTime.timeIntervalSinceNow) time to find thisLedger.")
            myLedger = thisLedger
        } else {
            myLedger = nil
        }
    }
}
println("DEBUG COMMENT: \(debugTime.timeIntervalSinceNow) time to link myLedger.")
Run Code Online (Sandbox Code Playgroud)

我得到这样的日志时间:

DEBUG COMMENT: -9.20295715332031e-05 time to create thisRequest.
DEBUG COMMENT: -0.174275994300842 time to find thisLedger.
DEBUG COMMENT: -0.174659013748169 time to link myLedger.
DEBUG COMMENT: -0.00464397668838501 time to find and link myAccount.
Run Code Online (Sandbox Code Playgroud)

创建 NSFetchRequest 的时间为 0.092 毫秒就可以了。174 毫秒找到 Ledger?当有 24k 分类帐时,在索引的 UUID 字符串上?!?当我需要将其链接到 57k 期刊时?

更快总是更好。当有 549 个帐户时,4 毫秒找到链接 myAccount 有点令人失望但可以接受。对于 Ledger 搜索,我预计大约需要 25-50 毫秒,而不是 174 毫秒!

我在它自己的核心数据存储和上​​下文中运行它:

    // Initialize the persistent store coordinator for the sync session.
    let url = appDel.applicationDocumentsDirectory.URLByAppendingPathComponent("FoodyCoreModel.sqlite")
    self.syncStore = NSPersistentStoreCoordinator(managedObjectModel: appDel.managedObjectModel)
    var error: NSError? = nil
    var failureReason = "There was an error creating or loading the application's saved data."
    let storeOptions: [NSObject: AnyObject] = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
    self.syncStore.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: storeOptions, error: &error)

    // Initialize the managed object contextfor the sync session
    self.syncContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType)
    self.syncContext.persistentStoreCoordinator = self.syncStore
    let nmp = NSMergePolicy(mergeType: NSMergePolicyType.MergeByPropertyStoreTrumpMergePolicyType)
    self.syncContext.mergePolicy = nmp
Run Code Online (Sandbox Code Playgroud)

iPhone 5S 的性能是否合理?我在这里阅读了许多 Core Data 性能问题,但其中许多都是几年前的。我希望 iOS 8 和更新的设备会更快。我不是要进行 MATCHES 或 CONTAINS 搜索,只是在索引文本字段上进行 EQUALS 搜索!

我已经阅读了 核心数据性能指南。是否有我遗漏的东西,或者我只是对移动设备期望过高?

Tom*_*ton 5

代码中最有可能的减速是您一次获取Ledger一个实例,并且您说其中有 24,000 个。无论如何,这将是一个主要的瓶颈。获取是一个相对昂贵的操作,无论您是否在谓词中使用字符串 ID,因此您的代码将花费大部分时间进行获取。

您应该分批提取,而不是一次提取一个。将 50 或 100 个左右的uuidKey值收集到一个数组中,并使用"uuidKey in %@"与数组一样的谓词格式作为替换变量。处理该批次,并重复直到完成。

有关如何高效导入数据的更多详细信息,请参阅 Apple 的“Efficiently Importing Data”指南,尤其是名为“Implementing Find-or-Create Efficiently”的部分。

println顺便说一句,像这样使用是衡量性能的一种非常糟糕的方式。使用仪器。它将以更少的开销为您提供更多细节,并且不会使您的代码混乱,并将帮助您准确确定瓶颈所在。