Две разные архитектуры баз данных
И SQLite, и MySQL понимают SQL и хранят данные построчно в таблицах, но встраиваются в систему они принципиально по-разному. SQLite — это библиотека: ваше приложение линкуется с ней и читает данные прямо из файла на диске. MySQL — это сервер: отдельный процесс, к которому вы подключаетесь через сокет или по сети.
Именно из этого отличия SQLite от MySQL вырастает всё остальное: как их ставить, сколько писателей могут работать одновременно, как делать бэкапы, как разворачивать в продакшене. Большинство вопросов в духе «SQLite vs MySQL» на самом деле сводятся к одному — встроенная база или клиент-серверная.
-- SQLite: открываете файл — у вас есть база данных.
sqlite3 app.db
-- MySQL: подключаетесь к работающему серверу.
mysql -h localhost -u root -p
Команда SQLite открывает (или создаёт) файл. Команда MySQL открывает соединение с процессом, который уже должен быть запущен, настроен и готов принимать логины.
Архитектура: встраиваемая БД против клиент-сервера
В приложении на SQLite движок базы данных работает внутри вашей программы. Никаких портов, никаких демонов, никакого systemctl start. Вызов библиотеки sqlite3 напрямую читает и пишет страницы в файл на диске.
С MySQL всё ровно наоборот. Сервер mysqld хранит данные, управляет соединениями, проверяет права, запускает планировщик запросов и разруливает блокировки. Ваше приложение выступает в роли клиента: отправляет SQL-строки по сети и получает в ответ строки результата.
Что это значит на практике:
- Развёртывание. SQLite уезжает в продакшен вместе с вашим приложением — один бинарник, один файл. Для MySQL нужен отдельный сервер: его придётся установить, защитить, мониторить и бэкапить.
- Доступ по сети. MySQL слушает порт, поэтому к одной базе данных могут подключаться сразу несколько серверов приложений. SQLite же рассчитан на один процесс (ну или на несколько кооперирующихся) в пределах одной машины.
- Права доступа. В MySQL есть пользователи, роли и оператор
GRANT. У SQLite вся система прав сводится к правам ОС на файл базы данных.
Ни одна из схем не «лучше». Они просто решают разные задачи.
Конкурентная запись: SQLite vs MySQL
Вот тут и проходит главная граница между ними. Движок InnoDB в MySQL использует построчные блокировки — десятки соединений могут писать в разные строки одновременно, не мешая друг другу.
SQLite сериализует запись на уровне всей базы. Один писатель в каждый момент времени — и точка. Читатели могут спокойно работать параллельно с писателем (особенно в режиме WAL), но второй писатель встаёт в очередь и ждёт.
-- SQLite: это работает нормально для многих читателей и одного писателя одновременно.
PRAGMA journal_mode = WAL;
-- MySQL: много писателей, мелкозернистая блокировка.
-- (Никакой особой настройки — InnoDB делает это по умолчанию.)
Для приложения с одним-двумя процессами и умеренной нагрузкой на запись — десктопная утилита, мобильное приложение, небольшая CMS — последовательных записей SQLite вам с головой хватит, и вы даже не заметите никаких ограничений. А вот для нагруженного веб-сервиса с сотнями соединений, которые одновременно вставляют заказы или обновляют сессии, построчные блокировки MySQL — это разница между «всё работает» и «всё висит в очереди за одной блокировкой».
Типы данных в SQL
В MySQL типов много, и они строгие: TINYINT, INT, BIGINT, VARCHAR(n), DATETIME, DECIMAL(p,s), BLOB, JSON и ещё с десяток других. Объявили колонку как INT — попытка записать туда строку закончится ошибкой.
SQLite работает иначе — через affinity типов (type affinity). Тип колонки здесь это скорее подсказка, чем жёсткое правило. Хотите положить строку в колонку INTEGER — пожалуйста, SQLite её сохранит (если только вы не включите режим STRICT-таблиц, появившийся в версии 3.37).
Обе строки вставятся без ошибок. Такая гибкость удобна на этапе прототипирования, но удивляет, если ожидаешь от базы строгой типизации. Когда нужна проверка типов в стиле MySQL, используйте таблицы с пометкой STRICT.
Различия в синтаксисе, с которыми столкнётесь на практике
Базовый SQL — SELECT, JOIN, WHERE, GROUP BY — выглядит одинаково. Различия концентрируются вокруг нескольких моментов:
- Автоинкрементные первичные ключи. В SQLite пишут
INTEGER PRIMARY KEY(автоинкремент по умолчанию). В MySQL —INT AUTO_INCREMENT PRIMARY KEY. - Кавычки и идентификаторы. MySQL разрешает обратные кавычки для идентификаторов (
`table`). SQLite, как и предписывает стандарт SQL, использует двойные кавычки ("table"). - Функции для работы с датами. В MySQL есть
NOW(),CURDATE(),DATE_ADD(). В SQLite —datetime('now'),date('now'),datetime('now', '+1 day'). - Синтаксис
LIMIT. КонструкцияLIMIT n OFFSET mработает и там, и там — здесь полная совместимость. - Булевы значения. В MySQL есть тип
BOOLEAN(по сути алиас дляTINYINT(1)). SQLite хранит булевы как0и1в столбцах типаINTEGER.
-- MySQL
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
created_at DATETIME DEFAULT NOW()
);
-- SQLite
CREATE TABLE users (
id INTEGER PRIMARY KEY,
created_at TEXT DEFAULT (datetime('now'))
);
Тот же смысл, но ключевые слова другие. Сама ментальная модель переносится без проблем, а синтаксис придётся слегка подправить.
Производительность: SQLite vs MySQL — смотря что считать
На вопрос «что быстрее — SQLite или MySQL?» нет одного ответа.
Если речь про один процесс, который локально читает и пишет, SQLite чаще всего быстрее — нет сетевого хопа, нет межпроцессного взаимодействия, парсер запросов не крутится в отдельном адресном пространстве. По сути, SELECT в SQLite — это просто вызов функции.
Когда же одновременно пишут много подключений в одну и ту же базу, вперёд выходит MySQL — за счёт построчных блокировок. У SQLite модель «один писатель», и под такой нагрузкой конкуренция за запись (та самая конкурентная запись SQLite) даёт о себе знать почти сразу.
А вот на нагрузке «много чтений, мало записей» с включённым режимом WAL SQLite масштабируется на удивление прилично: читатели не блокируют ни друг друга, ни единственного писателя. Существует немало боевых проектов, которые спокойно отдают реальный трафик из SQLite.
Не выбирайте по бенчмаркам из интернета. Выбирайте по своему реальному паттерну доступа.
Что выбрать — SQLite или MySQL
Берите SQLite, если:
- База живёт рядом с одним приложением (мобильное, десктопное, CLI, небольшой сайт).
- Нужен деплой без настройки — просто положили файл и поехали.
- Чтений сильно больше, чем записей, или записи случаются редко.
- Нужна встраиваемая тестовая база, поведение которой совпадает с продакшеном.
- Вы прототипируете и пока не хочется поднимать сервер.
Берите MySQL, если:
- Несколько серверов приложений работают с одной общей базой.
- Много одновременных писателей.
- Нужны гибкие права пользователей и управление ролями.
- Вы строите систему на стеке (LAMP, типовые managed-облака), который изначально заточен под MySQL.
- Эксплуатационная обвязка — репликация, point-in-time recovery, мониторинг — это жёсткое требование.
Грубое правило: если ваше хранилище описывается фразой «одно приложение, один диск» — скорее всего, SQLite хватит. Если же это «сервис, который кто-то эксплуатирует» — берите MySQL (или PostgreSQL). Это и есть короткий ответ на вопрос «SQLite или MySQL для продакшена».
Миграция с SQLite на MySQL
Стартовать на SQLite и потом перейти на MySQL — путь хорошо протоптанный, и это вполне разумный план. Схемы переносятся с небольшими правками, а данные аккуратно выгружаются командой .dump из CLI SQLite. В основном вам придётся подправить синтаксис автоинкремента, функции работы с датами и специфичные для SQLite вещи (частичные индексы с нетипичной формой, WITHOUT ROWID, таблицы STRICT), у которых нет прямых аналогов в MySQL. Кстати, и базовые типы данных SQL у этих СУБД совпадают далеко не один в один — это второе, на что стоит смотреть при миграции.
Обратное направление — с MySQL на SQLite — встречается реже, но тоже работает: обычно ради офлайн-анализа, встраиваемых копий части данных или тестовых фикстур.
Суть простая: выбор SQLite сегодня не запирает вас в нём навсегда. SQL, который вы пишете, переносится, и ваше понимание базы данных SQL — тоже.
Дальше: SQLite vs PostgreSQL
С MySQL сравнивают чаще всего, но PostgreSQL — вторая база, рядом с которой регулярно ставят SQLite, и там расклад уже совсем другой. Об этом — на следующей странице.
Часто задаваемые вопросы
В чём ключевое отличие SQLite от MySQL?
SQLite — встраиваемая база. Это просто файл, с которым ваше приложение работает напрямую, без отдельного процесса-сервера. MySQL устроена иначе: рядом крутится демон mysqld, слушает порт, а приложение общается с ним по сети. Из этого одного архитектурного различия и вытекают почти все остальные компромиссы между ними.
SQLite быстрее, чем MySQL?
Если речь про один процесс, который читает и понемногу пишет — да, SQLite обычно быстрее: нет ни сетевого round-trip, ни накладных расходов на межпроцессное взаимодействие. Но как только появляется много параллельных писателей, MySQL уверенно вырывается вперёд, потому что SQLite сериализует запись на уровне всей базы. Так что ответ зависит от вашей нагрузки, а не от движков самих по себе.
Когда выбирать SQLite, а когда MySQL?
SQLite хорош для встраиваемых приложений, мобильных и десктопных программ, CLI-утилит, локальных кэшей, тестов и небольших-средних сайтов с одним сервером приложения. MySQL берут, когда несколько серверов приложений должны ходить в одну базу, нужны гранулярные права доступа или нагрузка на запись такая, что без построчных блокировок уже не обойтись.
Можно ли потом мигрировать с SQLite на MySQL?
Да, и это вполне типичный путь. Диалекты SQL сильно пересекаются по CREATE TABLE, INSERT и SELECT, но придётся подправить типы (INTEGER PRIMARY KEY превращается в INT AUTO_INCREMENT), функции работы с датами и специфичные для SQLite штуки вроде WITHOUT ROWID или частичных уникальных индексов. Большую часть работы берут на себя инструменты вроде pgloader и самописные скрипты-дамперы.