В документации SQLite о функции журнала упреждающей записи, представленной в версии 3.7, есть некоторые комментарии, которые меня немного запутали.

На связанной странице сказано: «Синхронизация содержимого с диском не требуется, если приложение готово пожертвовать долговечностью после потери питания». Затем, несколькими абзацами ниже, говорится: «Контрольная точка требует операций синхронизации, чтобы избежать возможности повреждения базы данных после отключения питания или жесткой перезагрузки».

Так подвергается ли моя база данных большему риску повреждения при потере питания, если я использую WAL?

7
kdt 27 Авг 2010 в 17:18

3 ответа

Лучший ответ

При использовании WAL нет повышенного риска повреждения (поскольку он использует операции синхронизации при установлении контрольных точек).

Однако, если произойдет сбой (потеря питания или жесткая перезагрузка), вы потеряете все транзакции с момента последней контрольной точки; вот что подразумевается под «жертвой долговечности».

4
Doug Currie 27 Авг 2010 в 21:41
5
Я знаю, что это старый ответ, но в нем есть довольно важная ошибка. Вы не потеряете транзакции с момента последней контрольной точки, вы потеряете транзакции, которые еще не были полностью записаны в WAL. Если synchronous = NORMAL, он не ждет fsync () при записи транзакции в WAL, поэтому вы можете потерять эту транзакцию, если потеряете питание до того, как она будет полностью записана. Попав в WAL, он не будет потерян, независимо от контрольной точки.
 – 
Mike Marynowski
6 Фев 2013 в 02:07
1
До 17 февраля 2016 г. sqlite.org/docsrc/info/3540d671bcc4835c документация SQLite сказал, что синхронный = НОРМАЛЬНЫЙ по умолчанию в режиме WAL ... теперь он говорит синхронный = ПОЛНЫЙ - намного безопаснее по умолчанию. Таким образом, вы потеряете транзакции до контрольной точки, только если вы установите режим synchronous = NORMAL.
 – 
Doug Currie
11 Мар 2016 в 03:21

Чтобы ответить полностью, нам нужно знать, что у вас установлено для PRAGMA synchronous, поскольку это влияет на то, когда вызывается fdatasync() и, следовательно, когда буферы очищаются на физическом диске.

Когда вы цитируете «до тех пор, пока приложение готово пожертвовать долговечностью из-за потери мощности», имеется в виду наличие synchronous=NORMAL. Здесь WAL синхронизируется с диском только при установлении контрольных точек (один fdatasync() для WAL и один для основной БД после его слияния). Вы должны быть хорошо защищены от коррупции, но могут быть некоторые записи, которые никогда не попадают на пластину и, таким образом, теряются: отсюда и потеря прочности. Однако положительным моментом является гораздо меньше медленной fdatasync () для фактической синхронизации данных.

Чтобы обеспечить максимальную защиту от потери данных, вам может потребоваться synchronous=FULL. Это увеличивает надежность, но стоимость одной транзакции записи составляет один fdatasync(). Однако это все же лучше, чем режим без WAL, где было бы два вызова fdatasync() - один для журнала транзакций и один для основной БД.

7
MattR 3 Фев 2012 в 20:54

Пока вызовы синхронизации к вашей ОС работают безупречно, у вас нулевой риск повреждения базы данных. Однако это может быть так, а может и не быть - см. Документацию sqlite для более подробного объяснения этого.

Чтобы исправить Дуга Карри (см. Сообщение MattR): вы рискуете потерять транзакции, только если @ synchronous = NORMAL @. Если @ synchronous = FULL @ (по умолчанию), вы не жертвуете долговечностью. Подробнее см. http://www.sqlite.org/draft/wal.html. на этом.

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

0
Gabriel Schreiber 20 Мар 2012 в 18:05