swift CoreData:为什么使用Batch Update Operation更新单列比使用NSManagedObject慢得多?

s6fujrry  于 12个月前  发布在  Swift
关注(0)|答案(1)|浏览(184)

一直以来,我认为批更新操作比通过NSManagedObject更新要快得多。但是,根据我对2000行生产数据集的测试,使用批更新操作比通过NSManagedObject更新慢2到3倍。
我的更新模式是,大约有2000行。我正在更新他们的每一列名为“顺序”,每一行有不同的值。
目标很简单,我们要使当前行的order值,大于前一行的order值。
下面是我的代码片段。nsPlainNote是一个NSManagedObject

通过批更新操作更新(缓慢)

private func _updateOrdersIfPossible2(context: NSManagedObjectContext, updateOrders: [UpdateOrder]) {
    let count = updateOrders.count
    
    if count < 2 {
        return
    }
    
    var prevOrder = updateOrders[0].order
    
    var updatedObjectIDs = [NSManagedObjectID]()
    
    if !Utils.isValidOrder(prevOrder) {
        prevOrder = prevOrder - 1
        
        precondition(Utils.isValidOrder(prevOrder))
        
        // Time-consuming operation.
        if let updatedObjectID = _updateWithoutMerge(context: context, objectID: updateOrders[0].objectID, propertiesToUpdate: [
            "order": prevOrder
        ]) {
            updatedObjectIDs.append(updatedObjectID)
        }
    }
    
    for index in 1..<count {
        precondition(Utils.isValidOrder(prevOrder))
        
        let updateOrder = updateOrders[index]
        
        if !Utils.isValidOrder(updateOrder.order) || updateOrder.order <= prevOrder {
            var newOrder = prevOrder + 1
            
            if !Utils.isValidOrder(newOrder) {
                newOrder = newOrder + 1
            }
            
            precondition(newOrder > prevOrder)
            
            prevOrder = newOrder
            
            precondition(Utils.isValidOrder(newOrder))
            
            // Time-consuming operation.
            if let updatedObjectID = _updateWithoutMerge(context: context, objectID: updateOrder.objectID, propertiesToUpdate: [
                "order": newOrder
            ]) {
                updatedObjectIDs.append(updatedObjectID)
            }
        } else {
            // Skip from updating. Fast!
            
            prevOrder = updateOrder.order
        }
    }   // for index in 1..<count
    
    if !updatedObjectIDs.isEmpty {
        let changes = [NSUpdatedObjectsKey : updatedObjectIDs]
        CoreDataStack.INSTANCE.mergeChanges(changes)
    }
}

private func _updateWithoutMerge(context: NSManagedObjectContext, objectID: NSManagedObjectID, propertiesToUpdate: [AnyHashable : Any]) -> NSManagedObjectID? {
    return RepositoryUtils._updateWithoutMerge(
        context: context,
        entityName: "NSPlainNote",
        objectID: objectID,
        propertiesToUpdate: propertiesToUpdate
    )
}

static func _updateWithoutMerge(context: NSManagedObjectContext, entityName: String, objectID: NSManagedObjectID, propertiesToUpdate: [AnyHashable : Any]) -> NSManagedObjectID? {
    var result: NSManagedObjectID? = nil
    
    do {
        let batchUpdateRequest = NSBatchUpdateRequest(entityName: entityName)
        batchUpdateRequest.predicate = NSPredicate(format: "self = %@", objectID)
        batchUpdateRequest.propertiesToUpdate = propertiesToUpdate
        batchUpdateRequest.resultType = .updatedObjectIDsResultType
        
        let batchUpdateResult = try context.execute(batchUpdateRequest) as? NSBatchUpdateResult
        
        if let managedObjectIDs = batchUpdateResult?.result as? [NSManagedObjectID] {
            result = managedObjectIDs.first
        }
    } catch {
        context.rollback()
        
        error_log(error)
    }
    
    return result
}

字符串
根据我的基准测试,大多数时间都花在调用_updateWithoutMerge的循环中。

通过NSManagedObject更新(更快)

private func _updateOrdersIfPossible(context: NSManagedObjectContext, updateOrders: [UpdateOrder]) {
    let count = updateOrders.count
    if count < 2 {
        return
    }
    var prevOrder = updateOrders[0].order
    var updatedObjectIDs = [NSManagedObjectID]()
    if !Utils.isValidOrder(prevOrder) {
        prevOrder = prevOrder - 1
        precondition(Utils.isValidOrder(prevOrder))
        // Time-consuming operation.
        if let nsPlainNote = NSPlainNoteRepository.getNSPlainNote(context: context, objectID: updateOrders[0].objectID, propertiesToFetch: ["order"]) {
            nsPlainNote.order = prevOrder
        }
    }
    for index in 1..<count {
        precondition(Utils.isValidOrder(prevOrder))
        let updateOrder = updateOrders[index]
        if !Utils.isValidOrder(updateOrder.order) || updateOrder.order <= prevOrder {
            var newOrder = prevOrder + 1
            if !Utils.isValidOrder(newOrder) {
                newOrder = newOrder + 1
            }
            precondition(newOrder > prevOrder)
            prevOrder = newOrder
            precondition(Utils.isValidOrder(newOrder))
            // Time-consuming operation.
            if let nsPlainNote = NSPlainNoteRepository.getNSPlainNote(context: context, objectID: updateOrder.objectID, propertiesToFetch: ["order"]) {
                nsPlainNote.order = newOrder
            }
        } else {
            // Skip from updating. Fast!
            prevOrder = updateOrder.order
        }
    }   // for index in 1..<count
    RepositoryUtils.saveContextIfPossible(context)
}
static func getNSPlainNote(context: NSManagedObjectContext, objectID: NSManagedObjectID, propertiesToFetch: [Any]?) -> NSPlainNote? {
    var nsPlainNote: NSPlainNote? = nil
    context.performAndWait {
        let fetchRequest = NSPlainNote.fetchRequest()
        fetchRequest.predicate = NSPredicate(format: "self = %@", objectID)
        fetchRequest.propertiesToFetch = propertiesToFetch
        fetchRequest.fetchLimit = 1
        do {
            let nsPlainNotes = try fetchRequest.execute()
            if let _nsPlainNote = nsPlainNotes.first {
                nsPlainNote = _nsPlainNote
            }
        } catch {
            error_log(error)
        }
    }
    return nsPlainNote
}


我认为使用批更新操作应该比使用NSManagedObject快?
我的期望是错误的,还是我的实现中有错误?
谢谢.

92vpleto

92vpleto1#

我看不出你是如何在代码中真正使用批量更新的。你为每个objectID创建了一个新的NSBatchUpdateRequest,并为每个objectID创建了一个 predicate ,这违背了批量更新的目的。
此外,批量更新的目的是将所有符合条件的对象的字段更改为相同的新值。如果您希望逐个提升每个相应的订单,这意味着它必须加载每个对象的值,增加它,然后再次保存它。NSBatchUpdateRequest不是用于此目的的正确工具。

相关问题