Перейти к содержимому
ГоМастер

Поиск по урокам

Найдите урок, курс, термин или раздел

Урок 24 из 25 ~20 мин +50 XP

Сравнение с GORM, ent, squirrel

Тема урока — sqlc vs gorm vs ent: перед итоговым проектом честно выведем sqlc на ринг и посмотрим, против кого он выходил все двадцать три урока. Соседей четверо, и каждый живёт в соседних курсах самоучителя: [GORM](/courses/gorm/) — классическая ORM с моделями-тегами, [ent](/courses/ent/) — графовая ORM с кодогенерацией, sqlx — тонкая надстройка над database/sql, squirrel — билдер SQL для динамики. orm для go сравнение — жанр, в котором обычно побеждает вера, поэтому вместо лозунгов здесь критерии: где ловится ошибка в имени колонки, кто отвечает за миграции, как живёт динамика фильтров, что происходит с N+1 и сколько рантайм-слоя стоит между вашим кодом и драйвером. Ответ «sqlc во всём лучше» — неправда, и урок покажет дни, когда GORM, ent или sqlx честно сильнее. Урок отвечает на пять вопросов. Первый: как устроена карта альтернатив и по какой оси инструменты различаются в принципе. Второй: sqlc vs gorm — разница между «SQL первичен» и «модель первична» на конкретной опечатке. Третий: sqlc vs ent — два генератора с разными источниками правды. Четвёртый: что делают sqlx и squirrel и почему их полезно держать в одной сумке с sqlc. Пятый: алгоритм выбора слоя данных для нового проекта — по команде, по домену, по срокам. План курса — на [странице курса sqlc](/courses/sqlc/); первый набросок этой темы — [урок-знакомство](/courses/sqlc/lessons/01-znakomstvo/).

Содержание урока · 14 разделов

sqlc vs gorm vs ent: карта поля#

Сравнение sqlc vs gorm vs ent, а заодно sqlx и squirrel, ведётся по одному главному вопросу: что является источником правды о данных. У GORM источник правды — структуры с тегами: вы описываете модели, а ORM сам собирает SQL в рантайме по правилам конвенций и тегов. У ent источник правды — схема как код: пакеты ent/schema описывают поля и связи, а генератор строит типобезопасный API запросов. У sqlc источник правды — сам SQL: вы пишете запросы, генератор выводит из них типы и методы. sqlx и squirrel ни на что не претендуют: первый — умный сканер строк из database/sql в структуры, второй — конструктор текста запроса в рантайме; правду они не генерируют, а лишь помогают её исполнять.

Из этого главного вопроса вытекают все остальные различия, и сравнение становится не списком фич, а следствием позиции. Кто первичен — тот и проверяется: у sqlc компилятор-генератор проверяет SQL против схемы до сборки Go-кода; у ent компилятор проверяет построенный API после генерации; у GORM всё, что не проверил компилятор Go, остаётся на рантайме. Кто первичен — тому и миграции: у GORM это AutoMigrate по структурам, у ent — отдельный движок миграций поверх схемы, у sqlc — снаружи, golang-migrate или goose, как в шестнадцатом уроке.

Ограничение рамки, чтобы сравнение было честным: все четыре кандидата — про реляционные базы и database/sql-мир; драйверы pgx, modernc и родня за ними общие. Монго-драйверы, ORM поверх NoSQL и сырые драйверы в этот ринг не входят.

Один запрос четырьмя инструментами

GO
// Задача: выбрать незавершённые задачи по приоритету

// 1) sqlc: запрос — файл db/queries/todos.sql, код сгенерирован
-- name: ListOpen :many
SELECT id, title, priority FROM todos
WHERE done = false AND deleted_at IS NULL
ORDER BY priority;

todos, err := q.ListOpen(ctx)

// 2) GORM: запрос строится в рантайме по модели
type Todo struct {
    ID       int64
    Title    string
    Priority int16
    Done     bool
}
var todos []Todo
err := db.Where("done = ? AND deleted_at IS NULL", false).
    Order("priority").Find(&todos).Error

