LoginSignup
3
4

More than 5 years have passed since last update.

CoreData の relationshipKeyPathsForPrefetching

Last updated at Posted at 2016-09-27

CoreDataでSQL発行回数を減らしたいなと思い、relationshipKeyPathsForPrefetching というっぽいプロパティの存在に気づくも、SQL発行回数の削減には役立たなかったのでメモだけ残して帰ります。

挙動を観察

Book と Author モデルを例に、relationshipKeyPathsForPrefetching の有無による挙動を観察する。

swift|ViewController.swift
import UIKit
import CoreData

class ViewController: UIViewController {

    let container = (UIApplication.shared.delegate as! AppDelegate).persistentContainer

    @IBAction func selectEntities(_ sender: AnyObject) {
        container.performBackgroundTask { (context) in
            print("select all")
            let req = NSFetchRequest<Book>(entityName: "Book");

            //XXX
            req.relationshipKeyPathsForPrefetching = ["author"]

            let books = try! context.fetch(req)
            books.forEach({ (book) in
                print(book)
                print(book.author?.name)
            })
        }
    }

    @IBAction func createEntieies() {
        container.performBackgroundTask { (context) in
            let author = Author(context: context)
            author.name = "kentaro"
            let book = Book(context: context)
            book.title = "test title"
            book.author = author
            try! context.save()
            print("created")
        }
    }

    @IBAction func clearEntities() {
        container.performBackgroundTask { (context) in
            let books = try! context.fetch(Book.fetchRequest()) as [Book]
            books.forEach({ (book) in
                context.delete(book)
            })
            let authors = try! context.fetch(Author.fetchRequest()) as [Author]
            authors.forEach({ (author) in
                context.delete(author)
            })
            try! context.save()
            print("cleared")
        }
    }
}

プリフェッチなしの場合は、Bookを取得する段階ではZBOOKテーブルに対するselectが走るのみで、book.author.name にアクセスした瞬間にZAUTHORテーブルにselectが走る。

プリフェッチなし

CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZTITLE, t0.ZAUTHOR FROM ZBOOK t0 
CoreData: annotation: sql connection fetch time: 0.0002s
CoreData: annotation: total fetch execution time: 0.0006s for 1 rows.

<coredata_sample.Book: 0x6180000a86a0> (entity: Book; id: 0xd000000000100000 <x-coredata://3D6FA5D4-7E41-414F-AF67-B30C5480B9BC/Book/p4> ; data: <fault>)

CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZNAME, t0.ZBOOK FROM ZAUTHOR t0 WHERE  t0.Z_PK = ? 
CoreData: annotation: sql connection fetch time: 0.0001s
CoreData: annotation: total fetch execution time: 0.0002s for 1 rows.
CoreData: annotation: fault fulfilled from database for : 0xd000000000100002 <x-coredata://3D6FA5D4-7E41-414F-AF67-B30C5480B9BC/Author/p4>

Optional("kentaro")

プリフェッチありの場合は、Bookを取得する段階で、ZBOOKテーブルとZAUTHORテーブルに対してselectが一気に走り、book.author.name にアクセスしたときにはクエリは発行されない。

プリフェッチあり

CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZTITLE, t0.ZAUTHOR FROM ZBOOK t0 
CoreData: annotation: sql connection fetch time: 0.0001s
CoreData: annotation: Bound intarray _Z_intarray0
CoreData: annotation: Bound intarray values.
CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZNAME, t0.ZBOOK FROM ZAUTHOR t0 WHERE  t0.ZBOOK IN (SELECT * FROM _Z_intarray0)  
CoreData: annotation: sql connection fetch time: 0.0004s
CoreData: annotation: total fetch execution time: 0.0005s for 1 rows.
CoreData: annotation: Prefetching with key 'author'.  Got 1 rows.
CoreData: annotation: total fetch execution time: 0.0018s for 1 rows.

<coredata_sample.Book: 0x6080000b7640> (entity: Book; id: 0xd000000000100000 <x-coredata://3D6FA5D4-7E41-414F-AF67-B30C5480B9BC/Book/p4> ; data: <fault>)
Optional("kentaro")

てっきりZBOOKとZAUTHORをjoinしたクエリを一発だけ発行してくれるのかなーと思ったけど、そんなことはなかった。ということで、クエリ回数の削減にはならない。

クエリ回数の削減はIN句で頑張るのがいいかなー。

Realmとかだとどうなんでしょう。

別件

久しぶりに生のCoreData触ったけど
- NSPersistentContainerが導入された(iOS10から)
- NSFetchRequestがgenericsに対応してる

あたりの変更が入ってて、MagicalRecordとかそろそろ卒業してもいいかなーと思った。

3
4
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
3
4