Можно ли удалить sqlite WAL файл?

У меня странная проблема с Core Data в приложении iOS, где иногда файл WAL становится огромным (~ 1 ГБ). Похоже, что есть другие люди с проблемой (например, Core Data sqlite-wal файл получает MASSIVE ( > 7 ГБ) при вставке ~ 5000 строк).

Моя первоначальная мысль - удалить файл WAL при запуске приложения. Кажется, прочитав документацию sqlite по этому вопросу, это будет хорошо. Но кто-нибудь знает о каких-либо недостатках для этого?

Я, конечно же, хотел бы разобраться, почему файл WAL растет настолько большой, но сейчас я не могу разобраться с ним и хочу применить обходное решение, пока я копаю глубже в проблема.

Стоит отметить, что моя база данных Core Data больше кеша. Поэтому неважно, потеряю ли данные данные в WAL. Я действительно должен знать, будет ли база данных полностью повреждена, если я удалю WAL? Мое подозрение - нет, иначе WAL не выполняет одну из своих целей.

Ответы

Ответ 1

Режим WAL имеет проблемы, не используйте его. Проблемы различаются, но очень большой размер вашего отчета один, другие проблемы включают сбой во время миграции (с использованием NSPersistentStoreCoordinators migratePersistentStore) и сбой при импорте журналов транзакций iCloud. Таким образом, пока сообщается о преимуществах, пока эти ошибки не будут исправлены, вероятно, неразумно использовать режим WAL.

И нет, вы не можете удалить журнал записи Ahead, потому что он содержит самые последние данные.

Установите базу данных для использования режима журнала отката, и я думаю, вы обнаружите, что у вас больше нет этих очень больших файлов при загрузке большого количества данных.

Вот выдержка, в которой объясняется, как работает WAL. Если вы не можете гарантировать, что ваше приложение запустило контрольную точку, я не вижу, как вы можете удалить файл WAL, не рискуя удалить совершенные транзакции.

Как работает WAL

Традиционный журнал отката работает, написав копию исходный неизменный контент базы данных в отдельный журнал отката и затем записывать изменения непосредственно в файл базы данных. в событие сбоя или ROLLBACK, исходный контент, содержащийся в журнал отката воспроизводится в файле базы данных, чтобы вернуть файл базы данных в исходное состояние. COMMIT возникает, когда журнал отката удален.

Подход WAL инвертирует это. Исходный контент сохраняется в файл базы данных и изменения добавляются в отдельный WAL файл. COMMIT происходит, когда специальная запись с указанием фиксации прилагается к WAL. Таким образом, COMMIT может произойти без исходная база данных, которая позволяет читателям продолжать работать с оригинальная неизмененная база данных, в то время как изменения одновременно совершенных в WAL. Несколько транзакций могут быть добавлены к конец одного файла WAL.

Checkpointing

Конечно, каждый хочет в конечном итоге перенести все транзакции, которые добавляются в файл WAL обратно в исходную базу данных. перемещение транзакции WAL файла обратно в базу данных называются "Контрольные точки".

Еще один способ подумать о разнице между откатом и журнал записи-записи - это то, что в подходе с откатом-журналом есть две примитивные операции, чтение и письмо, тогда как с в журнале записи есть три примитивных операции: чтение, письменной форме и контрольной точке.

По умолчанию SQLite выполняет контрольную точку автоматически, когда файл WAL достигает порогового размера 1000 страниц. (The Параметр компиляции SQLITE_DEFAULT_WAL_AUTOCHECKPOINT может использоваться для укажите другое значение по умолчанию.) Приложения, использующие WAL, не должны выполнять все для того, чтобы эти контрольно-пропускные пункты произошли. Но если они хотят приложения могут регулировать порог автоматической контрольной точки. Или они могут отключать автоматические контрольные точки и выполнять контрольно-пропускные пункты во время холостых моментов или в отдельном потоке или процессе.