// 3) ent: запрос строится сгенерированным builder'ом
todos, err := client.Todo.Query().
    Where(todo.Done(false), todo.DeletedAtIsNil()).
    Order(ent.Asc(todo.FieldPriority)).
    All(ctx)

// 4) sqlx: SQL ваш, скан в структуры — библиотеки
var todos []Todo
err := db.Select(&todos,
    "SELECT id, title, priority FROM todos WHERE done = $1", false)

Четыре стиля одной выборки. sqlc: SQL в файле, аннотация :many, сгенерированный метод — единственная строка в вашем коде. GORM: SQL рождается в рантайме из цепочки вызовов, модель описана тегами и конвенциями. ent: builder сгенерирован из схемы — типобезопасно, но на языке ent, а не SQL. sqlx: SQL ваш целиком, библиотека лишь сканирует колонки в поля. Все четыре вернут одинаковый срез — разница в том, кто и когда поймает ошибку, если колонка в схеме зовётся иначе.

Проверка: кто поймает опечатку в колонке

В таблице колонка называется priority, а в коде по ошибке написано priorty. Кто из инструментов поймает это раньше всего?

sqlc vs gorm: где ловится ошибка#

Сравнение sqlc vs gorm — это столкновение двух определений удобства. GORM удобен, когда модель уже есть: описал структуру с тегами — и CRUD появился сам, включая ассоциации, хуки и миграцию AutoMigrate, которая достроит таблицы по структурам. Цена — двойная потеря контроля. Первая: SQL строится в рантайме, и «что за запрос уйдёт в базу» — вопрос рефлексии, конвенций имён и тегов; разница между Save и Updates, мягкое удаление с deleted_at, полуавтоматические обновления updated_at — всё это правила, которые надо знать наизусть. Вторая: ошибки типов между моделью и таблицей ловит не компилятор, а база — а она отвечает только в рантайме, у конкретного пользователя.

sqlc идёт с другого конца: удобство наступает, когда запрос уже написан. Вы не описываете модель — её выводит генератор из SQL и схемы; не строите WHERE — вы его пишете; не включаете лог SQL, чтобы понять, что уехало в базу, — потому что запрос лежит в файле и едет на ревью как текст. Цена симметрична: пока запроса нет, в sqlc ничего нет — прототип «просто сохраняй структуру» на голом энтузиазме не собирается, каждую выборку надо оформить аннотацией и перегенерировать.

Экономика ошибки — решающий аргумент этой пары. Опечатка в колонке у GORM живёт до первого исполнения пути кода: тест не покрыл — на прод. У sqlc она не переживает generate: CI роняет пайплайн за минуты. Но и тут честность: GORM имеет сырой выход — db.Raw и Exec — и тот же мир SQL доступен и в ORM-проекте, как показывал десятый урок GORM; только проверять эти raw-запросы его генератор, в отличие от sqlc, никак не будет.

Предскажите поведение GORM-кода с опечаткой

Прочитайте код и выберите, что он выведет:

type Todo struct {
    ID    int64
    Title string
    Done  bool
}

var open []Todo
err := db.Where("don = ?", false).Find(&open).Error
// в таблице todos колонка называется done; deleted_at у модели нет

sqlc vs ent: два генератора, две философии#

sqlc vs ent — пара ближе, чем кажется: оба генерируют код, оба переносят проверки на этап до рантайма, оба живут с кодогенерацией в CI. Разница — в направлении генерации. ent растёт из модели: вы описываете сущности и связи — edges — в схеме как код, генератор строит и типы, и API запросов, и миграции под эту схему; SQL остаётся делом ent. sqlc растёт из запросов: схема задана SQL-миграциями, запросы написаны SQL-ом, генератор выводит только типы и методы; запрос остаётся делом автора.

Отсюда практические следствия. Сложные связи — forte ent: many2many, сквозные графы, жадная загрузка With* на три уровня — в ent это одна цепочка, а в sqlc каждый запрос с джойнами вы пишете сами, как в двенадцатом уроке. Произвольные выборки — forte sqlc: оконные функции, CTE, специфичные для движка конструкции ent либо не выражает builder'ом, либо выражает через Raw, теряя проверку; в sqlc любой SQL, который поймёт парсер движка, становится типизированным методом. Девятый урок ent показывает, как приятен его builder, когда запрос вписывается в граф; пятнадцатый урок этого курса — как больно без оконных функций, если бы sqlc их не умел.

