Добавить в корзинуПозвонить
Найти в Дзене
Цифровая Переплавка

SQLite и «призрак долговечности»: почему документация путает, а настройки спасают

SQLite давно стал символом «баз данных по умолчанию» — встраиваемый, лёгкий, кроссплатформенный. Его используют браузеры, мобильные приложения, даже встраиваемые устройства. Но в вопросе долговечности транзакций (durability) ситуация оказалась куда менее прозрачной, чем хотелось бы разработчикам. Исследователь Эндрю Аер разобрался в официальной документации и пришёл к неожиданному выводу: Казалось бы — всё понятно. Но тут в дискуссию включился сам создатель SQLite, Ричард Хипп, заявивший ровно противоположное: В результате получается противоречие: документация говорит одно, автор — другое. Дополнительную путаницу создают окружения и драйверы: В итоге разработчик, не копающийся глубоко, может оказаться с базой, где «коммит» вовсе не значит «сохранено». Мне кажется, это яркий пример конфликта философий: Технически всё решается довольно просто: 📌 Дополнения: SQLite — блестящий инструмент, но именно его популярность делает проблему критичной: миллионы приложений опираются на предположение
Оглавление

SQLite давно стал символом «баз данных по умолчанию» — встраиваемый, лёгкий, кроссплатформенный. Его используют браузеры, мобильные приложения, даже встраиваемые устройства. Но в вопросе долговечности транзакций (durability) ситуация оказалась куда менее прозрачной, чем хотелось бы разработчикам.

🔍 В чём проблема

Исследователь Эндрю Аер разобрался в официальной документации и пришёл к неожиданному выводу:

  • 📄 По умолчанию SQLite работает в режиме journal_mode=DELETE и synchronous=FULL.
  • ⚡ Но в таком сочетании долговечность транзакций не гарантируется: чтобы защититься от сбоев питания и краха ОС, нужен уровень EXTRA.
  • 🔄 Если же включить WAL (Write-Ahead Logging), то достаточно FULL, и это действительно гарантирует сохранность.

Казалось бы — всё понятно. Но тут в дискуссию включился сам создатель SQLite, Ричард Хипп, заявивший ровно противоположное:

  • «По умолчанию SQLite долговечен».
  • «В WAL долговечность может не сохраняться».

В результате получается противоречие: документация говорит одно, автор — другое.

⚠️ Подводные камни

Дополнительную путаницу создают окружения и драйверы:

  • 🐹 Популярный Go-драйвер для SQLite в WAL по умолчанию ставит synchronous=NORMAL, что ломает гарантию долговечности.
  • 🍏 На macOS системный вызов fsync работает «смягчённо» (для скорости), и для реальной синхронизации нужно включать fullfsync.

В итоге разработчик, не копающийся глубоко, может оказаться с базой, где «коммит» вовсе не значит «сохранено».

🧑‍💻 Мой взгляд

Мне кажется, это яркий пример конфликта философий:

  • С одной стороны, SQLite хочет быть быстрым и «plug-and-play»,
  • С другой — мы живём в мире, где каждый байт данных может быть критически важным (финансы, медицинские записи, telemetry).

Технически всё решается довольно просто:

  • 🛡️ Если важна долговечность — явно выставляйте synchronous=EXTRA (для DELETE) или synchronous=FULL (для WAL).
  • 📊 Для кроссплатформенной работы закладывайте проверки окружения (например, принудительное включение PRAGMA fullfsync=ON на macOS).
  • 📌 Документации SQLite действительно не хватает таблицы комбинаций journal_mode × synchronous с чётким указанием: «даёт ли эта пара гарантию сохранности данных или нет».
Аккуратная таблица «journal_mode × synchronous», основанная на выводах из статьи Эндрю Аера и документации SQLite (с учётом тестов и уточнений
Аккуратная таблица «journal_mode × synchronous», основанная на выводах из статьи Эндрю Аера и документации SQLite (с учётом тестов и уточнений

📌 Дополнения:

  • В DELETE + FULL SQLite не синхронизирует каталог после удаления журнала. Поэтому при внезапном отключении питания данные могут пропасть. Именно поэтому нужен EXTRA.
  • В WAL + FULL дополнительно синхронизируется WAL-файл после каждого коммита, и этого достаточно для durability.
  • В WAL + EXTRA особых преимуществ нет, это поведение совпадает с FULL.
  • На macOS без включённого PRAGMA fullfsync=ON даже эти режимы не гарантируют реальный fsync.
  • Некоторые драйверы (например, Go) по умолчанию понижают synchronous в WAL до NORMAL, и это ломает долговечность.

🤔 Итог

SQLite — блестящий инструмент, но именно его популярность делает проблему критичной: миллионы приложений опираются на предположение «коммит значит навсегда», и не все догадываются, что это не всегда правда. В моём опыте внедрения SQLite в продакшн-системах, самое надёжное решение — не верить умолчаниям и всегда явно задавать параметры долговечности.

🔗 Источник: Andrew Ayer — SQLite’s Durability Settings are a Mess