Какой у вас опыт написания сложных SQL-запросов?

Ответ

Имею опыт написания и оптимизации сложных SQL-запросов (PostgreSQL, MySQL) и их аналогов в JPA (JPQL, Criteria API).

Пример сложного SQL-запроса с JOIN, агрегацией и подзапросом:

SELECT 
    u.id,
    u.name,
    COUNT(o.id) AS total_orders,
    (SELECT MAX(amount) FROM payments p WHERE p.user_id = u.id) AS max_payment
FROM users u
LEFT JOIN orders o ON u.id = o.user_id AND o.status = 'COMPLETED'
WHERE u.created_at > '2023-01-01'
GROUP BY u.id, u.name
HAVING COUNT(o.id) > 5
ORDER BY total_orders DESC;

Ключевые навыки и best practices:

  • Оптимизация: Анализ плана выполнения (EXPLAIN ANALYZE), создание эффективных индексов, избегание N+1 проблемы.
  • Сложные конструкции: Оконные функции (ROW_NUMBER(), RANK(), LAG/LEAD), рекурсивные CTE (WITH RECURSIVE), UNION.
  • Работа в JPA/Hibernate:
    • Использование @EntityGraph или JOIN FETCH для жадной загрузки и решения N+1.
    • Criteria API для построения динамических, типобезопасных запросов.
    • Проекции DTO через @Query и конструктор выражений для выборки только нужных данных, минуя лишнюю работу контекста persistence.
  • Безопасность и работа с данными: Всегда использую параметризованные запросы (защита от SQL-инъекций), пагинацию (LIMIT/OFFSET, keyset pagination) для больших наборов данных.

Ответ 18+ 🔞

А, опыт работы с SQL и JPA? Ну, это ж святое дело, блядь! Сидишь, бывает, перед монитором, а там запрос на три экрана, и думаешь — ёпта, кто эту хуйню писал? А потом вспоминаешь, что это ты полгода назад, и хочется ебать свои старые костыли.

Вот смотри, примерчик из жизни, когда нужно выцепить юзеров, которые не просто зарегились, а реально заказывали. И не просто заказывали, а чтобы больше пяти раз, да ещё и статус 'COMPLETED', чтобы не просто так пиздюли били. И заодно глянуть, какую максимальную сумму они отгрузили в платежах. Всё в одну кучу, блядь!

SELECT
    u.id,
    u.name,
    COUNT(o.id) AS total_orders,
    (SELECT MAX(amount) FROM payments p WHERE p.user_id = u.id) AS max_payment
FROM users u
LEFT JOIN orders o ON u.id = o.user_id AND o.status = 'COMPLETED'
WHERE u.created_at > '2023-01-01'
GROUP BY u.id, u.name
HAVING COUNT(o.id) > 5
ORDER BY total_orders DESC;

Выглядит вроде ничего, но под капотом-то, сука, может такая дичь начаться... Особенно если индексов нет, или JOIN'ы криво написаны. Одна N+1 проблема чего стоит — приложение хуярит запросы как сумасшедшее, а БД просто накрывается медным тазом.

Чем, собственно, маюсь и что умею:

  • Оптимизация — это религия. Без EXPLAIN ANALYZE вообще не подхожу к запросу. Создать индекс — это не просто CREATE INDEX, это надо понять, куда его ебашить, чтобы он реально работал, а не просто место жрал. И эта долбаная N+1... Её либо JOIN FETCH в JPQL, либо @EntityGraph — только так, иначе пиши пропало.
  • Сложные штуки тоже в ходу. Оконные функции — это ж магия, блядь! ROW_NUMBER(), RANK() — когда нужно ранжировать или выбрать топ чего-нибудь. Рекурсивные CTE — для древовидных структур, там вообще мозг можно сломать, но красиво получается.
  • В мире JPA/Hibernate тоже не лаптем щи хлебаю.
    • Criteria API — это мой друг, когда запрос нужно собирать по кусочкам, в зависимости от фильтров. Динамически, типобезопасно, без этих ужасных конкатенаций строк, где в любой момент можно накосячить.
    • Проекции — отдельная песня. Зачем тащить целую сущность со всеми её ленивыми связями, если нужны три поля? Правильно, нихуя не зачем. Поэтому либо DTO через конструктор в @Query, либо какие-нибудь интерфейсы Spring Data. Контекст persistence не засоряется, память не сосёт — красота.
  • Безопасность и голова. Параметризованные запросы — это аксиома. Даже думать не буду вставлять значения напрямую в строку, иди нахуй с такими инъекциями. Пагинация — тоже must have. LIMIT/OFFSET для простого, а если данные активно обновляются, то keyset pagination (или курсоры) — чтобы не прыгал общий счётчик, как угорелый.

Короче, задача — не просто написать запрос, который работает. Задача — написать запрос, который работает быстро, безопасно и не заставляет сервер хрипеть, как паровоз. А то бывает такое напишут, что хоть святых выноси, ёпта.