И про команду: ent-схема — это новый язык проекта, который надо учить всем; sqlc-запросы — это SQL, который команда и так знает. Обратная сторона: ent документирует модель кодом — по пакетам ent/schema видна вся картина данных; в sqlc-проекте карту данных собирают из миграций.

sqlx и squirrel: надстройки без амбиций#

Двое из четверки не претендуют на роль слоя данных — и именно поэтому полезны в любом проекте. sqlx — это database/sql с приятностями: Select и Get сканируют строки в структуры по тегам db, NamedQuery даёт именованные параметры, Rebind чинит плейсхолдеры между движками, In собирает список под IN. SQL вы пишете сами — sqlx ничего не генерирует и схему не знает; его роль — убрать из вашего кода ручной Scan на тридцать колонок. Ловушка единственная, но знаменитая: тег db с опечаткой не совпадает ни с одной колонкой — и sqlx по умолчанию молча оставит поле нулевым; защита — sqlx.Strict() или дисциплина тестов, а компилятор здесь не поможет никогда: теги не проверяются.

squirrel — конструктор текста запроса: sq.Select().From().Where() собирает SQL и аргументы в рантайме, сохраняя параметризацию. Его жанр — та самая динамика, которую статический sqlc не умеет: произвольные комбинации фильтров, условные JOIN, сборка отчётных запросов по частям. Он не сканирует, не знает схему и не проверяет ничего — выход squirrel это строка и аргументы, которые дальше едут в Exec или в QueryContext.

Почему оба живут в одной сумке с sqlc. sqlx может заменить скучный слой сканирования там, где sqlc не генерирует запросы — например, в редких динамических отчётах. squirrel закрывает динамику вместо COALESCE-хаков, когда комбинаций фильтров слишком много. Оба инструмента дружат с тем же *sql.DB или pgx-пулом, что и сгенерированный пакет: вы выбираете инструмент по запросу, а не по проекту.

orm для go сравнение: sqlc, GORM, ent, sqlx#

КритерийsqlcGORMentsqlx
Источник правдыSQL-файлы и миграцииструктуры с тегамисхема как код (ent/schema)нет — SQL ваш
Когда ловится опечатка в колонкеsqlc generate, до сборкирантайм, ошибка от базыкомпиляция после генерациирантайм; тег db — может молча
Кто пишет SQLвы — всегдаORM, кроме Rawent, кроме Rawвы — всегда
Динамические фильтрыCOALESCE-паттерн, sqlc.sliceбилдер в рантаймепредикаты And/Or/Notвручную или с squirrel
Миграцииснаружи: golang-migrate, gooseAutoMigrate по структурамвстроенные, atlas для версионныхснаружи, как у sqlc
Жадная загрузка связейджойн или второй запрос рукамиPreloadWith* на всю глубинуруками
Рантайм-слой над драйверомнет — только database/sql или pgxесть: рефлексия, хуки, конвенцииесть: сгенерированный, без рефлексиинет, кроме скана
Проверка SQL против схемыкаждый generateнетнет (SQL строит ent)нет
Кривая входанужен уверенный SQLнизкая: модели и конвенциисредняя: учить схему и builderнизкая при знании SQL
Лучший жанрсервисы со сложными выборкамибыстрый CRUD, прототипыдомены со сложными связямитонкий слой поверх SQL

Проверка: сценарий и выбор

Стартап строит MVP каталога: CRUD на пять таблиц, связи один-ко-многим, схему ещё наверняка менять, SQL-навыки команды — базовые. Какой инструмент даст самый быстрый честный старт?

Динамика запросов: главный аргумент против sqlc и ответ#

Самый честный минус sqlc в любом orm для go сравнение — статичность. Запросы живут в файлах, генерация фиксирует их структуру, и «собрать WHERE из произвольного набора фильтров» в лоб не выходит: нельзя конкатенировать строки в query.sql и скормить генератору. GORM и ent решают это цепочками вызовов, squirrel — сборкой текста; sqlc предлагает три пути, и все три уже разобраны в пятнадцатом уроке.

