Введение в базы данных

Этот модуль нужен, чтобы backend-разработчик уверенно работал с данными, а не просто перекладывал JSON из HTTP в таблицу. База данных отвечает за факты, ограничения, транзакции, конкурентный доступ, поиск, хранение истории и восстановление после сбоев.

Основной фокус будет на SQL и PostgreSQL, потому что это базовый инструмент для большинства Go-сервисов. Но важно не заучить синтаксис, а понять, какие гарантии даёт база, где она помогает приложению, а где требует аккуратного проектирования.

Что будет внутри

Разберём реляционную модель, SQL, нормализацию, транзакции, уровни изоляции, MVCC, индексы, planner, production-возможности PostgreSQL, работу из Go через pgx, sqlc, Squirrel и обзор других типов баз.

Общая логика модуля:

text
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 accounttenant/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.