1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Realmのfilter() vs Arrayのfilter() 処理速度比較

Posted at

確認したいこと

  • Swift で Realm を使っているが、どれだけ早いの?
  • Realm で対応できないクエリを書きたいけど、どうするべきなの?
    例えば Object に List<String> を持たせているときは単純には filter できない。
    class Person: Object {
        @objc dynamic var id: String?
        @objc dynamic var name: String?
        @objc dynamic var grade: Int?
        let classList = List<String>() // 特定のクラスをもつ Person の検索はできない
    }
    
    この場合 Array.filter() で検索するか、Results.filter()で検索するかどちらが良いか。

結果

  • 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 で検索可能なフィールドを作る方が良さそう。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?