2010年5月30日日曜日

Core Data のパフォーマンスをちょっとだけ調べてみた

ちょっと仕事で触ってみて分かった範囲のことを書きます。断りがない限り、 iPhone 3GS で Wifi 接続環境下においてテストしました。

■キャッシュ無し vs キャッシュ有り

executeFetchRequest:error: メソッドを用いて、 Entityのプロパティで一件だけ絞り込んで返すようなクエリは大変遅いということが分かりました。Indexを付けて実行してもほとんど速くなりません。どうやらそもそもバックエンドに使っているSqliteが大変遅い、特にコネクションを生成したり破棄したりするのが遅い感じがするので、ループで一件ずつ取得するなどのときはたくさんのSQLが実行されないようにする必要があります。 objectWithID: メソッドは試していないのでちょっと不明です。

回避策として、アプリが起動したタイミングで当該エンティティの全オブジェクトをあらかじめ取ってきて、 NSMutableDictionary にでも突っ込んでおく。次回以降のフェッチはその NSMutableDictionary から行う、と言うようにすると凄く速くなりました。

実測値は以下の通り。
pre loading time というのが自前のNSDictionaryキャッシュの事前生成、parseResponseBodyというのがXMLの解析で、この中に大量のCore DataオブジェクトをDBから引っ張ってくる処理が含まれています。
//////////////////
プリキャッシュなし
//////////////////

2010-05-25 12:11:37.254  FetchAllModelA parseResponseBody time : -1.214856
2010-05-25 12:11:39.674  FetchAllModelB parseResponseBody time : -2.416063
2010-05-25 12:11:41.097  FetchAllModelC parseResponseBody time : -1.384185

//////////////////
プリキャッシュあり
//////////////////

2010-05-25 14:12:14.788  pre loading time : -0.039540
2010-05-25 14:12:17.518  FetchAllModelA parseResponseBody completed. time : -0.836754
2010-05-25 14:12:20.719  FetchAllModelB parseResponseBody completed. time : -1.312910
2010-05-25 14:12:19.169  FetchAllModelC parseResponseBody completed. time : -0.902832
ほんの0.03秒のプリキャッシュ処理のおかげで、XML解析が最大で1秒以上短縮できています。とにかくCore DataがSQLを飛ばさないように調整すると効果があるみたいです。


■DB書き込み速度

NSManagedObject の生成はメモリ上 (NSManagedObjectContext) で行われるためなかなか高速なのですが、それを save するのがとにかく iPhone 3G で顕著に遅く、 300件程度のデータを保存するのに5秒以上かかってアプリが正常終了できないという事態が発生しました。リレーション張りすぎたかなーと思います>< iPhone 3GS なら2秒3秒程度で間違いなく完了するので特に問題になっていません。対策としては暇なときに逐一DBにsaveするか、どうでもいいデータはiPhone 3Gでは保存しないとか、一時エンティティにするとか。

iPhone の NSURLRequest で gzip 使ってみた

http://stackoverflow.com/questions/2682483/nsurlconnection-nsurlrequest-gzip-support

こちらに記載があるとおり、 Cocoa の NSURLConnection はgzip圧縮されたコンテンツを自動的に解凍して扱ってくれるみたいです。gzipでリクエストを受け取るには、以下のように NSURLRequest のヘッダに値を追加します。
[urlReq setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];
これだけで後はすべて自動的にやってくれます。もちろんサーバー側がきちんとgzip圧縮して返すように設定されていなければなりません。


■パフォーマンスを試してみる

サーバーと通信を行い、レスポンスとして1000行程度のXMLを取得して解析するアプリで実験してみました。iPhone 3GS, Wifi回線を使用。

圧縮無しの時の結果はこちら。
API①
16:11:58.822 開始
16:12:04.126 レスポンス受信
16:12:04.184 データ受信
16:12:05.322 パース完了

API②
16:11:58.838 開始
16:12:04.118 レスポンス受信
16:12:04.433 データ受信
16:12:07.276 パース完了

API③
16:11:58.847 開始
16:12:04.718 レスポンス受信
16:12:05.822 データ受信
16:12:08.299 パース完了
圧縮ありの時の結果はこちら。
API①
16:03:43.056 開始
16:03:46.349 レスポンス受信
16:03:46.414 データ受信
16:03:48.473 パース完了

API②
16:03:43.080 開始
16:03:46.326 レスポンス受信
16:03:46.671 データ受信
16:03:49.905 パース完了

API③
16:03:43.088 開始
16:03:46.308 レスポンス受信
16:03:46.371 データ受信
16:03:47.532 パース完了
一回しか試していないのでムラはありそうですが、通信自体は確実に早くなっている気がします。3Gで計測すればさらに顕著な違いになると思うのでおすすめです。

iPad 3G を Xcode につないだら対応していない OS と言われてしまった件



昨日の勉強会でさっそく買ったばかりのiPad 3GをXcodeにつないでみたら、ご覧のように対応していないOSであるとエラーが出てしまいました。

再度iPhone Developer CenterからSDKをダウンロードしてインストールし直したら問題なく動作するようになりました。おそらく単にSDKが古かっただけなのだとは思いますが、一応。