Почему я ставлю strict tables в sqlite по умолчанию
SQLite кажется простой и удобной базой, но именно в этой простоте часто прячется проблема: типы данных могут вести себя слишком свободно. Я предпочитаю включать STRICT tables по умолчанию, потому что они ловят ошибки сразу, а не через пару недель в продакшене.
Что такое strict tables и зачем они нужны
Обычная таблица в SQLite — это почти полная свобода. Можно объявить колонку age INTEGER, а потом записать туда строку 'garbage'. База это проглотит. В STRICT-таблице такой трюк уже не пройдёт: если тип не совпадает, запись завершится ошибкой.
Это особенно полезно там, где схема базы — не формальность, а контракт. Если колонка должна хранить число, база должна это проверять, а не надеяться на аккуратность приложения.
Как это работает на практике
В SQLite есть приведение типов, или affinity: база пытается угадать, что вы имели в виду, и автоматически преобразовать значение. Для прототипов это удобно. Для боевых систем — источник тихих ошибок.
STRICT tables отключают эту магию. Разрешены только явные типы: INT, INTEGER, REAL, TEXT, BLOB и ANY. Никаких неявных сюрпризов, никаких опечаток вроде BLOBB.
ТАБЛИЦЫ С ТИПАМИ ──────────────── Нестрогая таблица Строгая таблица (STRICT) ┌─────────────────┐ ┌─────────────────┐ │ age │ value │ │ age │ value │ ├─────────────────┤ ├─────────────────┤ │ 25 │ "25" │ │ 25 │ 25 │ │ old │ "garbage" │ │ ERR │ ERR │ │ 30 │ "thirty" │ │ ERR │ ERR │ └─────────────────┘ └─────────────────┘ Тип колонки: INTEGER Тип колонки: INTEGER
Когда strict tables особенно полезны
Импорт данных. Если вы загружаете CSV, данные из legacy-системы или ответ внешнего API, STRICT помогает быстро заметить грязные значения, которые иначе тихо испортят аналитику.
Миграции. Когда схема меняется, строгая таблица не даст случайно протолкнуть несовместимые данные. Ошибка проявится сразу, а не после деплоя.
Контракты между сервисами. Если несколько компонентов пишут в одну базу, тип колонки становится частью контракта. STRICT делает этот контракт явным.
ВЫБОР СТРАТЕГИИ
───────────────
Нужна гибкость? Нужна надёжность?
───────────────── ─────────────────
Прототип ▶ Обычные таблицы STRICT (с ANY)
Импорт CSV ▶ Обычные таблицы STRICT + очистка
Продакшен ▶ ??? STRICT по умолчанию
Key-value ▶ Обычные таблицы STRICT (с ANY)
Где есть компромиссы
Если вам нужно хранить значения разных типов в одной колонке, для этого есть ANY. Это честный способ сказать базе: «Здесь допустимы разные форматы».
Главное ограничение — нельзя просто так включить STRICT у существующей таблицы. Обычно приходится создавать новую таблицу, переносить данные и переименовывать её. Если в старых данных есть ошибки, миграция сразу об этом сообщит.
Ещё один момент — совместимость по версиям. Клиент SQLite старее 3.37.0 может не открыть базу со STRICT-таблицами.
Мой вывод
STRICT tables — не сложная новая парадигма, а простой способ сделать схему базы честной. Если таблица хранит не временный мусор, а данные системы, я предпочитаю включать строгий режим.
Это как strict mode в JavaScript или type hints в Python: без них можно жить, но с ними ошибки становятся гораздо заметнее и дешевле.
Ссылки
- Оригинальная статья Evan Hahn — Prefer STRICT tables in SQLite — статья, с которой начинается обсуждение
- Документация SQLite — Flexible Typing — описание гибкой типизации SQLite
- SQLite 3.37.0 Release Notes — релиз, в котором появились STRICT tables
Дмитрий Полухин — продуктовый дизайнер. Пишу про разработку, AI и дизайн интерфейсов. Обо мне, контакты и профили.