Какие плюсы и минусы у raw SQL и ORM
Что проверяют
Умеете ли вы выбирать инструмент под задачу, а не защищать один подход. Хороший ответ показывает, что в одном проекте нормально жить с ORM и точечным SQL. Следом спросят, как вы безопасно передаёте параметры в сырой запрос.
Как отвечать
Держите три уровня, а не два: ORM (Django ORM, SQLAlchemy ORM), построитель запросов (SQLAlchemy Core) и сырой SQL через драйвер (psycopg 3, asyncpg).
ORM:
- плюсы: модели и миграции в одном месте, переиспользуемые фильтры, параметризация по умолчанию, меньше шаблонного кода для CRUD;
- минусы: SQL скрыт, и неэффективный запрос легко не заметить. Создание объектов заметно стоит на десятках тысяч строк. Часть возможностей PostgreSQL в Django ORM без сторонних пакетов не выразить, например рекурсивные CTE и
LATERAL.
Сырой SQL:
- плюсы: полный контроль над запросом, любые возможности СУБД, запрос можно скопировать в
psqlи прогнатьEXPLAIN ANALYZEкак есть; - минусы: ручной маппинг результатов, никакой проверки при переименовании колонки, риск инъекции при склейке строк, SQL размазан по коду.
Практичная граница: CRUD и бизнес-логика через ORM, отчёты, аналитика и массовые операции на сыром SQL или Core. Для пачек есть bulk_create и executemany, для миллионов строк COPY через cursor.copy() в psycopg 3.
Параметры в сыром SQL передаются отдельно от текста: %s и кортеж аргументов в psycopg, $1 в asyncpg, text() с именованным :id в SQLAlchemy. В Django это Model.objects.raw() или connection.cursor(), правила там те же.
Где спотыкаются
Подставляют значения через f-строку, потому что так нагляднее. Это SQL-инъекция, даже если сейчас значение приходит из вашего же кода.
Утверждают, что raw SQL всегда быстрее. Одинаковый SQL выполняется за одинаковое время, разница только в маппинге и в том, насколько удачно написан сам запрос.
Уходят в сырой SQL и забывают про транзакции и пул соединений, которые раньше брала на себя ORM. В итоге каждое обращение открывает новое подключение.