Введение в базы данных
Этот модуль нужен, чтобы backend-разработчик уверенно работал с данными, а не просто перекладывал JSON из HTTP в таблицу. База данных отвечает за факты, ограничения, транзакции, конкурентный доступ, поиск, хранение истории и восстановление после сбоев.
Основной фокус будет на SQL и PostgreSQL, потому что это базовый инструмент для большинства Go-сервисов. Но важно не заучить синтаксис, а понять, какие гарантии даёт база, где она помогает приложению, а где требует аккуратного проектирования.
Что будет внутри
Разберём реляционную модель, SQL, нормализацию, транзакции, уровни изоляции, MVCC, индексы, planner, production-возможности PostgreSQL, работу из Go через pgx, sqlc, Squirrel и обзор других типов баз.
Общая логика модуля:
data model -> constraints -> transactions -> indexes -> Go access layer -> production behavior
Production map
В production база почти всегда оказывается не "деталью хранения", а границей надежности сервиса. Ошибка в handler можно откатить релизом, а ошибка в данных часто живет дольше кода: она попадает в отчеты, расчеты, кэш, события, интеграции и ручные операции поддержки.
В этом модуле будем смотреть на базу через несколько рабочих вопросов:
| Область | Что может сломаться | Что должен видеть backend-разработчик |
|---|---|---|
| Модель данных | дубли, невозможные статусы, потеря истории | сущности, ключи, constraints, source of truth |
| Запросы | медленные страницы, N+1, нестабильная пагинация | план запроса, индексы, объем данных, порядок сортировки |
| Транзакции | lost update, гонки, двойное списание, read skew | границы транзакции, isolation level, retry policy |
| Миграции | блокировки, долгий backfill, несовместимые версии приложения | expand-contract, батчи, rollback, validation |
| Доступ | утечки чужих данных, широкие права service account | tenant/user predicates, least privilege, audit trail |
| Эксплуатация | рост таблиц, bloat, истощение pool'а, неясные ошибки | метрики, slow queries, connection pool, понятный error mapping |
Такой взгляд нужен не для усложнения каждого маленького CRUD. Он помогает заранее заметить места, где простое решение перестает быть безопасным при росте данных, параллельных запросах, ретраях и нескольких версиях приложения.
Связь с RateDesk
В проекте уровня RateDesk база становится источником истины для курсов, провайдеров, правил выбора ставки, статусов заявок и аудита решений. Для такой системы важно не только "сохранить курс", но и ответить на production-вопросы:
- какая запись является фактом от провайдера, а какая - расчетным решением сервиса;
- как запретить две активные настройки для одного валютного направления;
- как сохранить историю изменения ставки и не перетереть ее очередным импортом;
- как отличить "курс не найден" от "провайдер временно недоступен";
- как доказать в разборе инцидента, какой курс и какая версия правила были использованы.
Статьи модуля будут давать теорию для таких решений: где помогает нормализация, где нужен snapshot, почему constraints важнее "проверили в Go", как читать планы запросов и как проводить миграции без долгих блокировок.
Как понять, что освоил
Вы освоили модуль, если можете спроектировать простую схему, написать запрос с join и агрегацией, объяснить аномалии транзакций, подобрать индекс под запрос, прочитать базовый query plan и выбрать адекватный способ работы с PostgreSQL из Go.
Рабочие ориентиры
- Constraints в базе не дублируют бизнес-логику, а защищают данные от неконсистентных состояний.
- Индекс нужен под конкретный запрос и профиль нагрузки, а не "на всякий случай".
- Хорошая модель данных обычно переживает несколько версий приложения. Её стоит проектировать медленнее, чем handler.
- Миграция - это часть релиза: у нее должны быть совместимость, проверка результата и план отката.
- Ошибка базы должна маппиться в понятное поведение API, а не превращаться по умолчанию в
500.