Можно ли удалить 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