一直以来,我认为批更新操作比通过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快?
我的期望是错误的,还是我的实现中有错误?
谢谢.
1条答案
按热度按时间92vpleto1#
我看不出你是如何在代码中真正使用批量更新的。你为每个objectID创建了一个新的NSBatchUpdateRequest,并为每个objectID创建了一个 predicate ,这违背了批量更新的目的。
此外,批量更新的目的是将所有符合条件的对象的字段更改为相同的新值。如果您希望逐个提升每个相应的订单,这意味着它必须加载每个对象的值,增加它,然后再次保存它。NSBatchUpdateRequest不是用于此目的的正确工具。