Два запроса ищут пользователей без заказов: LEFT JOIN orders ON ... WHERE orders.id IS NULL и WHERE NOT EXISTS (SELECT 1 FROM orders WHERE ...). Что верно о производительности в PostgreSQL?
AОптимизатор
PostgreSQL обычно сводит оба варианта к плану Anti Join, разница в скорости минимальнаBВариант с
LEFT JOIN ... IS NULL быстрее: NOT EXISTS запускает подзапрос для каждой строкиCВариант с
NOT EXISTS быстрее: он прерывает поиск в подзапросе на первом совпаденииDОба варианта выполняются последовательно: сначала полный
JOIN, потом фильтр по IS NULLПравильный ответ. Оптимизатор PostgreSQL обычно распознаёт оба паттерна как анти-соединение и строит одинаковый план — разница в скорости минимальна.
Разбор
Современные оптимизаторы (PostgreSQL, SQL Server, Oracle) умеют преобразовывать LEFT JOIN ... IS NULL, NOT EXISTS и даже NOT IN (без NULL) в один оператор Anti Join. В выводе EXPLAIN это видно как Hash Anti Join или Merge Anti Join. На практике для PostgreSQL разница в скорости между первыми двумя подходами пренебрежимо мала. NOT IN может проиграть из-за обработки NULL. Рекомендация: выбирать наиболее читаемый вариант.
Проверь себя · 1/3разбор после ответа
Два запроса:
SELECT * FROM orders JOIN users ON orders.user_id = users.user_id и SELECT * FROM orders JOIN users USING(user_id). В чём ключевое ограничение USING?Ещё вопросы по теме «JOIN и операции множеств»
- В отчёте нужно вывести всех пользователей и количество их заказов, включая тех, у кого заказов нет. Какой тип соединения между `users` и `orders` по `user_id` нужен?
- Нужно посчитать число пользователей, которые сделали хотя бы 1 заказ (таблицы `users(user_id)` и `orders(user_id, order_id)`). Какой запрос посчитает правильно?
- Вы соединили заказы с `order_items` и `payments` по `order_id`, а потом посчитали `SUM(paid_amount)`. Сумма оказалась завышенной. Что вероятнее всего произошло и как исправить?
- Есть две таблицы с одинаковой схемой: `events_web(user_id, event_name, created_at)` и `events_app(user_id, event_name, created_at)`. Нужно получить общий поток событий для дальнейшей агрегации. Что использовать?
- Нужно получить уникальный список идентификаторов пользователей из двух каналов: `campaign_a(user_id)` и `campaign_b(user_id)`. Как корректнее объединить списки, чтобы убрать дубликаты?
- Все вопросы по «JOIN и операции множеств» →