← Назад к вопросам

Что выполняется раньше: WHERE или JOIN

2.0 Middle🔥 101 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что выполняется раньше: WHERE или JOIN?

Отличный вопрос об основах SQL, который показывает понимание того, как база данных обрабатывает запросы. Краткий ответ: JOIN выполняется ДО WHERE, но есть тонкости.

Порядок выполнения SQL операций

SQL запросы выполняются НЕ в том порядке, в котором ты их пишешь. База данных имеет собственный порядок обработки:

SELECT ... -- 6. Выбираем нужные столбцы
FROM ... -- 1. Начинаем отсюда
JOIN ... -- 2. Объединяем таблицы
WHERE ... -- 3. Фильруем строки
GROUP BY ... -- 4. Группируем
HAVING ... -- 5. Фильтруем группы
ORDER BY ... -- 7. Сортируем
LIMIT ... -- 8. Ограничиваем результат

Точный порядок выполнения

1. FROM и JOIN — первыми объединяются таблицы

SELECT u.id, u.name, o.total
FROM users u
JOIN orders o ON u.id = o.user_id  -- Выполняется ПЕРВЫМ!
WHERE u.status = "active"          -- Выполняется ВТОРЫМ

База данных работает так:

  1. Загружает все пользователей из users
  2. Объединяет с orders по условию u.id = o.user_id
  3. Потом применяет фильтр WHERE u.status = "active"

2. WHERE — применяется ПОСЛЕ JOIN

Фильтр WHERE действует на результат JOIN, а не на исходные таблицы:

-- Этот запрос:
SELECT u.id, u.name
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.status = "active"

-- Выполняется так:
-- 1. SELECT u.*, o.* FROM users u, orders o -- Декартово произведение
-- 2. WHERE u.id = o.user_id -- Фильтруем по JOIN условию
-- 3. WHERE u.status = "active" -- Фильтруем по WHERE

Важная деталь: ON vs WHERE

ON в JOIN выполняется раньше WHERE, потому что ON определяет, как объединять таблицы:

-- Вариант 1: фильтр в ON
SELECT u.id, o.id
FROM users u
JOIN orders o ON u.id = o.user_id AND o.status = "paid"
-- o.status = "paid" проверяется ВО ВРЕМЯ JOIN!

-- Вариант 2: фильтр в WHERE
SELECT u.id, o.id
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.status = "paid"
-- o.status = "paid" проверяется ПОСЛЕ JOIN

Практический пример: разница между ON и WHERE

-- ВАРИАНТ 1: Фильтр в ON (выполняется раньше)
SELECT u.id, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id AND o.status = "paid"
GROUP BY u.id

-- Результат:
-- user_id | order_count
-- 1       | 2           (только paid заказы)
-- 2       | 0           (нет paid заказов)
-- 3       | 1

-- ВАРИАНТ 2: Фильтр в WHERE (выполняется позже)
SELECT u.id, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.status = "paid"
GROUP BY u.id

-- Результат:
-- user_id | order_count
-- 1       | 2           (только пользователи с paid заказами)
-- 3       | 1
-- Пользователь 2 исчез, потому что WHERE отфильтровал его!

LEFT JOIN vs INNER JOIN с WHERE

Это очень важная разница:

-- Вариант A: INNER JOIN с WHERE
SELECT u.id, o.id
FROM users u
INNER JOIN orders o ON u.id = o.user_id
WHERE u.status = "active"
-- Выполнение:
-- 1. INNER JOIN между users и orders
-- 2. WHERE фильтрует результат
-- Не имеет значения, где фильтр (ON или WHERE) — INNER JOIN уберёт нестыковки

-- Вариант B: LEFT JOIN с WHERE на правую таблицу
SELECT u.id, o.id
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.status = "paid"
-- ОШИБКА В ЛОГИКЕ! LEFT JOIN дает NULL для пользователей без заказов
-- WHERE o.status = "paid" отфильтровает NULL
-- Результат: как INNER JOIN!

