SQL оптимизация JOIN: лучшие практики

Оптимизация JOIN-операций

Джойним от меньшего к большему

Should Have

При соединении таблиц старайтесь, чтобы меньшая таблица была слева (в первой позиции). PostgreSQL часто строит хеш-таблицу(об этом поговорим в следующем блоке) на основе меньшей таблицы, что ускоряет выполнение запроса.

Неоптимальный запрос:

SELECT o.order_id, c.customer_name
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id;

Оптимальный запрос (если customers меньше):

SELECT o.order_id, c.customer_name
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id;

Фильтрация внутри JOIN

Should Have

Добавление фильтров непосредственно в условие JOIN может ускорить выполнение запроса, так как уменьшает количество строк до соединения.

Неоптимальный запрос:

SELECT o.order_id, c.customer_name
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE o.order_date > '2023-01-01' AND c.region = 'Europe';

Оптимальный запрос:

SELECT o.order_id, c.customer_name
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id 
                AND c.region = 'Europe'
WHERE o.order_date > '2023-01-01';

Избегайте сложной обработки ключей в JOIN

Must Have

Сложные выражения в условиях JOIN могут значительно замедлить запрос. Лучше подготовить данные заранее.

Неоптимальный запрос:

SELECT p.product_name, s.sales_amount
FROM products p
JOIN sales s ON LOWER(TRIM(p.product_code)) = LOWER(TRIM(s.product_code));

Оптимальный подход:

-- Сначала создаем временную таблицу или CTE
WITH normalized_products AS (
    SELECT product_id, product_name, LOWER(TRIM(product_code)) AS norm_code
    FROM products
)
-- Затем используем простое условие JOIN
SELECT p.product_name, s.sales_amount
FROM normalized_products p
JOIN sales s ON p.norm_code = LOWER(TRIM(s.product_code));

Избегайте неравенств в JOIN

Should Have

JOIN с условиями неравенства (<, >, <=, >=, <>) работают значительно медленнее, чем с равенством.

Неоптимальный запрос:

SELECT e.employee_name, d.department_name
FROM employees e
JOIN departments d ON e.salary > d.min_salary AND e.salary < d.max_salary;

Лучший подход: Если возможно, преобразуйте данные так, чтобы использовать равенство в JOIN.