0Pricing
SQL Academy · Урок

Антисоединения и полусоединения (NOT EXISTS)

Находите «строки в A без совпадений в B» (антисоединение) и «строки в A хотя бы с одним совпадением в B» (полусоединение) с помощью EXISTS/NOT EXISTS

«Антисоединения и полусоединения (NOT EXISTS)» — бесплатный урок SQL Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения SQL Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс SQL Academy содержит 4 уроков всего.

Полусоединение: «есть хотя бы одно совпадение»

Верните строки из A, для которых существует хотя бы одна совпадающая строка в B, но только столбцы A. SQL реализует полусоединения с помощью EXISTS или IN.

Полусоединение с EXISTS

Пользователи, разместившие хотя бы один заказ:

SELECT u.* FROM users u
WHERE EXISTS (
  SELECT 1 FROM orders o WHERE o.user_id = u.id
);

Полусоединение с IN

Тот же результат, другой стиль:

SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders);

Почему EXISTS часто эффективнее

EXISTS применяет ранний выход: останавливается после первого совпадения для каждой внешней строки. IN может материализовать весь внутренний набор. Современные планировщики часто оптимизируют их до одного и того же плана, но EXISTS надёжнее использовать для огромных внутренних наборов.

Антисоединение: «нет совпадения»

Пользователи, которые NEVER размещали заказ, — три идиоматичных варианта:

-- NOT EXISTS (preferred):
SELECT u.* FROM users u
WHERE NOT EXISTS (
  SELECT 1 FROM orders o WHERE o.user_id = u.id
);

-- LEFT JOIN ... IS NULL:
SELECT u.* FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE o.id IS NULL;

-- NOT IN (risky with NULLs):
SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM orders);

Почему NOT IN рискован

Если внутренний подзапрос содержит NULL, NOT IN возвращает NULL, а WHERE отбрасывает строки, для которых предикат равен NULL. Результат: ноль строк. У NOT EXISTS такой проблемы нет.

Оптимизация планировщиком

Современный PostgreSQL распознаёт EXISTS и NOT EXISTS как шаблоны полусоединения и антисоединения и может выполнять их с помощью хеш-соединений:

EXPLAIN ANALYZE
SELECT u.* FROM users u
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);
-- → Hash Anti Join

Антисоединения по нескольким столбцам

Используйте составные ключи:

SELECT * FROM order_items oi
WHERE NOT EXISTS (
  SELECT 1 FROM shipments s
  WHERE s.order_id = oi.order_id
    AND s.line_no  = oi.line_no
);

Полусоединение с EXISTS и дополнительным предикатом

Добавьте фильтры во внутренний подзапрос:

SELECT u.* FROM users u
WHERE EXISTS (
  SELECT 1 FROM orders o
  WHERE o.user_id = u.id
    AND o.status = 'paid'
    AND o.created_at >= NOW() - INTERVAL '30 days'
);

Индексируйте столбец корреляции

И в EXISTS, и в NOT EXISTS внутренний подзапрос фильтруется по ключу внешней строки. Без индекса по этому ключу выполняется сканирование для каждой внешней строки:

CREATE INDEX orders_user_id_idx ON orders(user_id);

Когда использовать LEFT JOIN ... IS NULL

Для панелей мониторинга, которым нужны также столбцы из несопоставленной стороны, естественно подходит стиль с LEFT JOIN. Для чистой семантики антисоединения понятнее использовать NOT EXISTS.

За пределами SQL: фильтры Блума

Для огромных антисоединений может помочь предварительная фильтрация с помощью фильтра Блума. PostgreSQL поддерживает индексы bloom через расширение bloom.

Итоги

Полусоединение = «есть совпадение»; антисоединение = «нет совпадения».

  • EXISTS для полусоединения
  • NOT EXISTS для антисоединения, безопасного при NULL
  • Индексируйте столбец корреляции
  • Избегайте NOT IN, если внутренний набор может содержать NULL

Быстрая проверка

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

Часто задаваемые вопросы

Урок «Антисоединения и полусоединения (NOT EXISTS)» бесплатный?

Да — полный текст урока «Антисоединения и полусоединения (NOT EXISTS)» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс SQL Academy, подпишись на CoddyKit PRO. Курс SQL Academy содержит 4 уроков всего.

Чему я научусь в уроке «Антисоединения и полусоединения (NOT EXISTS)»?

Находите «строки в A без совпадений в B» (антисоединение) и «строки в A хотя бы с одним совпадением в B» (полусоединение) с помощью EXISTS/NOT EXISTS Ты практикуешь SQL Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать SQL Academy?

Предыдущий опыт не требуется. SQL Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Антисоединения и полусоединения (NOT EXISTS)»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке SQL Academy?

Да. Каждый урок SQL Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Перекрёстные соединения и декартовы произведения
  2. Латеральные соединения (LATERAL JOIN)
  3. Антисоединения и полусоединения (NOT EXISTS)
  4. Оптимизация производительности соединений нескольких таблиц
← Назад к SQL Academy