All of the whereas, my ideas on Batch Replace Operations are that they’re much sooner than updating by way of NSManagedObject. Nevertheless, as per my testing on a 2000 rows manufacturing knowledge set, utilizing Batch Replace Operations is 2 to three occasions slower than updating by way of NSManagedObject.
My replace sample is, there are round 2000 rows. I’m updating every of their column named “order”, with completely different worth for every row.
The objective is straightforward, we wish to make the present row’s order
worth, is bigger than earlier row’s order
worth.
This is my code snippet. nsPlainNote
is an NSManagedObject
Replace by way of Batch Replace Operation (gradual)
personal func _updateOrdersIfPossible2(context: NSManagedObjectContext, updateOrders: [UpdateOrder]) {
let depend = updateOrders.depend
if depend < 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..<depend {
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. Quick!
prevOrder = updateOrder.order
}
} // for index in 1..<depend
if !updatedObjectIDs.isEmpty {
let modifications = [NSUpdatedObjectsKey : updatedObjectIDs]
CoreDataStack.INSTANCE.mergeChanges(modifications)
}
}
personal 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 consequence: NSManagedObjectID? = nil
do {
let batchUpdateRequest = NSBatchUpdateRequest(entityName: entityName)
batchUpdateRequest.predicate = NSPredicate(format: "self = %@", objectID)
batchUpdateRequest.propertiesToUpdate = propertiesToUpdate
batchUpdateRequest.resultType = .updatedObjectIDsResultType
let batchUpdateResult = strive context.execute(batchUpdateRequest) as? NSBatchUpdateResult
if let managedObjectIDs = batchUpdateResult?.consequence as? [NSManagedObjectID] {
consequence = managedObjectIDs.first
}
} catch {
context.rollback()
error_log(error)
}
return consequence
}
As per my benchmark, most time are spent within the loop of calling _updateWithoutMerge
.
Replace by way of NSManagedObject (Sooner)
personal func _updateOrdersIfPossible(context: NSManagedObjectContext, updateOrders: [UpdateOrder]) {
let depend = updateOrders.depend
if depend < 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..<depend {
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. Quick!
prevOrder = updateOrder.order
}
} // for index in 1..<depend
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 = strive fetchRequest.execute()
if let _nsPlainNote = nsPlainNotes.first {
nsPlainNote = _nsPlainNote
}
} catch {
error_log(error)
}
}
return nsPlainNote
}
I believed utilizing Batch Replace Operation must be sooner than utilizing NSManagedObject?
Am I having flawed expectation, or there may be an error in my implementation?
Thanks.