-- Правильно:
SELECT u.id, o.id
FROM users u
LEFT JOIN orders o ON u.id = o.user_id AND o.status = "paid"
-- o.status в ON сохранит все пользователи и даст NULL для не-paid заказов

Полный пример с таблицами

-- Таблицы:
users:                    orders:
id | name | city          id | user_id | total
1  | Alice| New York      1  | 1       | 100
2  | Bob  | London        2  | 1       | 200
3  | Carol| Paris         3  | 3       | 150

-- Запрос 1: JOIN, потом WHERE
SELECT u.name, o.total
FROM users u
INNER JOIN orders o ON u.id = o.user_id
WHERE o.total > 150

-- Выполнение:
-- Step 1 (JOIN): Объединяем users и orders
--   u.name | o.total
--   Alice  | 100
--   Alice  | 200
--   Carol  | 150
-- Step 2 (WHERE): Фильтруем по o.total > 150
--   u.name | o.total
--   Alice  | 200
-- Результат: одна строка

Пример с GROUP BY и HAVING

SELECT u.id, COUNT(o.id) as order_count
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.total > 0              -- Выполняется ДО GROUP BY
GROUP BY u.id
HAVING COUNT(o.id) > 2         -- Выполняется ПОСЛЕ GROUP BY

-- Порядок:
-- 1. FROM users u
-- 2. JOIN orders o
-- 3. WHERE o.total > 0         <- Фильтр на строки
-- 4. GROUP BY u.id
-- 5. HAVING COUNT(o.id) > 2    <- Фильтр на группы

Оптимизация: используй WHERE правильно

-- ПЛОХО: фильтр в JOIN условии для INNER JOIN
SELECT u.id, COUNT(o.id)
FROM users u
INNER JOIN orders o ON u.id = o.user_id AND u.city = "New York"
GROUP BY u.id
-- Это работает, но неэффективно: сначала JOIN, потом фильтр

-- ХОРОШО: используй WHERE для фильтра строк
SELECT u.id, COUNT(o.id)
FROM users u
INNER JOIN orders o ON u.id = o.user_id
WHERE u.city = "New York"
GROUP BY u.id
-- База данных может оптимизировать: фильтроват users ДО JOIN

Полный порядок выполнения (для памяти)

1. FROM          <- Загружаем таблицы
2. JOIN          <- Объединяем (ON условие)
3. WHERE         <- Фильтруем строки
4. GROUP BY      <- Группируем
5. HAVING        <- Фильтруем группы
6. SELECT        <- Выбираем столбцы
7. DISTINCT      <- Удаляем дубли
8. ORDER BY      <- Сортируем
9. LIMIT/OFFSET  <- Ограничиваем результат

Практический совет для Java разработчика

// Когда пишешь запрос с JOIN и WHERE, помни:

// 1. JOIN определяет, какие строки объединяются
String query1 = "SELECT u.id FROM users u JOIN orders o ON u.id = o.user_id";

// 2. WHERE фильтрует РЕЗУЛЬТАТ объединения
String query2 = "SELECT u.id FROM users u JOIN orders o ON u.id = o.user_id WHERE o.status = ?";

// 3. Для LEFT JOIN, используй ON для фильтра правой таблицы
// чтобы сохранить строки из левой таблицы
String query3 = "SELECT u.id FROM users u LEFT JOIN orders o ON u.id = o.user_id AND o.status = ?"; // Сохраняет пользователей

// 4. Если нужен WHERE, используй его только для левой таблицы
String query4 = "SELECT u.id FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE u.city = ?"; // OK

Итог

JOIN выполняется ДО WHERE. Порядок:

  1. FROM и JOIN объединяют таблицы
  2. WHERE фильтрует результат объединения
  3. Для LEFT JOIN используй ON для фильтра правой таблицы, WHERE для левой
  4. Это критически важно, особенно при использовании LEFT JOIN

Это один из самых важных моментов SQL оптимизации!

Что выполняется раньше: WHERE или JOIN | PrepBro