Плюсы и минусы написания запросов с ORM и на SQL

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

SQL против ORM — один из самых горячих споров среди разработчиков. Одни уверены, что писать SQL-запросы вручную — это гарантия контроля и эффективности. Другие считают, что ORM упрощает жизнь и снижает вероятность ошибок. А что, если правда где-то посередине?

В этой статье я разберу плюсы и минусы обоих подходов, рассмотрю реальные примеры уязвимостей, производительности и удобства сопровождения кода. Почему SQL-инъекции до сих пор остаются проблемой? Когда ORM становится тормозом, а когда — спасением? Правда ли, что ORM — это просто «модная игрушка», или же он стал стандартом разработки? Давайте разберемся, а заодно — подискутируем в комментариях.

Содержание

  1. Проблемы с SQL-запросами

  2. Преимущества ORM

  3. Ошибки при работе с ORM

  4. Когда стоит использовать чистый SQL?

  5. Комбинирование ORM и SQL

  6. Как проверять, какие SQL-запросы генерирует ORM?

  7. Тренды: уходит ли ORM в прошлое?

  8. Выводы

Проблемы с SQL-запросами

SQL-инъекции

Рассмотрим простой SQL-запрос:

def get_user(conn, user_id):
    return conn.execute(
        f"""
        SELECT * FROM users WHERE id = {user_id}
        """
    )

В чем проблема? Этот код уязвим для SQL-инъекции. Если user_id содержит вредоносный SQL-код, например:

1; DROP TABLE users;

То запрос превратится в:

SELECT * FROM users WHERE id = 1; DROP TABLE users;

В результате можно потерять всю таблицу!

Конечно тут дело не в том, что мы используем SQL, а просто ошибка разработчика, который неверно передал параметр в запрос.

Решение – использовать плейсхолдеры:

def get_user(conn, user_id):
    return conn.execute(
        "SELECT * FROM users WHERE id = ?",
        (user_id, )
    )

Сложность формирования SQL-запросов

Допустим, у нас есть фильтрация по нескольким параметрам:

def get_books(conn, name, author):
    query = "SELECT * FROM books"
    where = []
    if name:
        where.append(f"name = '{name}'")
    if author:
        where.append(f"author = '{author}'")
    if where:
        query += " WHERE " + " AND ".join(where)
    return conn.execute(query)

Здесь сразу две потенциальные проблемы:

  • SQL-инъекции.

  • Сложность формирования строки запроса.

Чем больше условий, тем сложнее читать и поддерживать код.

Преимущества ORM

Безопасность

ORM автоматически подставляет параметры запросов, снижая риск SQL-инъекций:

def get_user(user_id):
    return User.objects.filter(id=user_id).first()

Удобство написания запросов

Пример выборки книг с ORM:

def get_books(name=None, author=None):
    query = Book.objects.all()
    if name:
        query = query.filter(name=name)
    if author:
        query = query.filter(author=author)
    return query

Запрос читается проще, а ORM сам оптимизирует его под конкретную БД.

Автоматизация миграций

Django и SQLAlchemy поддерживают автоматическое создание миграций, упрощая управление схемой БД.

Low-code возможности

ORM позволяет быстро создавать админ-панели, например, Django Admin или Flask-Admin.

Ошибки при работе с ORM

Не всегда ORM-запросы оптимальны. Например:

users = User.objects.all()
for user in users:
    print(user.profile)

Это вызовет проблему Query N+1. Нужно использовать select_related:

users = User.objects.select_related("profile").all()

Чтобы эффективно использовать ORM, нужно хорошо понимать как он работает. Нет смысла просто ругать ORM. Использование ORM не отменяет того, что вам нужно также отлично знать SQL и внутреннее устройство БД.

Многие начинающие ошибочно думают, что ORM — это абстракция, которая позволяет не изучать SQL. Это не так.

Когда стоит использовать чистый SQL?

Иногда SQL предпочтительнее:

  • Для сложных запросов, которые ORM не поддерживает или это сервис без миграций и админки, а предназначен только для выполнения больших сложных запросов например, для формирования отчетов.

  • Если ORM генерирует неэффективные запросы и не поддерживает нужные SQL-конструкции.

  • Когда нужно работать с нестандартными SQL-конструкциями.

Комбинирование ORM и SQL

Чистая архитектура

Хорошая практика – использовать слой репозитория, где SQL и ORM-методы сосуществуют.

Возвращать из методов следует DTO-объекты, а не ORM-модели или словари, тогда код будет чистым.

Использование ORM для миграций и админки

Обычно даже в проектах с SQL используют ORM как минимум для миграций и админки.

Как проверять, какие SQL-запросы генерирует ORM?

Django ORM:

В Django можно увидеть, какой SQL-запрос будет выполнен, через свойство query:

print(str(Book.objects.filter(name='Django').query))

Также можно включить логирование SQL-запросов.

Если речь о миграциях, можно посмотреть, какой SQL сгенерировала Django ORM:

./manage.py sqlmigrate app_name 0005

Это покажет SQL-код миграции и поможет убедиться, что ORM корректно изменяет схему базы. Иногда можно увидеть неожиданное поведение поэтому, все миграции и запросы всегда нужно проверять.

