UpPetto

This is a real course generated by UpPetto — unedited.

AI-generated · source-grounded review: written by two AI models, cross-checked by a third. Yours takes ~5 minutes.

Create my own course

Оптимизация JOIN и фильтрация данных

Pareto core

Самая частая причина медленных запросов — соединение больших таблиц без предварительной фильтрации. Когда вы пишете JOIN, СУБД должна сопоставить строки из двух таблиц, и если каждая содержит миллионы записей, объем работы становится огромным. Правильная оптимизация JOIN начинается с уменьшения данных до соединения.

Фильтрация перед JOIN

Плохой подход:

SELECT u.user_id, u.name, o.order_date, o.amount
FROM users u
JOIN orders o ON u.user_id = o.user_id
WHERE o.order_date >= '2024-01-01';

Здесь СУБД сначала соединяет ВСЕ строки из users и orders, а потом фильтрует по дате. Если в orders 10 млн строк, а нужны только за 2024 год (1 млн) — 9 млн строк обработаны зря.

Хороший подход — CTE с предварительной фильтрацией:

WITH recent_orders AS (
    SELECT user_id, order_date, amount
    FROM orders
    WHERE order_date >= '2024-01-01'  -- Фильтр ДО JOIN
)
SELECT u.user_id, u.name, ro.order_date, ro.amount
FROM users u
JOIN recent_orders ro ON u.user_id = ro.user_id;

Теперь JOIN работает с 1 млн строк вместо 10 млн — ускорение в разы. Всегда применяйте максимально строгие фильтры (WHERE, HAVING) до соединения таблиц.

Правильный порядок JOIN

СУБД обычно оптимизирует порядок соединений автоматически, но не всегда идеально. Общее правило: начинайте с самой маленькой таблицы (или самой отфильтрованной) и присоединяйте к ней более крупные.

Пример: - users: 100 000 строк - orders: 5 000 000 строк
- products: 10 000 строк

Нужны заказы за последний месяц с информацией о пользователях и продуктах.

WITH recent_orders AS (
    SELECT user_id, product_id, amount
    FROM orders
    WHERE order_date >= CURRENT_DATE - INTERVAL '1 month'  -- 200 000 строк
)
SELECT ro.amount, u.name, p.product_name
FROM recent_orders ro          -- Начинаем с отфильтрованной таблицы (200К)
JOIN products p ON ro.product_id = p.product_id  -- Присоединяем маленькую (10К)
JOIN users u ON ro.user_id = u.user_id;          -- Затем среднюю (100К)

Если начать с users JOIN orders без фильтра, СУБД обработает 500 млрд потенциальных комбинаций (100К × 5М) перед фильтрацией.

EXISTS vs IN для больших таблиц

Когда нужно проверить наличие связанных записей в другой таблице, EXISTS часто эффективнее IN, особенно для больших объемов данных.

IN — загружает весь список в память:

SELECT user_id, name
FROM users
WHERE user_id IN (SELECT user_id FROM orders WHERE amount > 1000);

Если подзапрос возвращает миллион user_id, все они загружаются в память для сравнения.

EXISTS — проверяет существование построчно:

SELECT user_id, name
FROM users u
WHERE EXISTS (
    SELECT 1 
    FROM orders o 
    WHERE o.user_id = u.user_id AND o.amount > 1000
);

EXISTS останавливается на первом найденном совпадении для каждого пользователя — не нужно сканировать все заказы. Для таблицы в 10 млн заказов разница может быть 10-кратной.

Когда использовать что: - IN — если подзапрос возвращает маленький список (десятки-сотни значений) или нужны сами значения для дальнейшей работы - EXISTS — для проверки существования связи в больших таблицах - NOT EXISTS почти всегда быстрее NOT IN для больших данных

Избегайте декартова произведения

Если забыть указать условие соединения, получится CROSS JOIN — каждая строка первой таблицы соединится с каждой строкой второй:

-- ОПАСНО! Декартово произведение
SELECT *
FROM users, orders;  -- 100К × 5М = 500 млрд строк

Всегда явно указывайте условие ON в JOIN. Если EXPLAIN показывает астрономическое количество строк — проверьте, не пропущено ли условие соединения.

Практический чеклист оптимизации JOIN

  1. Фильтруйте данные до JOIN: Используйте CTE или подзапросы с WHERE для уменьшения объема данных
  2. Проверьте индексы: На всех столбцах, участвующих в ON условиях, должны быть индексы
  3. Начинайте с малого: Первой в цепочке JOIN ставьте самую маленькую (или самую отфильтрованную) таблицу
  4. EXISTS вместо IN: Для проверки наличия в больших таблицах используйте EXISTS
  5. Проверьте план: EXPLAIN ANALYZE покажет реальный порядок соединений и количество обработанных строк

Ключевой вывод: Оптимизация JOIN — это в первую очередь уменьшение объема данных, участвующих в соединении. Отфильтруйте таблицы до минимума перед JOIN, используйте индексы на ключах соединения и выбирайте правильные операторы (EXISTS vs IN). Эти простые техники превращают запросы, выполняющиеся минутами, в секундные.

AI-generated · source-grounded review

Automated fact-check did not complete for this lesson — do not rely on it as verified.

A second opinion has not checked this lesson.

Key concepts: оптимизация JOIN фильтрация перед соединением EXISTS vs IN
Tell me more 🔒 Didn't understand — explain simply 🔒 Show examples 🔒 Sources 🔒

On your own course these buttons answer instantly, quizzes track what you've mastered, and lessons adapt to your gaps. Sign up free →

Check yourself

1. Почему важно применять WHERE-фильтры до JOIN, а не после?
2. В каком случае EXISTS предпочтительнее IN?
3. С какой таблицы лучше начинать цепочку JOIN для оптимальной производительности?
Sign up free to check your answers