Menu

SQLite :memory: — база данных в оперативной памяти

Разбираемся, как работает in-memory база данных SQLite, когда стоит брать :memory: и чем такой режим отличается от обычной БД в файле.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

База данных, которая живёт в оперативке

В SQLite есть особое имя файла — :memory:. Открываете базу с таким именем, и SQLite полностью пропускает диск: вся база данных хранится в оперативной памяти. Таблицы, индексы, транзакции, внешние ключи — всё работает ровно так же, как обычно. Разница лишь одна: как только соединение закрывается, база исчезает.

Из командной строки:

sqlite3 :memory:

Теперь вы в интерактивном режиме SQLite, перед вами свежая пустая база, которая живёт только в оперативной памяти. Создавайте таблицу, вставляйте строки, делайте запросы — всё работает как обычно:

Закрыли сессию — и данные испарились. Никакого файла на диске не остаётся, потому что его и не было.

Зачем это вообще нужно

База данных, которая не переживает перезапуск, звучит как баг, а не как фича. Но на деле она полезна в трёх ситуациях.

Тесты. Каждый тест получает чистую базу за миллисекунды. Никаких временных файлов для уборки, никакого мусора от прошлого прогона, никакого общего фикстур-файла, который кто-то залочил. Большинство тестовых наборов на Python, Node и Go, использующих SQLite, открывают именно :memory: ровно по этой причине.

Одноразовый анализ. Загрузили CSV, погоняли запросы, выкинули. Быстрее, чем поднимать настоящую БД, и удобнее, чем каждый раз парсить файл руками в коде.

Кэш и временное хранилище. Внутри долго работающей программы in-memory база SQLite — на удивление удачный движок для ad-hoc запросов по данным, которые вы уже подгрузили в память.

Общий знаменатель простой: SQL нужен, а вот персистентность — нет.

Производительность: быстрее, но без магии

База в памяти не ходит на диск, поэтому записи, которые обычно били бы по файловой системе, превращаются в обычные операции с памятью. Нагрузки, упирающиеся в I/O, заметно ускоряются. А вот те, что упираются в CPU — сложное планирование запросов, тяжёлые сортировки — почти не меняются, ведь SQLite и так кэширует горячие страницы в памяти.

Небольшая демонстрация того, насколько синтаксис идентичен:

Запрос отработал на базе в памяти, но точно такой же SQL пойдёт и к файловой БД — движку без разницы.

SQLite в памяти или в файле: что выбрать

Компромисс здесь простой, и о нём стоит сказать прямо:

  • Файловая база (mydata.db): переживает перезапуски. Её могут открывать несколько процессов одновременно. Выдерживает сбои (в режиме WAL — почти всегда). Берите её для всего, что должно что-то помнить.
  • База в памяти (:memory:): исчезает при закрытии соединения. По умолчанию доступна только тому соединению, которое её создало. Быстрее работает на интенсивной записи, если результат всё равно не нужен. Подходит для тестов, черновых экспериментов и короткоживущих кэшей.

Если сомневаетесь — берите файл. Память — это частный случай.

У каждого соединения — своя база в памяти

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

-- Терминал 1
sqlite3 :memory:
sqlite> CREATE TABLE t (x); INSERT INTO t VALUES (1);

-- Терминал 2
sqlite3 :memory:
sqlite> SELECT * FROM t;
Error: no such table: t

Это не баг — так задумано. :memory: означает «приватная база для этого соединения». То же самое работает и внутри одной программы: если код открывает два соединения к :memory:, каждое получит свою изолированную базу.

Общая sqlite база данных в памяти для нескольких соединений

Если вам всё-таки нужно, чтобы несколько соединений видели одну и ту же in-memory базу, SQLite это умеет — через URI-имена файлов и общий кэш. Волшебная строка — file::memory:?cache=shared:

sqlite3 'file::memory:?cache=shared'

Любое соединение в том же процессе, открывшее ровно такой же URI, подключается к этой же базе. Закроете все соединения — база исчезнет.

