Reputation: 89
Trying to solve performance issues with SwiftData.
When I add one-to-many relationship to my model, performance drastically degrades.
Code below. To reproduce just add more than 5-6 thousands of models.
@Model
class EnterChild {
@Relationship
var enterModel: EnterModel?
init(enterModel: EnterModel? = nil) {
self.enterModel = enterModel
}
}
@Model
class EnterModel {
@Relationship(inverse: \EnterChild.enterModel)
var enterChildren = [EnterChild]()
var name: String
init(name: String) {
self.name = name
}
}
struct EnterView: View {
@Environment(\.modelContext)
private var mc
@State
var models: [EnterModel] = []
var body: some View {
List {
Text("\(models.count)")
.onTapGesture {
for i in 1...5000 {
let em = EnterModel(name: "Model number \(i)")
mc.insert(em)
try? mc.save()
}
}
}
.onAppear {
var descriptor = FetchDescriptor<EnterModel>()
// descriptor.propertiesToFetch = [\.name]
// descriptor.relationshipKeyPathsForPrefetching = [\.enterChildren]
if let result = try? mc.fetch(descriptor) {
models = result
}
}
}
}
Also in my log I see a lot of queries like this:
CoreData: sql: SELECT 0, t0.Z_PK FROM ZENTERCHILD t0 WHERE t0.ZENTERMODEL = ?
CoreData: annotation: sql connection fetch time: 0.0000s
CoreData: annotation: total fetch execution time: 0.0000s for 0 rows.
CoreData: annotation: to-many relationship fault "enterChildren" for objectID 0x847373e672d56572 <x-coredata://AA52F4C2-B209-45D9-9F04-FE9291706CCD/EnterModel/p6000> fulfilled from database. Got 0 rows
I believe SwiftData makes query for every EnterModel record.
Using descriptor.relationshipKeyPathsForPrefetching = [.enterChildren] helps reducing amount of queries, but performance remains poor. Also, if in my real app I have relationships in my children model, which starts producing queries when I use prefetching.
Upvotes: 1
Views: 179
Reputation: 11
I have the same issue. I have two classes one-to-many (parent -> [child]) relationship. If I put the SwiftData relationship (explicit or inferred), even adding the records, the performance is degraded too much (Talking about 100k+ records). My only option was remove the relationship and add manually foreign keys to child entities, and modifying the queries to look for Ids.
What helped too was:
How do you insert an array of objects into the SwiftData ModelContext
Upvotes: 1
Reputation: 89
Finally I decided to add pagination and performance issues had gone away. Still don't know why selecting several thousands is slow, it seems strange for me.
Upvotes: 0
Reputation: 30746
Try fetchIdentifiers
or fetchCount
https://developer.apple.com/documentation/SwiftData/ModelContext
Upvotes: 0