Первый — COALESCE-паттерн: один статический запрос, в котором каждый фильтр вежлив к пустому параметру — WHERE ($1 = '' OR title ILIKE '%' || $1 || '%'). Дискретные комбинации фильтров на два-три поля закрываются им без единой строки динамики. Второй — sqlc.slice и ANY($1::int[]) для списков id: черные дыры «IN с переменным числом аргументов» перестают существовать. Третий — признать границу: отчётный конструктор с двадцатью комбинациями условий — работа для squirrel или сырого pgx, и это нормально: 5 процентов запросов проекта могут жить вне sqlc, при этом 95 процентов остаются проверяемыми генератором.

Сравните экономику с GORM-путём. Там динамика бесплатна в коде, но каждый такой запрос — невидимка: ни схема его не проверяет, ни ревью не видит текст SQL. Здесь динамика стоит одного декоративного OR-условия в SQL, но запрос остаётся документированным, проверенным и переиспользуемым. Ошибка «наш фильтр сломал план» ловится vet-правилом из двадцать третьего урока — в ORM-мире тот же баг найдёт только мониторинг.

COALESCE-фильтр против динамического билдера

GO
-- sqlc-путь: один статический запрос на все комбинации фильтров
-- name: SearchTodos :many
SELECT id, title, priority, done
FROM todos
WHERE deleted_at IS NULL
  AND ($1::int IS NULL OR priority = $1::int)
  AND ($2::text = '' OR title ILIKE '%' || $2::text || '%')
  AND ($3::boolean IS NULL OR done = $3::boolean)
ORDER BY priority, id
LIMIT 50;

// GORM-путь: WHERE собирается по условию
q := db.Model(&Todo{}).Where("deleted_at IS NULL")
if filter.Priority != nil {
    q = q.Where("priority = ?", *filter.Priority)
}
if filter.Title != "" {
    q = q.Where("title ILIKE ?", "%"+filter.Title+"%")
}
err := q.Limit(50).Find(&rows).Error

Две стратегии одной задачи. sqlc: вся динамика переехала в SQL через NULL-параметры — генератор выведет Params с указателями и sql.Null-типами, план запроса один, vet его проверит. GORM: код гибче, но SQL не существует нигде в виде текста — его собирает рантайм, и регрессия «забыл deleted_at IS NULL» не поймается ничем, кроме теста. Выбор — между проверяемой статикой и гибкой сборкой; середина — squirrel для этого одного запроса и sqlc для остальных.

Допишите фильтр, который делает sqlc динамичным

Заполните пропуски COALESCE-паттерна: проверка пустоты параметра, оператор сопоставления и обёртка паттерна LIKE.

-- name: FindUsers :many SELECT id, name FROM users WHERE 1 = 1 AND ($1::text = OR name ILIKE || $1::text || '%') AND (($2::int) OR age = $2::int);

Миграции и N+1: что каждый инструмент делает за вас#

Две обязанности слоя данных, в которых различия не менее остры, чем в запросах. Миграции: GORM несёт AutoMigrate — структуру изменил, база достроена при старте; соблазнительно для MVP и обсуждаемо для прода: документация GORM прямо не рекомендует AutoMigrate как единственный способ ведения версионной схемы, а история изменений в git — это история из дифов структур, а не читаемый SQL. ent подходит серьёзнее: собственная миграционная система с atlas, versioned migrations и ревью файлов. sqlc миграций не делает вообще — это решение шестнадцатого урока: golang-migrate или goose ведут SQL-файлы, а sqlc честно проверяет по ним каждый запрос. Формула ясная: у GORM миграции — конвенция, у ent — продукт, у sqlc — соседний инструмент, и в двух случаях из трёх вы всё равно упрётесь в SQL-миграции, как только понадобится перенос данных, а не только DDL.