Можно также задать именованную базу данных в памяти — это удобно, когда нужно несколько отдельных общих баз:

sqlite3 'file:mydb?mode=memory&cache=shared'

Имя mydb здесь — всего лишь метка, никакого файла за ним нет. Два соединения, открывающие file:mydb?mode=memory&cache=shared, работают с одной и той же базой, а соединение с file:other?mode=memory&cache=shared получит уже другую.

Как сохранить базу SQLite из памяти в файл

Бывает так: вы прогоняете весь рабочий процесс в памяти, а потом решаете, что результат неплохо бы сохранить. В CLI для этого есть точечная команда .backup:

sqlite3 :memory:
sqlite> CREATE TABLE results (id INTEGER, score REAL);
sqlite> INSERT INTO results VALUES (1, 0.91), (2, 0.87);
sqlite> .backup snapshot.db
sqlite> .quit

snapshot.db теперь — это обычная файловая БД с тем же содержимым. Позже её можно открыть командой sqlite3 snapshot.db и продолжить с того места, где остановились.

Обратная операция тоже работает — .restore загружает файловую базу в память текущего соединения:

sqlite3 :memory:
sqlite> .restore snapshot.db
sqlite> SELECT * FROM results;

Из кода приложения тот же механизм доступен через C API SQLite — функцию sqlite3_backup_init, и большинство биндингов к языкам её оборачивают. Например, в модуле sqlite3 для Python есть метод Connection.backup().

Типичная ошибка

Иногда базу данных в памяти пытаются «сохранить», подключив файл через ATTACH и скопировав туда данные:

Такой способ годится для простого копирования таблиц, но индексы, триггеры, представления и внешние ключи он переносит не на сто процентов. Если нужна точная копия всей базы — берите .backup (или соответствующий API): он делает побайтовую копию на уровне страниц.

Что стоит запомнить

  • :memory: — это специальное имя файла в SQLite, которое создаёт базу прямо в оперативной памяти, без записи на диск.
  • SQL остаётся ровно тем же, что и для файловой базы: те же таблицы, те же запросы, те же ограничения.
  • Каждое подключение к :memory: получает свою личную базу. Если нескольким соединениям нужно работать с одной, используйте URI с общим кэшем (file::memory:?cache=shared).
  • Это удачный выбор для тестов, разовой аналитики и короткоживущих кэшей — но не для данных, которые должны пережить перезапуск.
  • Когда решите сохранить in-memory базу на диск, перенесите её туда через .backup.

Дальше: создание таблиц

CREATE TABLE уже мелькал в примерах выше. На следующей странице мы разберём его не спеша — описание колонок, типы данных, доступные ограничения и те мелкие решения, благодаря которым со схемой потом приятно работать.

Часто задаваемые вопросы

Как создать базу данных SQLite в оперативной памяти?

Вместо пути к файлу передайте SQLite специальное имя :memory:. В CLI это выглядит как sqlite3 :memory:, а из любой библиотеки — то же самое имя в вызове connect. База будет жить в RAM и пропадёт сразу, как только вы закроете соединение.

Что такое :memory: в SQLite?

:memory: — это магическое имя файла, по которому SQLite понимает: «никакого файла не нужно, держим всё в оперативке». Получается полноценная база — таблицы, индексы, транзакции, всё на месте, — просто на диск ничего не пишется. И учтите: каждое соединение, открытое с :memory:, получает свою отдельную базу.

Можно ли расшарить in-memory базу SQLite между соединениями?

По умолчанию — нет, каждое соединение к :memory: изолировано. Чтобы база была общей, открывайте её через URI вида file::memory:?cache=shared с включённым shared cache. Тогда все соединения внутри одного процесса, открывшие ровно этот URI, увидят одну и ту же базу.

Можно ли сохранить in-memory базу SQLite на диск?

Да, без проблем. В CLI используйте команду .backup, а в коде — backup API вашей библиотеки: они скопируют базу из памяти в файл. Альтернатива — подключить файловую базу через ATTACH и перелить данные запросом вида INSERT INTO file.table SELECT * FROM main.table.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