私はリファクタリングする必要がある iPad 用の準備が整ったエンタープライズ (AppStore 以外の) レガシー iOS アプリケーションを持っています (それは別の開発者、私の現在の仕事の前任者によって書かれました)。
このアプリケーションは、MSSQL データベースを持つサーバーから JSON 経由でデータをフェッチします。データベース スキーマには約 30 のテーブルがあり、最も容量が大きいのは、それぞれ約 10.000 レコードを持つクライアント、市、代理店であり、将来的にはさらなる成長が予想されます。JSON が受信された後 (テーブルごとに 1 つの JSON 要求と応答のペア) - CoreData にマップされます - このプロセスには、対応する CoreData エンティティ (クライアント、都市、機関など) を互いに接着することも含まれます。 CoreData レイヤーでこれらのエンティティ間の関係を設定します。
それ自体、プロジェクトの CoreData fetch-part (または read-part) は大幅に最適化されています。CoreData が持つほとんどすべての可能なパフォーマンスとメモリ調整を使用していると思います。そのため、アプリケーションの UI レイヤーは非常に高速で応答性が高いため、その仕事は完全に満足のいくものであり、適切であると考えてください。
問題は、CoreData レイヤーの準備のプロセス、つまりサーバーからクライアントへの同期プロセスです。時間がかかりすぎます。30 個の JSON パック (「パック」とは「1 つのテーブル - 1 つの JSON」を意味します) になる 30 個のネットワーク リクエストを考えてみましょう。これらは 30 個の CoreData エンティティにマップされ、それらは互いに接着されます (適切な CoreData 関係がそれらの間に設定されます)。このプロジェクトでこれがどのように行われるか (遅すぎる) を最初に見たとき、頭に浮かんだ最初のアイデアは次のとおりでした。
「初めて完全な同期が実行されます (アプリの初回起動時) -たとえば、1 つのアーカイブ ファイル (データベース ダンプのようなもの) でデータベース データ全体のフェッチを実行し、それを全体としてコア データにインポートします。土地"。
しかし、そのような 1 ファイル ダンプの送信が可能であったとしても、CoreData では、対応する CoreData エンティティを接着して、それらの間に適切な関係を設定する必要があるため、それができるとは想像しがたいことに気付きました。このスキームに頼れば、パフォーマンスが向上します。
また、私の同僚は SQLite を Core Data の完全な代替手段として検討するよう提案してくれましたが、残念ながら私は SQLite を使用した経験がありません。同期プロセスが非常に遅いですが、私のアプリは動作します。特に UI パフォーマンスは非常に優れています)。SQLite について私が想像できる唯一のことは、Core Data とは対照的に、SQLite には古き良き外部キー システムがあるため、クライアント側でいくつかの追加の関係を接着する必要がないということですよね?
質問は次のとおりです (回答者の皆様、回答の際にこれらの点を混同しないでください。すべての質問について、私はあまりにも多くの混乱を抱えています)。
私が上で説明した方法で「データベース全体を初めて大量にインポートする」アプローチをとった経験のある人はいますか? JSON <-> CoreDataペアを利用するかどうかにかかわらず、解決策について知っていただければ幸いです。
Core Data には、対応する 30 個のテーブル スキーマ (上記の "30 パックの JSON" 以外の特定のソースを使用する可能性があります) を大量に作成できるグローバル インポート メカニズムがありますか?
2)が不可能な場合、同期プロセスを高速化する可能性はありますか? ここで私が意味するのは、現在の JSON<->CoreData スキームの改善で、私のアプリが使用するものです。
SQLite への移行: そのような移行を検討する必要がありますか? 私はそれから何を得ますか?では、複製→送信→クライアントの準備という全体のプロセスはどのように見えるでしょうか?
CoreData と SQLite の他の代替手段 - それらはどのようなものか、またはどのように見えるでしょうか?
私が説明した状況について、他に何か考えやビジョンはありますか?
更新 1
Mundi によって書かれた回答は良いものですが (1 つの大きな JSON、SQLite を使用する場合は「いいえ」)、私が説明した問題について他の洞察があるかどうかはまだ興味があります。
更新 2
私の質問がそれを読むすべての人にとってかなり明確になることを期待して、私は自分の状況を説明するためにできる限り最善の方法でロシア語の英語を使用しようとしました. この 2 回目の更新までに、質問をさらに明確にするためのガイドをいくつか提供しようと思います。
2 つの二分法を検討してください。
- iOS クライアントのデータ レイヤーとして何を使用できますか?
- トランスポート層として何を使用できるか/使用すべきか-JSON(回答で提案されているように一度に1つのJSON、圧縮されている可能性もあります)またはいくつかのDB自体のダンプ(もちろん可能であれば-私がいることに注意してください私の質問でもこれを尋ねています)。
これら 2 つの二分法の交差によって形成される「セクター」は、最初のものから CoreData を選択し、2 番目のものから JSON を選択することは、iOS 開発の世界で最も広く普及しているデフォルトであり、私のアプリでも使用されています。この質問から。
そうは言っても、CoreData-JSONペアに関する回答と、他の「セクター」の使用を考慮した回答を見ていただければ幸いです(SQLiteとそのダンプアプローチのいくつかを選択するのはどうですか?)
また、重要なのは、現在のオプションを他のいくつかの代替手段にドロップするだけではなく、その使用の同期フェーズと UI フェーズの両方でソリューションを高速に動作させたいということです。したがって、現在のスキームの改善に関する回答と、他のスキームを示唆する回答は大歓迎です!
さて、私の現在の CoreData-JSON 状況の詳細を提供する次の更新 #3 を参照してください。
更新 3
前述したように、現在、私のアプリは 30 パックの JSON を受け取ります。つまり、テーブル全体に対して 1 パックです。たとえば、大容量のテーブルを見てみましょう: Client、Agency、City。
これは Core Data であるため、client
レコードに空でないagency_id
フィールドがある場合、クラスの新しい Core Data エンティティを作成Agency (NSManagedObject subclass)
し、このレコードの JSON データを入力する必要があります。そのため、このクラスのエージェンシーに対応する Core Data エンティティが既に必要です。Agency (NSManagedObject's subclass)
、そして最後に、次のようなことをしてclient.agency = agency;
から呼び出す必要があります[currentManagedObjectContext save:&error]
。このようにして、後でこのクライアントにフェッチを要求し、その.agency
プロパティに対応するエンティティを見つけるように要求できます。このようにすると、完全に正気であることを願っています。
このパターンが次の状況に適用されると想像してください。
次の 3 つの個別の JSON パックを受け取りました: 10000 のクライアントと 4000 の都市と 6000 の機関 (クライアントには 1 つの都市があり、都市には多くのクライアントがあります。クライアントには代理店があり、代理店には多くのクライアントがあり、代理店には 1 つの都市があり、都市には多くの代理店があります)。
ここで、コア データ レベルで次の関係を設定したいと考えています。クライアント エンティティclient
を対応する都市と対応する機関に接続する必要があります。
プロジェクトでのこれの現在の実装は非常に醜いことをします:
依存関係の順序は次のとおりです: City -> Agency -> Client つまり City を最初にベイクする必要があるため、アプリケーションは City のエンティティの作成を開始し、それらを Core Data に永続化します。
次に、機関の JSON を処理します。すべての JSON レコードを反復処理します。すべての機関について、新しいエンティティ
agency
を作成し、その によって、city_id
対応するエンティティcity
を取得し、agency.city = city
. 機関の JSON 配列全体を反復処理した後、現在の管理オブジェクト コンテキストが保存されます (実際には、500 レコードが処理されるたびに -[managedObjectContext save:] が数回実行されます)。このステップでは、6000 の機関ごとにクライアントごとに 4000 の都市の 1 つを取得すると、同期プロセス全体のパフォーマンスに大きな影響があることは明らかです。次に、最後にクライアントの JSON を処理します。前の 2 段階と同様に、10000 要素の JSON 配列全体を反復処理し、対応する機関と ZOMG 都市のフェッチを 1 つずつ実行します。これは、全体的なパフォーマンスに影響を与えます。前のステージ2と同じように。
それはすべて非常に悪いです。
ここで確認できる唯一のパフォーマンスの最適化は、最初の段階で、都市の ID (実際の ID の NSNumber を意味します) と失敗した City エンティティを値として含む大きな辞書を残すことができるため、次の醜い検索プロセスを防ぐことができることです。ステージ 2 で同様のキャッシング トリックを使用してステージ 3 で同じことを行いますが、問題は、[ Client-City、Client-Agency、Agency-City ] で説明した 30 個のテーブルすべての間にはるかに多くの関係があることです。すべてのエンティティのキャッシュを含む最終的な手順では、iPad デバイスがアプリ用に予約しているリソースを使用する可能性が最も高くなります。
更新 4
今後の回答者へのメッセージ: この回答が詳細で適切な形式になるように最善を尽くしましたが、詳細な回答を期待しています。あなたの答えが、ここで議論されている問題の複雑さに実際に対処し、私の質問を可能な限り明確かつ一般的にするために行った私の努力を補完してくれるなら、それは素晴らしいことです. ありがとう。
更新 5
関連トピック:サーバーからのデータをキャッシュするためのクライアント (iOS) 上の Core Data 戦略、RestKit で POST 要求を作成し、応答を Core Data にマップしようとしています。
更新 6
新しい報奨金を開くことができなくなり、回答が受け入れられた後でも、このトピックが扱う問題に関する追加情報を含む他の回答をお待ちしております. 前もって感謝します。