N+1 — вторая обязанность. GORM умеет Preload: один вызов переложит «задачи с авторами» в два SQL-запроса; ent — With*, сгенерированные жадные загрузки на любую глубину. У sqlc нет ничего — потому что и не нужно: связь двух таблиц — это JOIN, который вы пишете в запросе, и план у него один, а не два; связь «список + детали» — второй запрос с ANY. Проблема N+1 в sqlc-мире не исчезает — она переезжает в ваши руки: слепую выборку в цикле вы устроите сами, и ни Preload за вас её не вытянет. Зато ни один из сгенерированных методов не спрячет от вас лишний запрос — текст каждого на экране.

Проверка: мифы о sqlc

Какое из четырёх утверждений о сравнении инструментов — правда?

Предскажите поведение sqlx с опечаткой в теге

Прочитайте код и выберите, что он выведет:

type User struct {
    ID    int64
    Email string `db:"mail"`   // в таблице колонка называется email
}

var u User
err := db.Get(&u, "SELECT id, email FROM users WHERE id = $1", 42)

Производительность и рантайм-слой#

Производительность слоя данных складывается из двух частей: во что превращается ваш код и во что превращается SQL-запрос. Со второй частью все четыре инструмента равны: SQL исполняет база, и разница между «ORM построил плохой JOIN» и «вы написали плохой JOIN» — в виновнике, а не в цене. Первая часть различается по-настоящему.

sqlc не имеет рантайм-слоя: сгенерированный метод — это строка запроса, пачка аргументов и вызов QueryContext с ручным сканом в структуру — как будто вы написали database/sql-код сами. ent генерирует код без рефлексии: builder собирает запрос вызовами методов, цена — в порядке простых операций; overhead заметен на построении, а не на исполнении. GORM — единственный из четверки с рефлексией в рантайме: модели читаются тегами и полями на каждом вызове, отсюда честные расходы на построение каждого запроса и знаменитые сюжеты про «ORM медленный», большинство которых на деле — про N+1 и неудачные Preload, а не про рефлексию. sqlx почти голый: скан структур — его единственная работа.

Практический вывод скучен и важен: на типичном веб-сервисе разница рантайм-слоев — микросекунды на фоне миллисекунд сети и диска. Выбирайте не по микробенчмарку построения запроса, а по тому, чьи запросы лучше: плохой план от ручного SQL дороже любого overhead, а vet и мониторинг из двадцать третьего урока нужны sqlc-проекту не меньше, чем GORM-проекту — просто у sqlc хотя бы текст запроса всегда под рукой.

DX и команда: цена входа и цена выхода#

Developer experience — категория времени, и у каждого инструмента она двуликая: цена входа и цена жизни. GORM даёт самую низкую цену входа: модели, конвенции, готовый CRUD — разработчик без SQL пишет работающий слой в первый день. Цена жизни — накопленная: нюансы Save и Updates, сюрпризы Preload с кастомными условиями, поведение мягкого удаления, отладка «какой SQL ушёл в базу» — всё это платят коллеги через полгода, и платят чаще там, где SQL-культура слабее, потому что инструмент её не требует.

sqlc наоборот: вход дорог — нужен уверенный SQL, аннотации, понимание типов и NULL-семантики; первых два дня команды без SQL-опыта проходят больно. Цена жизни — низкая и стабильная: запросы читаются в ревью как текст, ошибки ловятся на generate, новые люди изучают домен, читая SQL. Хозяйственный бонус: SQL-навыки, которые команда прокачивает в sqlc-проекте, переносятся — это не внутренний язык инструмента, а профессия. ent занимает середину: учить надо схему и builder, зато дальше компилятор ведёт за руку, а по пакетам ent/schema новичок читает карту домена быстрее, чем по папке миграций.

И организационный фактор — найм и ревью. SQL знают и мидлы, и сеньоры; ent-схему придётся объяснять каждому новому человеку; GORM-конвенции неявно требуют прочтения документации. В ревью sqlc-PR показывает SQL и код рядом — обсуждение запроса предметно; ORM-PR показывает цепочки вызовов, и «что уйдёт в базу» остаётся догадкой до запуска. Для команды, где SQL — сила, sqlc превращает эту силу в архитектуру; для команды, где её нет, GORM честнее признает этот дефицит и не будет его наказывать.

