Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.xcuserdatad

137 changes: 137 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Perf Test for CoreData, SwiftData and Realm

Comparing the performance characteristics of Realm, SwiftData and CoreData.

Code accompanying the Emerge Tools blog article:
[SwiftData vs Realm: Performance Comparison](https://www.emergetools.com/blog/posts/swiftdata-vs-realm-performance-comparison)
by Jacob Bartlett.

Original repositoy: https://github.com/jacobsapps/RealmVsSwiftData

Michal Tsai's coverage: https://mjtsai.com/blog/2024/06/24/swiftdata-vs-realm-performance-comparison/


## Issues

- UUID init is superfluous in all but Realm? CD/SQLite can do the primary keys.
- Delete all users could be just a database table drop/recreate?


## Links

- [SwiftData vs Realm: Performance Comparison](https://www.emergetools.com/blog/posts/swiftdata-vs-realm-performance-comparison)
- [RealmVsSwiftData](https://github.com/jacobsapps/RealmVsSwiftData) original repository
- Storages
- [Realm](https://www.mongodb.com/docs/atlas/device-sdks/) by MongoDB
- [SwiftData](https://developer.apple.com/documentation/swiftdata) by Apple
- [Core Data](https://developer.apple.com/documentation/coredata/) by Apple
- [ManagedModels](https://github.com/Data-swift/ManagedModels)) by [Helge Heß](https://helgehess.eu/),
access Core Data in a SwiftData like fashion
- [Lighter.swift](https://github.com/Lighter-swift) by [Helge Heß](https://helgehess.eu/), direct SQLite access


## Numbers

M2 Mac Mini Pro, Xcode 16 b2, running in simulator

- SwiftData and CoreData can grow big, e.g. SwiftData >6GB of RAM for the 1m
user inserts, or CoreData >2GB of RAM for the "complex" 100k run.

### Simple User Objects

```
💽 ===============
💽 SwiftData: 1.000.000 Simple Objects
===============
💽 User instantiation: 6.5249
💽 Create users: 9913.5297 (2.75h)
207 users named Jane
💽 Fetch users named `Jane` in age order: 1.7491
207 users renamed to `Wendy`
💽 Rename users named `Jane` to `Wendy`: 133.1398
💽 DB file size: 101.51 MB
💽 Delete all users: 17.4455

💽 ===============
💽 Realm: 1.000.000 Simple Objects
===============
💽 User instantiation: 1.6368
💽 Create users: 4.8281
199 users named Jane
💽 Fetch users named `Jane` in age order: 0.0110
199 users renamed to `Wendy`
💽 Rename users named `Jane` to `Wendy`: 0.0101
💽 DB file size: 75.64 MB
💽 Delete all users: 0.0120

💽 ===============
💽 CoreData: 1.000.000 Simple Objects
===============
💽 User instantiation: 1.9408
💽 Create users: 4270.8671 (~1:15h)
205 users named `Jane`
💽 Fetch users named `Jane` in age order: 0.8116
205 users named `Jane` being renamed to `Wendy`
205 users renamed to `Wendy`
💽 Rename users named `Jane` to `Wendy`: 1.5780
💽 DB file size: 72.57 MB
💽 Delete all users: 70.3943

💽 ===============
💽 Lighter: 1.000.000 Simple Objects
===============
💽 User instantiation: 0.4484
💽 Create users: 7.8463
💽 Create index: 0.3628
218 users named Jane
💽 Fetch users named `Jane` in age order: 0.0016
218 users renamed to `Wendy`
💽 Rename users named `Jane` to `Wendy`: 0.0100
💽 DB file size: 79.65 MB
💽 Delete all users: 10.0460
```

### Complex Student/School/Grade Objects

```
💽 ===============
💽 CoreData: 1.000 Complex Objects
===============
💽 Student instantiation: 0.0220
Created 1000 students.
💽 Create students: 0.2168
43 students with an A* in Physics
💽 Read students with A* in Physics: 0.0051
De-graded 0 students.
💽 Fail the cheating Maths students: 0.0006
💽 DB file size: 0.05 MB
💽 Delete all students: 0.0063
💽 ===============
💽 CoreData: 10.000 Complex Objects
===============
CoreData: debug: PostSaveMaintenance: incremental_vacuum with freelist_count - 120 and pages_to_free 107
💽 Student instantiation: 0.1986
Created 10000 students.
💽 Create students: 16.1095
385 students with an A* in Physics
💽 Read students with A* in Physics: 0.1160
De-graded 0 students.
💽 Fail the cheating Maths students: 0.0038
💽 DB file size: 4.73 MB
💽 Delete all students: 0.0857
💽 ===============
💽 CoreData: 100.000 Complex Objects
===============
💽 Student instantiation: 1.8890
Created 100000 students.
💽 Create students: 1631.6497 ~28min
4032 students with an A* in Physics
💽 Read students with A* in Physics: 9.4956
De-graded 0 students.
💽 Fail the cheating Maths students: 0.0299
💽 DB file size: 48.77 MB
CoreData: debug: PostSaveMaintenance: fileSize 49415312 greater than prune threshold
CoreData: debug: PostSaveMaintenance: incremental_vacuum with freelist_count - 12457 and pages_to_free 12429
CoreData: annotation: PostSaveMaintenance: wal_checkpoint(TRUNCATE)
💽 Delete all students: 29.9509
```
72 changes: 72 additions & 0 deletions RealmVsSwiftData.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@
16A41EDB2BE3A7DE00C62A21 /* SwiftStudentsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16A41ED82BE3A7DE00C62A21 /* SwiftStudentsTests.swift */; };
16A41EDC2BE3A7DE00C62A21 /* RealmStudentsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16A41ED92BE3A7DE00C62A21 /* RealmStudentsTests.swift */; };
16A41EDD2BE3A7DE00C62A21 /* SwiftUsersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16A41EDA2BE3A7DE00C62A21 /* SwiftUsersTests.swift */; };
E82FB4D82C2C50D7000E0FCC /* CoreStudentsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82FB4D62C2C50D7000E0FCC /* CoreStudentsTests.swift */; };
E82FB4D92C2C50D7000E0FCC /* CoreUsersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82FB4D72C2C50D7000E0FCC /* CoreUsersTests.swift */; };
E82FB4E22C2C50E7000E0FCC /* CoreUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82FB4DD2C2C50E7000E0FCC /* CoreUser.swift */; };
E82FB4E32C2C50E7000E0FCC /* CoreStudentDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82FB4DB2C2C50E7000E0FCC /* CoreStudentDB.swift */; };
E82FB4E42C2C50E7000E0FCC /* CoreDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82FB4E02C2C50E7000E0FCC /* CoreDatabase.swift */; };
E82FB4E52C2C50E7000E0FCC /* CoreStudent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82FB4DA2C2C50E7000E0FCC /* CoreStudent.swift */; };
E82FB4E62C2C50E7000E0FCC /* CoreUserDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82FB4DE2C2C50E7000E0FCC /* CoreUserDB.swift */; };
E82FB4EA2C2C537B000E0FCC /* ManagedModels in Frameworks */ = {isa = PBXBuildFile; productRef = E82FB4E92C2C537B000E0FCC /* ManagedModels */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand Down Expand Up @@ -62,13 +70,22 @@
16A41ED82BE3A7DE00C62A21 /* SwiftStudentsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftStudentsTests.swift; sourceTree = "<group>"; };
16A41ED92BE3A7DE00C62A21 /* RealmStudentsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RealmStudentsTests.swift; sourceTree = "<group>"; };
16A41EDA2BE3A7DE00C62A21 /* SwiftUsersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftUsersTests.swift; sourceTree = "<group>"; };
E82FB4D62C2C50D7000E0FCC /* CoreStudentsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreStudentsTests.swift; sourceTree = "<group>"; };
E82FB4D72C2C50D7000E0FCC /* CoreUsersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreUsersTests.swift; sourceTree = "<group>"; };
E82FB4DA2C2C50E7000E0FCC /* CoreStudent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreStudent.swift; sourceTree = "<group>"; };
E82FB4DB2C2C50E7000E0FCC /* CoreStudentDB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreStudentDB.swift; sourceTree = "<group>"; };
E82FB4DD2C2C50E7000E0FCC /* CoreUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreUser.swift; sourceTree = "<group>"; };
E82FB4DE2C2C50E7000E0FCC /* CoreUserDB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreUserDB.swift; sourceTree = "<group>"; };
E82FB4E02C2C50E7000E0FCC /* CoreDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDatabase.swift; sourceTree = "<group>"; };
E82FB4E72C2C5155000E0FCC /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
167973C42BC804B9002FE4D9 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
E82FB4EA2C2C537B000E0FCC /* ManagedModels in Frameworks */,
167973DC2BC8057C002FE4D9 /* RealmSwift in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -115,9 +132,11 @@
167973BE2BC804B9002FE4D9 = {
isa = PBXGroup;
children = (
E82FB4E72C2C5155000E0FCC /* README.md */,
167973C92BC804B9002FE4D9 /* RealmVsSwiftData */,
167973C82BC804B9002FE4D9 /* Products */,
);
indentWidth = 4;
sourceTree = "<group>";
};
167973C82BC804B9002FE4D9 /* Products */ = {
Expand Down Expand Up @@ -156,6 +175,7 @@
167973E22BC805D6002FE4D9 /* Database.swift */,
167973E12BC805B7002FE4D9 /* SwiftData */,
167973E02BC805B3002FE4D9 /* Realm */,
E82FB4E12C2C50E7000E0FCC /* CoreData */,
);
path = DB;
sourceTree = "<group>";
Expand Down Expand Up @@ -188,6 +208,8 @@
16A41ED92BE3A7DE00C62A21 /* RealmStudentsTests.swift */,
16A41ED82BE3A7DE00C62A21 /* SwiftStudentsTests.swift */,
16A41EDA2BE3A7DE00C62A21 /* SwiftUsersTests.swift */,
E82FB4D62C2C50D7000E0FCC /* CoreStudentsTests.swift */,
E82FB4D72C2C50D7000E0FCC /* CoreUsersTests.swift */,
);
path = PerformanceTesting;
sourceTree = "<group>";
Expand All @@ -212,6 +234,34 @@
path = Resources;
sourceTree = "<group>";
};
E82FB4DC2C2C50E7000E0FCC /* Students */ = {
isa = PBXGroup;
children = (
E82FB4DA2C2C50E7000E0FCC /* CoreStudent.swift */,
E82FB4DB2C2C50E7000E0FCC /* CoreStudentDB.swift */,
);
path = Students;
sourceTree = "<group>";
};
E82FB4DF2C2C50E7000E0FCC /* Users */ = {
isa = PBXGroup;
children = (
E82FB4DD2C2C50E7000E0FCC /* CoreUser.swift */,
E82FB4DE2C2C50E7000E0FCC /* CoreUserDB.swift */,
);
path = Users;
sourceTree = "<group>";
};
E82FB4E12C2C50E7000E0FCC /* CoreData */ = {
isa = PBXGroup;
children = (
E82FB4DC2C2C50E7000E0FCC /* Students */,
E82FB4DF2C2C50E7000E0FCC /* Users */,
E82FB4E02C2C50E7000E0FCC /* CoreDatabase.swift */,
);
path = CoreData;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand All @@ -230,6 +280,7 @@
name = RealmVsSwiftData;
packageProductDependencies = (
167973DB2BC8057C002FE4D9 /* RealmSwift */,
E82FB4E92C2C537B000E0FCC /* ManagedModels */,
);
productName = RealmVsSwiftData;
productReference = 167973C72BC804B9002FE4D9 /* RealmVsSwiftData.app */;
Expand Down Expand Up @@ -261,6 +312,7 @@
mainGroup = 167973BE2BC804B9002FE4D9;
packageReferences = (
167973DA2BC8057B002FE4D9 /* XCRemoteSwiftPackageReference "realm-swift" */,
E82FB4E82C2C537B000E0FCC /* XCRemoteSwiftPackageReference "ManagedModels" */,
);
productRefGroup = 167973C82BC804B9002FE4D9 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -297,6 +349,11 @@
167973E92BC805E0002FE4D9 /* SwiftUser.swift in Sources */,
16A41ED52BE38F6600C62A21 /* SchoolLocations.swift in Sources */,
167973E72BC805E0002FE4D9 /* SwiftDatabase.swift in Sources */,
E82FB4E22C2C50E7000E0FCC /* CoreUser.swift in Sources */,
E82FB4E32C2C50E7000E0FCC /* CoreStudentDB.swift in Sources */,
E82FB4E42C2C50E7000E0FCC /* CoreDatabase.swift in Sources */,
E82FB4E52C2C50E7000E0FCC /* CoreStudent.swift in Sources */,
E82FB4E62C2C50E7000E0FCC /* CoreUserDB.swift in Sources */,
16A41ED32BE38F3A00C62A21 /* SchoolNames.swift in Sources */,
16168E342BE0C36300874AC2 /* SwiftStudent.swift in Sources */,
167973FB2BC8063F002FE4D9 /* FirstNames.swift in Sources */,
Expand All @@ -309,6 +366,8 @@
16168E362BE0C36A00874AC2 /* RealmStudent.swift in Sources */,
16A41EDD2BE3A7DE00C62A21 /* SwiftUsersTests.swift in Sources */,
167973EF2BC805E4002FE4D9 /* RealmUserDB.swift in Sources */,
E82FB4D82C2C50D7000E0FCC /* CoreStudentsTests.swift in Sources */,
E82FB4D92C2C50D7000E0FCC /* CoreUsersTests.swift in Sources */,
16A41ED72BE3A7C400C62A21 /* RealmUsersTests.swift in Sources */,
167973ED2BC805E4002FE4D9 /* RelamDatabase.swift in Sources */,
);
Expand Down Expand Up @@ -527,6 +586,14 @@
kind = branch;
};
};
E82FB4E82C2C537B000E0FCC /* XCRemoteSwiftPackageReference "ManagedModels" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/Data-swift/ManagedModels.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.8.12;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
Expand All @@ -535,6 +602,11 @@
package = 167973DA2BC8057B002FE4D9 /* XCRemoteSwiftPackageReference "realm-swift" */;
productName = RealmSwift;
};
E82FB4E92C2C537B000E0FCC /* ManagedModels */ = {
isa = XCSwiftPackageProductDependency;
package = E82FB4E82C2C537B000E0FCC /* XCRemoteSwiftPackageReference "ManagedModels" */;
productName = ManagedModels;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 167973BF2BC804B9002FE4D9 /* Project object */;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
Expand Down
Loading