Ответ 2

Я вижу довольно много негативных сообщений о WAL в iOS 7. Мне пришлось отключить его по нескольким проектам, пока я не успел изучить проблемы более подробно.

Я бы не удалял файл журнала, но вы могли бы играть с возможностью вакуумирования SQLite файла, который заставит SQLite "уничтожить" файл журнала. Вы можете сделать это, добавив NSSQLiteManualVacuumOption как часть параметров при добавлении NSPersistentStore в NSPersistentStoreCoordinator.

Если это закончится тем, что потребуется много времени, я бы предложил отключить WAL. Я не видел никаких негативных последствий для его отключения (пока).

Ответ 3

В этом потоке есть неплохие ответы, но я добавляю этот, чтобы связать с официальным QnA Apple о режиме ведения журнала в iOS7 Core Data: https://developer.apple.com/library/ios/qa/qa1809/_index.html

Они дают разные решения:

Чтобы безопасно создавать резервные копии и восстанавливать хранилище SQLite Core Data, вы можете выполнить следующее:

Используйте следующий метод класса NSPersistentStoreCoordinator, а чем API-интерфейсы файловой системы, для резервного копирования и восстановления хранилища основных данных:

- (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 файл существуют, используя режим ведения журнала отката, чтобы добавить хранилище в постоянный координатор магазина заставит Core Data выполнить контрольно-пропускной пункт который объединяет данные в файле -wal в файл хранилища. На самом деле это метод Core Data для выполнения операции контрольной точки. С другой стороны, если -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/

Ответ 4

Пара вещей:

  • Вы можете удалить файл WAL. Вы потеряете любые совершенные транзакции, которые не были отправлены обратно в основной файл. (Таким образом, нарушение "долговечности" части ACID, но, возможно, вам все равно.)

  • Вы можете управлять размером файла WAL на диске с помощью прагмы journal_size_limit (если это вас беспокоит). Возможно, вы захотите также вручную установить контрольно-пропускной пункт. См. "Предотвращение чрезмерно больших файлов WAL" здесь: https://www.sqlite.org/wal.html

  • Мне не нравится все суеверное избиение режима WAL. Режим WAL более быстрый, более параллельный и намного более простой, поскольку он обойдется со всеми уровнями блокировки shenanigans (и большинство проблем с "базой данных занято" ), которые идут с журналами отката. Режим WAL - это правильный выбор практически во всех ситуациях. (Единственное место, где это проблематично, - это файловые системы флэш-памяти, которые не поддерживают доступ к файлам с распределенной памятью. В этом случае "неофициальная" директива компиляции SQLITE_SHM_DIRECTORY может использоваться для перемещения файла .shm в другую файловую систему - например, tmpfs - но это не должно быть проблемой для iOS.)

Ответ 5

Вы никогда не должны удалять SQL файл sqlite, он содержит транзакции, которые еще не были записаны в фактический файл sqlite. Вместо этого установите базу данных на контрольную точку, а затем очистите файл WAL для вас.

В CoreData лучший способ сделать это - открыть базу данных с помощью прагмы режима журнала DELETE. Это будет контрольная точка, а затем удалит файл WAL для вас.

NSDictionary *options = @{ NSSQLitePragmasOption: @{ @"journal_mode": @"DELETE"}};
[psc addPersistentStoreWithType:NSSQLiteStoreType
                  configuration:nil
                            URL:_storeURL
                        options:options
                          error:&localError];

Для здравого смысла вы должны убедиться, что у вас есть только одно соединение с постоянным хранилищем, когда вы это делаете, т.е. только один постоянный экземпляр хранилища в одном постоянном координаторе хранилища.

FWIW в вашем конкретном случае вы можете использовать TRUNCATE или OFF для первоначального импорта базы данных и переключиться на WAL для обновлений.

http://www.sqlite.org/pragma.html#pragma_journal_mode