Алгоритм выбора слоя данных

Расставьте шаги выбора инструмента для нового проекта.

Строки

Ваша программа

Нажимайте на строки слева, чтобы собрать программу

Комбинации в одном проекте и когда sqlc — не выбор#

Инструменты слоя данных не являются моногамными: соединение одно, а слои могут быть разными. Рабочие гибриды встречаются постоянно. sqlc плюс squirrel: 95 процентов запросов — сгенерированные методы, редкий отчётный конструктор собирает SQL в рантайме и едет через то же соединение. sqlc плюс GORM: домен, рождённый прототипом, живёт в GORM, а тяжёлые выборки постепенно переезжают в sqlc-пакет — миграция слоя данных без остановки разработки. ent плюс Raw: граф закрывает 90 процентов, экзотические оконные функции идут через raw. Общая химия одна: у всех общий пул соединений и общий мир типов database/sql, сгенерированный пакет от соседей не зависит.

Но и честные дни, когда sqlc — неправильный выбор. Динамические отчётные системы, где пользователь собирает произвольные запросы из сотен полей, — там статические файлы не выживут, и его место займёт билдер. Проект без SQL-культуры на старте — sqlc потребует того, чего у команды нет, и не даст взамен скорости прототипа. Быстрый disposable-скрипт на две таблицы — генерация и аннотации дороже задачи. И команды, чей домен — глубоко вложенные связи с политиками доступа на графе, найдут ent роднее: там граф — не надстройка, а модель мышления.

Формула урока: sqlc выигрывает там, где SQL сложный, стабильный и дорогой в ошибках — сервисы, платёжные домены, аналитические выборки. GORM выигрывает там, где сложность в скорости разработки, а не в запросах. ent — где сложность в связях. sqlx — везде, где вы и так пишете SQL и не хотите платить за скан.

Финальная рамка выбора и мост к проекту#

Соберём двадцать четыре урока в одну рамку. Источник правды определяет всё: SQL-файлы у sqlc дают проверку на generate и SQL-грамотность как актив команды; структуры у GORM дают скорость входа и рантайм как место ошибок; схема как код у ent даёт граф и компилятор ценой нового языка; надстройки sqlx и squirrel дают честный ноль магии. Динамика, миграции, N+1 и производительность — следствия этой позиции, а не независимые фичи. Решение стоит принимать по команде и домену, фиксировать в ADR и пересматривать при смене фазы — гибриды легальны.

Для трекера задач из этого курса ответ уже принят: SQL здесь сложный, команда — вы, и вы двадцать три урока прокачивали SQL-first-мир. Осталось доказать делом. Двадцать пятый, итоговый урок — репозиторий задач целиком: миграции, queries, транзакции, HTTP-хендлеры и тесты в одном проекте, где каждый слой из этих уроков займёт своё место. sqlc проект соберётся из деталей, которые вы уже знаете, — урок лишь расставит их по полкам.

Карточки: sqlc против альтернатив

Термин

Главный вопрос, по которому различаются sqlc, GORM и ent?

нажмите, чтобы перевернуть
Определение

Источник правды: у sqlc — SQL-файлы, у GORM — структуры с тегами, у ent — схема как код; из этого следуют проверки, миграции и стиль запросов

1 / 6

Песочница урока

Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.

Вывод

Запустите код, чтобы увидеть вывод.

Коротко: что запомнить

  • Критерий сравнения один — источник правды: SQL-файлы (sqlc), структуры с тегами (GORM), схема как код (ent), отсутствие претензий у надстроек (sqlx, squirrel).
  • sqlc vs gorm: опечатка в колонке у sqlc ломает generate до сборки, у GORM — рантайм от базы; sqlc не имеет рантайм-слоя, GORM платит рефлексией и конвенциями, raw-выход — db.Raw.
  • sqlc vs ent: оба генерируют и оба переносят проверки до рантайма; ent силён на связях и графе (With*, миграции atlas), sqlc — на произвольных выборках и SQL как навыке команды.
  • sqlx — скан без магии (тихая ловушка тега db), squirrel — билдер для динамики; оба легально живут в одном проекте со sqlc через общее соединение.
  • Динамика у sqlc — COALESCE-паттерн, sqlc.slice и выход на squirrel; миграции — golang-migrate/goose; N+1 — ваша ответственность в JOIN-ах и вторых запросах.
  • Выбор — по команде и домену, а не по микробенчмарку: сложные стабильные выборки — sqlc, быстрый CRUD — GORM, граф связей — ent, тонкий слой — sqlx; гибриды фиксируются в ADR.

