База данных SQLite: полный обзор, плюсы, минусы и пределы
Для чего нужна SQLite, подходит ли она для сайта и где выигрывает серверная база: режим WAL, плюсы и минусы, сравнение с PostgreSQL и MySQL, инструменты, примеры SQL, пределы и советы.
Коротко
SQLite — это база данных в одном файле: небольшая библиотека внутри приложения, без сервера, пользователей и настройки. По оценке авторов, это самая распространённая база в мире — она живёт в каждом телефоне, каждом браузере и бесчисленных программах. Для сайта это серьёзный вариант: в режиме WAL множество читателей работают параллельно с записью, транзакции полностью надёжны, есть полнотекстовый поиск, JSON, RETURNING и строгие таблицы. Её предел — один пишущий за раз и одна машина: для нагруженного магазина с множеством одновременных заказов или нескольких серверов приложения берите PostgreSQL или MySQL.
SQLite коротко: паспорт базы
Главные факты одной таблицей: что такое SQLite, как она хранит данные и где живёт.
- Тип
- Встраиваемая реляционная база: библиотека, а не сервер
- История
- Д. Ричард Хипп, 2000 год; формат файла версии 3 стабилен с 2004-го
- Лицензия
- Общественное достояние — без лицензии вообще
- Хранение
- Вся база — один файл, который копируется как любой другой
- Транзакции
- ACID; в режиме WAL читатели не блокируют запись
- Запись
- Один пишущий за раз, остальные ждут очереди
- SQL
- Оконные функции, CTE, upsert,
RETURNING, вычисляемые колонки, таблицыSTRICT - Встроено
- Функции JSON, полнотекстовый поиск FTS5, R*Tree для координат
- Пределы
- До 281 ТБ на файл в теории; на практике — одна машина
- Где живёт
- Android и iOS, все крупные браузеры, настольные программы, устройства
- В языках
- Встроена в PHP, Python и Node.js (
node:sqlite); драйверы для остальных
Для чего применяется SQLite: 8 сфер
От телефонов до рабочих сайтов. Под каждой сферой — инструменты, с которыми она обычно идёт.
-
01
Сайты и блоги
Контент, формы и админка: большинство сайтов пишут редко, а читают много, — сильный случай для SQLite.
-
02
Небольшие сервисы и внутренние инструменты
Один сервер, один файл, ничего лишнего для администрирования.
-
03
Мобильные приложения
Локальная база по умолчанию на Android и iOS.
-
04
Настольные программы
Настройки, история и документы приложений часто хранятся в SQLite.
-
05
Расширения браузера
SQLite, скомпилированная в WebAssembly, хранит данные прямо в браузере.
-
06
Анализ данных
Загрузить CSV и выполнить по нему SQL за секунды, без сервера.
-
07
Тесты и прототипы
База в памяти создаётся на каждый тест и исчезает после него.
-
08
Распределённая SQLite
Копии рядом с пользователем и репликация в хранилище — через отдельные проекты.
Плюсы и минусы SQLite
SQLite меняет сервер на простоту. И приобретения, и потери идут отсюда.
Плюсы · 8
-
Нечего администрировать
Нет сервера, пользователей, портов и паролей — база стартует вместе с приложением.
-
Очень быстрое чтение
Между кодом и данными нет сети: запрос — это вызов функции.
-
Копия — это копия файла
Вся база переносится и копируется одним файлом.
-
Надёжная
Полноценные транзакции; код протестирован тщательнее почти любого другого ПО.
-
Современный SQL
Оконные функции, upsert,
RETURNING, JSON и строгие таблицы. -
Поиск из коробки
FTS5 даёт полнотекстовый поиск с ранжированием без отдельного движка.
-
Свободна навсегда
Общественное достояние и формат файла, поддержку которого авторы обещают до 2050 года.
-
Дешевле хостинг
Отдельный сервер базы не нужен — одной машины хватает на весь проект.
Минусы · 8
-
Один пишущий за раз
Множество одновременных записей встают в очередь — нагруженные магазины и сервисы это почувствуют.
-
Одна машина
Несколько серверов приложения не могут безопасно делить один файл по сетевому диску.
-
Нет пользователей и прав
Доступ решают права на файл, а не учётные записи базы.
-
Мягкие типы по умолчанию
Без
STRICTтекст может тихо попасть в числовую колонку. -
Ограниченный ALTER TABLE
Часть изменений схемы означает пересоздание таблицы вручную.
-
Нет встроенной репликации
Копии и переключение при сбое дают отдельные инструменты вроде Litestream.
-
Поиск без морфологии
FTS5 из коробки не знает словоформ; помогают запросы по началу слова.
-
Права на файлы важны
В режиме WAL даже чтению нужен доступ на запись к файлам
-walи-shmрядом с базой.
SQLite и серверные базы: сравнение с PostgreSQL и MySQL
Файл против сервера — сравнение про модель, а не про бенчмарки.
| Критерий | SQLite | PostgreSQL | MySQL |
|---|---|---|---|
| Модель | библиотека и файл | сервер | сервер |
| Настройка | нет | да, плюс пулер | да |
| Одновременная запись | по одному | много | много |
| Несколько серверов приложения | нет | да | да |
| Скорость чтения на одной машине | очень высокая, без сети | высокая | высокая |
| Пользователи и права | права на файл | роли и права | пользователи и права |
| Репликация | внешними инструментами | встроена | встроена |
| Лучше всего для | сайтов, небольших сервисов, приложений | сервисов со сложными данными | CMS и веб-приложений |
Когда брать SQLite, а когда нет
Двенадцать типичных задач с вердиктом. Где SQLite не лучший выбор, названа альтернатива.
-
Корпоративный сайт или блог
Лучший выборМало записи, много чтения — ровно случай SQLite.
-
Лендинг с формой
Лучший выборСерверная база была бы избыточной.
-
Внутренний инструмент для команды
Лучший выборОдин сервер, один файл, нечего администрировать.
-
Мобильное или настольное приложение
Лучший выборСтандартная локальная база.
-
Тесты и прототипы
Лучший выборСвежая база в памяти на каждый запуск.
-
Каталог на несколько тысяч позиций
Лучший выборЧтение и поиск работают хорошо, импорт идёт одной транзакцией.
-
Небольшой интернет-магазин
ПодходитПодойдёт при скромном числе заказов; переезд планируйте, когда вырастет.
-
SaaS на старте
ПодходитВозможно на одном сервере с WAL; для роста надёжнее PostgreSQL.
-
Нагруженный магазин с множеством заказов сразу
Другой языкPostgreSQL или MySQL: много пишущих одновременно.
-
Несколько серверов приложения
Другой языкСерверная база, к которой подключаются все.
-
Строгие права для многих пользователей
Другой языкPostgreSQL с ролями.
-
Геоданные и векторный поиск в масштабе
Другой языкPostgreSQL с PostGIS и pgvector.
Экосистема SQLite: инструменты для частых задач
Средняя колонка — то, что идёт вместе с самой SQLite.
| Задача | Встроено | Инструменты |
|---|---|---|
| Командная строка | sqlite3 | — |
| Резервные копии | VACUUM INTO, .backup | Litestream |
| Репликация | — | Litestream, LiteFS, Turso |
| Полнотекстовый поиск | FTS5 | — |
| JSON | json_*, ->> | — |
| Векторы | — | sqlite-vec |
| В браузере | — | sqlite-wasm |
| Просмотр данных | — | DB Browser for SQLite, Datasette, DBeaver |
| В PHP | PDO_SQLITE, SQLite3 | — |
| В Node.js | node:sqlite | better-sqlite3 |
Пределы SQLite и частые ошибки
-
Режим журнала по умолчанию
Без WAL запись блокирует читателей. Для сайта WAL включают один раз — он сохраняется в файле.
-
«database is locked» без ожидания
Без
busy_timeoutзапрос, встретив занятый файл, сразу падает, вместо того чтобы подождать мгновение. -
Чужой владелец файлов WAL
Если
-walили-shmпринадлежат другому пользователю, сайт ловит случайные ошибки — даже при чтении. -
Файл на сетевом диске
Блокировки файлов по NFS ненадёжны — базу можно повредить.
-
Копировать живой файл
Простая копия во время записи может оказаться битой; используйте
VACUUM INTOили.backup. -
Рост без плана
Когда множатся записи или серверы, переезд на серверную базу проще спланировать заранее.
8 советов для SQLite в рабочем проекте
-
01
Режим WAL
PRAGMA journal_mode = WAL— читатели и запись перестают мешать друг другу. -
02
busy_timeout
Несколько секунд ожидания вместо «database is locked».
-
03
Внешние ключи включены
PRAGMA foreign_keys = ONв каждом подключении — по умолчанию они выключены. -
04
Таблицы STRICT
Типы проверяются, и неверные данные становятся ошибкой, а не сюрпризом.
-
05
Импорт одной транзакцией
Тысячи вставок в одной транзакции в разы быстрее, чем по одной.
-
06
Один владелец всех файлов
База,
-walи-shmпринадлежат пользователю, от которого работает сайт. -
07
Копии через Litestream
Непрерывное копирование в хранилище — восстановление на любой момент.
-
08
Спланируйте выход
Стандартный SQL и инструмент миграций делают будущий переезд на PostgreSQL рутиной.
Как выглядит SQLite: 3 примера SQL
Настройки для сайта со строгой таблицей, полнотекстовый поиск и JSON с индексом. Проверены в SQLite 3.40 на файле базы.
Настройки и строгая таблица
WAL, ожидание вместо ошибки, upsert с RETURNING — а текст в колонке цены отклоняется.
-- настройки для сайта: чтение не мешает записи, а занятый файл ждёт, а не падает
PRAGMA journal_mode = WAL; -- wal
PRAGMA busy_timeout = 5000;
PRAGMA foreign_keys = ON;
-- STRICT: типы колонок проверяются, как в серверной базе
CREATE TABLE products (
id INTEGER PRIMARY KEY,
sku TEXT NOT NULL UNIQUE,
title TEXT NOT NULL,
price INTEGER NOT NULL CHECK (price >= 0)
) STRICT;
INSERT INTO products (sku, title, price) VALUES ('A-100', 'Дубовый стол', 24000)
ON CONFLICT (sku) DO UPDATE SET price = excluded.price
RETURNING id, title, price; -- 1|Дубовый стол|24000
INSERT INTO products (sku, title, price) VALUES ('A-101', 'Дубовый стул', 'дёшево');
-- ошибка: cannot store TEXT value in INTEGER column products.price
Полнотекстовый поиск в файле
FTS5 находит и подсвечивает совпадение и сортирует по релевантности.
-- полнотекстовый поиск прямо в файле — без отдельного поискового движка
CREATE VIRTUAL TABLE articles USING fts5(title, body);
INSERT INTO articles (title, body) VALUES
('Как выбрать стол', 'Дубовые и ореховые столы для кухни'),
('Уход за стульями', 'Как чистить дубовые стулья'),
('Полки', 'Сосновые полки для маленькой комнаты');
SELECT title, snippet(articles, 1, '[', ']', '…', 4) AS fragment
FROM articles
WHERE articles MATCH 'дуб*' -- у SQLite нет морфологии: звёздочка ловит «дубовые»
ORDER BY rank;
-- Уход за стульями|Как чистить [дубовые] стулья
-- Как выбрать стол|[Дубовые] и ореховые столы…
JSON с индексом
Вычисляемая колонка достаёт поле из JSON, а индекс делает поиск по нему быстрым.
-- JSON в колонке и индекс по полю внутри него
CREATE TABLE events (
id INTEGER PRIMARY KEY,
payload TEXT NOT NULL CHECK (json_valid(payload)),
kind TEXT GENERATED ALWAYS AS (payload ->> '$.kind') VIRTUAL
);
CREATE INDEX events_kind_idx ON events (kind);
INSERT INTO events (payload) VALUES ('{"kind": "order", "total": 24000}'), ('{"kind": "visit"}');
SELECT id, payload ->> '$.total' AS total
FROM events
WHERE kind = 'order'; -- 1|24000
Вопросы о SQLite
Можно ли использовать SQLite для сайта?
Да. Большинство сайтов читают гораздо больше, чем пишут, и SQLite в режиме WAL справляется с этим очень хорошо.
Сколько посетителей выдержит SQLite?
Зависит от записи, а не от посещений: чтение масштабируется хорошо, а предел — множество одновременных записей.
SQLite или PostgreSQL?
SQLite — для сайта или сервиса на одном сервере; PostgreSQL — когда пишущих много, серверов несколько или данные сложные.
Надёжна ли SQLite?
Да: полноценные транзакции и один из самых тщательно протестированных кодов в мире. Риски — от сетевых дисков и копирования живого файла.
Как делать резервные копии SQLite?
VACUUM INTO или .backup для согласованной копии либо Litestream для непрерывного копирования.
Почему «database is locked»?
Другое подключение пишет. Включите WAL и задайте busy_timeout, чтобы запросы ждали мгновение.
Есть ли в SQLite полнотекстовый поиск?
Да, FTS5 с ранжированием и подсветкой; словоформ он не знает, поэтому помогают запросы по началу слова.
Сложно ли переехать с SQLite на PostgreSQL?
Нет, если SQL стандартный: pgloader переносит данные, а код меняется мало.
Форма
База данных
под ваш масштаб
Подбираю базу под масштаб проекта: SQLite для сайтов и небольших сервисов, PostgreSQL или MySQL там, где растут нагрузка и данные, — и переношу данные, когда приходит время. Расскажите о задаче — отвечу в течение рабочего дня.