確認したいこと
- Swift で Realm を使っているが、どれだけ早いの?
- Realm で対応できないクエリを書きたいけど、どうするべきなの?
例えば Object にList<String>
を持たせているときは単純には filter できない。この場合 Array.filter() で検索するか、Results.filter()で検索するかどちらが良いか。class Person: Object { @objc dynamic var id: String? @objc dynamic var name: String? @objc dynamic var grade: Int? let classList = List<String>() // 特定のクラスをもつ Person の検索はできない }
結果
- Realm の方が速いので Realm を使おう
- 複雑な Query でも頑張って Realm で対応しよう
実験
準備
データの登録
Personオブジェクトを8000個くらい用意。
classListに入る授業名は20個程度用意し、一人複数個持つように設定。
こんな感じで。
Person(value: [
"id": "000001",
"name": "Alice",
"grade": 3,
"classList": ["Math", "English", "Japanese", "Chinese"],
])
検索したい授業名を用意
今回は時間を測るだけなので、全てを列挙したものを作成。
let classNameList = [
"English",
"Japanese",
"Chinese",
:
"Psychology",
]
それぞれを履修している生徒の人数を取得していく。
時間を測る関数
時間を測る関数を作成する。
クロージャを渡せるようにしておく。
func evalFunc(f: () -> Void) {
let start = DispatchTime.now()
f()
let end = DispatchTime.now()
let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds
let timeInterval = Double(nanoTime) / 1_000_000_000
print("elapsed time: \(timeInterval) seconds")
}
実行
Array.filter() を使う
単純にArrayにしてfilterをかけてやる。
contains()が使える。
evalFunc {
let realm = try! Realm()
let allPersons = Array(realm.objects(Person.self)) // 一旦 Array にする
for className in classNameList {
let persons = allPersons.filter({ p in p.classList.contains(className) })
}
}
// Time to evaluate function: 1.733439875 seconds
Results.filter() を使う
単純には実行できないのでString結合したフィールドを作成しておく。
class Person: Object {
@objc dynamic var id: String?
@objc dynamic var name: String?
@objc dynamic var grade: Int?
let classList = List<String>()
@objc dynamic var classListStr: [String] = [] // 追加
}
classList を join して classListStr に入れる。
person.classListStr = person.classList.joined(separator: "|") // 適当な文字で区切っておく
// こんな感じになる
// "Math|English|Japanese|Chinese"
いよいよ評価。
evalFunc {
let realm = try! Realm()
for className in classNameList {
let persons = realm.objects(Person.self).filter("classListStr CONTAINS '\(className)'")
}
}
// Time to evaluate function: 0.024232959 seconds
速い。
まとめ
Array: 1.733439875 seconds
Realm: 0.024232959 seconds
私の環境下、問題設定では Realm の方が断然速くなった。
ちょっと頑張ってでも、Realm で検索可能なフィールドを作る方が良さそう。