Домашнее задание

Первое: напишите один и тот же запрос тремя способами — sqlc-аннотацией, GORM-цепочкой и sqlx-строкой — и сломайте его опечаткой в колонке: соберите таблицу, кто что сказал и когда; зафиксируйте вывод в шпаргалку. Второе: возьмите панель фильтров из пятнадцатого урока и оцените её честно: сколько комбинаций закрыл COALESCE-паттерн, где начался squirrel; напишите один отчётный запрос squirrel'ом через то же соединение, что и sqlc-пакет. Третье: посчитайте N+1 на пальцах: выборка задач с авторами через sqlc (JOIN) и через GORM (без Preload и с Preload) — распечатайте SQL каждого варианта и объясните разницу планов. Четвёртое: оформите ADR на полстраницы: ваш проект, ваша команда, ваш домен — что выберете и по каким трём критериям; перечислите условия, при которых решение пересматривается. Пятое: прочитайте десятый урок GORM про Raw и сравните с sqlc: где raw-запросы проверяются, а где нет; напишите абзац, что это значит для проекта с сотней raw-вызовов.

Личные заметкиПусто
Хранятся только в вашем браузере (sqlc · Сравнение с GORM, ent, squirrel)

Вопросы и ответы по уроку

sqlc быстрее GORM — стоит ли менять слой данных ради производительности?

Ради одного только рантайма — почти никогда: у sqlc нет слоя над драйвером, а у GORM есть рефлексия, но разница — микросекунды на фоне сети и плана запроса. Реальные различия скорости делают запросы, а не инструменты: N+1 и плохие планы дороже любой рефлексии. Переезд с ORM на sqlc оправдан, когда важнее другое: проверка запросов на generate, читаемые в ревью SQL и контроль плана — производительность приходит следствием, а не причиной.

Можно ли использовать sqlc и GORM в одном проекте?

Да, и это рабочий паттерн для эволюции: соединение общее — *sql.DB или pgx-пул удовлетворяет и DBTX сгенерированного пакета, и GORM. Типичная схема: легаси-CRUD остаётся в GORM, сложные и горячие выборки переезжают в sqlc-пакет с проверкой на generate и vet. Следите за границами ответственности в ревью и за тем, чтобы у каждой таблицы был один владелец-инструмент — иначе schema_истина размажется между тегами моделей и миграциями.

Что выбрать начинающему: sqlc или ORM?

Зависит от цели. Если цель — быстрее получить работающий CRUD и продукт, GORM честнее: конвенции и AutoMigrate убирают барьер SQL. Если цель — стать сильным бэкенд-инженером, sqlc превращает каждое изменение данных в урок SQL: запросы придётся писать, читать и оптимизировать, а generate и vet не дадут врать. Середина: начните с ORM, а первую настоящую выборку с джойнами и пагинацией напишите уже на sqlc — вы почувствуете разницу на собственной задаче.

Термины урока

Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.

Сравните с альтернативами

Практический вопрос после первых уроков: а почему именно эта библиотека? Мы разобрали конкурентов по одним критериям, с кодом одной задачи рядом и персональным подбором под ваши приоритеты.

Следующая ступень учебного пути

ent25 уроков~13 чпрактика25 уроков уже доступны

ent: графовая ORM с кодогенерацией

Курс ent: схемы, поля, связи, запросы, хуки, privacy, миграции и GraphQL. 25 уроков с примерами и проектом микроблога.

  • Проектировать схемы и связи в ent
  • Генерировать код и жить с кодогенерацией
  • Писать запросы builder-стилем с типами
  • Строить хуки, интерсепторы и privacy-правила