IOSアプリのCoreDataに奇妙な問題があり、WALファイルがhuge(〜1GB)になることがあります。問題を抱えている他の人がいるようです(例: コアデータsqlite-walファイルは〜5000行を挿入するとMASSIVE(> 7GB)になります )。
私の最初の考えは、アプリの起動時にWALファイルを削除することです。これは問題ないという問題に関するsqliteのドキュメントを読んでいるようです。しかし、誰かがこれを行うことの欠点を知っていますか?
もちろん、WALファイルが非常に大きくなっている理由を突き止めたいのですが、現時点ではその根底に到達できず、問題を深く掘り下げながら回避策を講じたいと思います。
私のCoreDataデータベースはキャッシュのようなものであることを指摘する価値があります。したがって、WALにあるデータを失っても問題ありません。私が本当に知る必要があるのは、WALを削除するとデータベースが完全に破損するのでしょうか?私の疑いはノーです。そうでなければ、WALはその目的の1つを果たしません。
いくつかのこと:
あなたは確かにWALファイルを削除することができます。メインファイルにチェックポイントされていないコミット済みトランザクションはすべて失われます。 (したがって、ACIDの「耐久性」の部分に違反しますが、おそらく気にしません。)
Journal_size_limitプラグマを使用して、ディスク上のWALファイルのサイズを制御できます(気になる場合)。より頻繁に手動でチェックポイントを設定することもできます。ここの「過度に大きなWALファイルの回避」を参照してください: https://www.sqlite.org/wal.html
私はWALモードの迷信的なバッシングをすべて嫌います。 WALモードは、ロールバックジャーナルに伴うすべてのロックレベルの問題(およびほとんどの「データベースがビジー」の問題)を排除するため、より高速で、より同時で、はるかに簡単です。 WALモードは、ほとんどすべての状況で正しい選択です。 (問題となるのは、ファイルへの共有メモリマップアクセスをサポートしていないフラッシュファイルシステムだけです。その場合、「非公式」SQLITE_SHM_DIRECTORYコンパイルディレクティブを使用して、.shmファイルを別の種類のファイルシステムに移動できます。 -例:tmpfs-ただし、これはiOSでは問題になりません。)
WALモードには問題があります。使用しないでください。問題はさまざまですが、レポートのサイズが非常に大きいため、移行中の失敗(NSPersistentStoreCoordinatorsmigratePersistentStoreを使用)やiCloudトランザクションログのインポート中の失敗などの問題があります。したがって、これらのバグが修正されるまでは利点が報告されていますが、WALモードを使用するのはおそらく賢明ではありません。
また、最新のデータが含まれているため、先行書き込みログを削除することはできません。
ロールバックジャーナルモードを使用するようにデータベースを設定すると、大量のデータをロードするときに、これらの非常に大きなファイルがなくなると思います。
これは、WALがどのように機能するかを説明する抜粋です。アプリがチェックポイントを実行したことを保証できない限り、コミットされたトランザクションを削除するリスクを冒さずにWALファイルを削除する方法がわかりません。
WALの仕組み
従来のロールバックジャーナルは、元の変更されていないデータベースコンテンツのコピーを別のロールバックジャーナルファイルに書き込み、変更をデータベースファイルに直接書き込むことによって機能します。クラッシュまたはROLLBACKが発生した場合、ロールバックジャーナルに含まれている元のコンテンツがデータベースファイルに再生され、データベースファイルが元の状態に戻ります。 COMMITは、ロールバックジャーナルが削除されたときに発生します。
WALアプローチはこれを逆転させます。元のコンテンツはデータベースファイルに保存され、変更は別のWALファイルに追加されます。 COMMITは、コミットを示す特別なレコードがWALに追加されたときに発生します。したがって、COMMITは、元のデータベースに書き込むことなく発生する可能性があります。これにより、リーダーは、変更が同時にWALにコミットされている間、元の変更されていないデータベースから操作を続行できます。 1つのWALファイルの最後に複数のトランザクションを追加できます。
チェックポインティング
もちろん、最終的にWALファイルに追加されたすべてのトランザクションを元のデータベースに転送したいと考えています。 WALファイルトランザクションをデータベースに戻すことを「チェックポイント」と呼びます。
ロールバックログと先行書き込みログの違いについて考える別の方法は、ロールバックジャーナルアプローチでは、読み取りと書き込みの2つの基本操作があるのに対し、先行書き込みログでは、読み取り、書き込みの3つの基本操作があることです。 、およびチェックポイント。
デフォルトでは、WALファイルが1000ページのしきい値サイズに達すると、SQLiteは自動的にチェックポイントを実行します。 (SQLITE_DEFAULT_WAL_AUTOCHECKPOINTコンパイル時オプションを使用して、別のデフォルトを指定できます。)WALを使用するアプリケーションは、これらのチェックポイントを発生させるために何もする必要はありません。ただし、必要に応じて、アプリケーションは自動チェックポイントのしきい値を調整できます。または、自動チェックポイントをオフにして、アイドル状態のとき、または別のスレッドやプロセスでチェックポイントを実行することもできます。
IOS 7のWALについては、かなりの数の否定的な報告があります。問題をより徹底的に調査する時間ができるまで、いくつかのプロジェクトでWALを無効にする必要がありました。
ジャーナルファイルは削除しませんが、SQLiteファイルをバキュームするオプションを試してみると、SQLiteがジャーナルファイルを「消費」します。これを行うには、NSSQLiteManualVacuumOption
をNSPersistentStore
に追加するときに、オプションの一部としてNSPersistentStoreCoordinator
を追加します。
それが時間がかかることになった場合は、WALを無効にすることをお勧めします。それを無効にすることによる悪影響は(まだ)見ていません。
このスレッドにはかなり良い答えがありますが、iOS7コアデータのジャーナリングモードに関するApple公式QnAにリンクするためにこれを追加しています: https:// developer。 Apple.com/library/ios/qa/qa1809/_index.html
彼らは異なる解決策を提供します:
Core Data SQLiteストアを安全にバックアップおよび復元するには、次の手順を実行します。
ファイルシステムAPIではなくNSPersistentStoreCoordinatorクラスの次のメソッドを使用して、CoreDataストアをバックアップおよび復元します。
- (NSPersistentStore *)migratePersistentStore:(NSPersistentStore *)store toURL:(NSURL *)URL options:(NSDictionary *)options withType:(NSString *)storeType error:(NSError **)error
これが推奨されるオプションであることに注意してください。
ストアファイルをコピーする必要がある場合は、ストアを永続ストアコーディネーターに追加するときに、ロールバックジャーナリングモードに変更します。リスト1は、これを行う方法を示すコードです。
リスト1永続ストアを追加するときにロールバックジャーナリングモードを使用する
NSDictionary *options = @{NSSQLitePragmasOption:@{@"journal_mode":@"DELETE"}}; if (! [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:options
error:&error])
{
// error handling.
}
WALモードでロードされたストアの場合、メインストアファイルと対応する-walファイルの両方が存在する場合、ロールバックジャーナリングモードを使用してストアを永続ストアコーディネーターに追加すると、CoreDataにチェックポイント操作が実行されます。 -walファイルのデータをストアファイルに追加します。これは実際には、チェックポイント操作を実行するためのCoreDataの方法です。一方、-walファイルが存在しない場合、このアプローチを使用してストアを追加しても例外は発生しませんが、欠落している-walファイルに記録されているトランザクションは失われます。
非常に重要な編集
一部のユーザーがiOS 8.1
を使用していて、最初のソリューション(Apple推奨)を選択した場合、ユーザーのmany-to-many
データの関係は完全に破棄されることに注意してください。失われました。 。削除されました。移行されたデータベース全体で。
これは明らかにiOS 8.2
で修正された厄介なバグです。詳細はこちら http://mjtsai.com/blog/2014/11/22/core-data-relationships-data-loss-bug/
SqliteWALファイルは絶対に削除しないでください。実際のsqliteファイルにまだ書き込まれていないトランザクションが含まれています。代わりに、データベースにチェックポイントを強制してから、WALファイルをクリーンアップしてください。
CoreDataでこれを行う最良の方法は、DELETEジャーナルモードプラグマを使用してデータベースを開くことです。これにより、チェックポイントが設定され、WALファイルが削除されます。
NSDictionary *options = @{ NSSQLitePragmasOption: @{ @"journal_mode": @"DELETE"}};
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:_storeURL
options:options
error:&localError];
正気のために、これを行うときは、永続ストアへの接続が1つだけであること、つまり、単一の永続ストアコーディネーター内の永続ストアインスタンスが1つだけであることを確認する必要があります。
特定の場合のFWIWでは、最初のデータベースインポートにTRUNCATEまたはOFFを使用し、更新のためにWALに切り替えることができます。