SQLAlchemy ORM:

Чтобы включить логирование всех запросов в SQLAlchemy, можно при создании engine передать флаг echo=True:

from sqlalchemy import create_engine

engine = create_engine("sqlite:///example.db", echo=True)

Тренды: уходит ли ORM в прошлое?

Некоторые разработчики считают, что ORM теряет популярность, но на самом деле он продолжает широко использоваться. ORM предлагает автоматическое управление схемой БД, генерацию миграций и интеграцию с административными панелями.

Часто отказ от ORM происходит из-за незнания его возможностей и особенностей. Опытные разработчики, хорошо разбирающиеся в ORM, редко переходят на чистый SQL без веских причин, но и сам SQL знают хорошо. Или как минимум используют ORM для миграций и админ-панелей.

Выводы

  • ORM облегчает работу с базой, делая код более читаемым и безопасным и предоставляет LOW-CODE решение для админ-панели.

  • Чистый SQL нужен в сложных запросах и при оптимизации производительности там, где ORM не поддерживает нужные конструкции.

  • Важно следить за тем, какие SQL-запросы генерирует ORM, используя инструменты отладки и логирования.

  • Оптимальный вариант — совмещать оба подхода: использовать ORM для удобства и LOW-CODE админ-панели, а SQL там, где ORM неэффективен.

  • Если сомневаетесь, выбирайте ORM – он безопаснее и удобнее.

Хороший разработчик должен хорошо знать и SQL, и ORM. Нельзя даже объективно рассуждать, что лучше, если вы хорошо знаете только что-то одно.

Стоит ли использовать ORM или писать SQL-запросы вручную? Ответ зависит от контекста. В большинстве случаев ORM ускоряет разработку, уменьшает вероятность ошибок и улучшает читаемость кода. Однако для сложных или специфичных запросов SQL остается незаменимым.

Лучший вариант — комбинировать оба подхода: использовать ORM для удобства и SQL там, где это необходимо. Главное — изучить оба инструмента и выбирать их осознанно!

Вопросы для обсуждения:

  1. В каких случаях вы предпочли бы SQL вместо ORM?

  2. Как вы решаете проблемы производительности ORM?

  3. Были ли у вас случаи, когда переписывали проект с ORM на SQL (или наоборот)?

Пишите в комментариях – обсудим!

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Как часто вы используете ORM в своей работе?
85.71% Часто6
14.29% Иногда1
0% Редко0
Проголосовали 7 пользователей. Воздержались 2 пользователя.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Какие преимущества ORM вы считаете наиболее важными?
85.71% Упрощение кода6
14.29% Безопасность1
0% Поддержка миграций и LOW-CODE решений0
Проголосовали 7 пользователей. Воздержались 2 пользователя.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Какие недостатки ORM вы встречали?
33.33% Недостаточная гибкость для сложных запросов2
16.67% Отсутствие контроля над запросами1
16.67% Плохая производительность на больших данных1
33.33% Чаще проблемы в неверном использовании ORM2
Проголосовали 6 пользователей. Воздержались 2 пользователя.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Как часто вы пишете SQL-запросы вручную?
14.29% Всегда1
71.43% Иногда5
14.29% Редко1
Проголосовали 7 пользователей. Воздержался 1 пользователь.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Какой тип запросов вы обычно пишете вручную?
14.29% Простые запросы (SELECT, UPDATE, DELETE)1
14.29% Сложные запросы с JOIN1
57.14% Запросы для отчетности4
14.29% Все из перечисленного1
Проголосовали 7 пользователей. Воздержался 1 пользователь.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Какой подход вам кажется более удобным для разработки?
20% Использование ORM всегда1
0% Чистый SQL всегда0
80% Использование ORM для базовых операций, SQL для сложных запросов4
Проголосовали 5 пользователей. Воздержались 2 пользователя.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Как вы думаете, будущее за ORM или за чистым SQL?
0% ORM0
0% Чистый SQL0
100% Будущее за гибридными решениями (и то, и другое)7
Проголосовали 7 пользователей. Воздержался 1 пользователь.
Источник: https://habr.com/ru/companies/beget/articles/890390/


Интересные статьи

Интересные статьи

Когда я только начинала писать статьи на Хабр, работая в айтишной компании, мне всегда было страшно смотреть на изменения рейтинга публикации. Поэтому я открывала профиль, жала F5 и наблюдала за своим...
В этой статье мы популярно объясняем на собственном опыте как организовать массовую выгрузку, обработку и загрузку фотографий товаров из Bitrix, используя Python и минимальное количество SQL. Для проч...
Подборка мероприятий на неделю SmartData 2021 – конференция по Data Engineering 11 октября (понедельник) — 14 октября (четверг) онлайн от 20 000р. SmartData — это техническая конференция для ...
Статья о том, как упорядочить найм1. Информируем о вакансии2. Ведём до найма3. Автоматизируем скучное4. Оформляем и выводим на работу5. Отчитываемся по итогам6. Помогаем с адаптацией...
Компании растут и меняются. Если для небольшого бизнеса легко прогнозировать последствия любых изменений, то у крупного для такого предвидения — необходимо изучение деталей.