Гид по технологиям

Объединение таблиц в MySQL: как и когда использовать JOIN

6 min read Databases Обновлено 31 Dec 2025
Объединение таблиц в MySQL — JOIN на практике
Объединение таблиц в MySQL — JOIN на практике

  • JOIN в SQL позволяет извлекать связанные данные из нескольких таблиц за один запрос.
  • Основные типы: INNER (пересечение), LEFT (все слева + совпадения справа), RIGHT (все справа + совпадения слева).
  • Для многих задач используйте явные JOIN … ON вместо подзапросов с IN — это обычно быстрее и понятнее.

Объединение таблиц в MySQL с примером связей

Что вы узнаете

В этой статье подробно объяснено, как получать нужные данные из нескольких таблиц MySQL с помощью JOIN: синтаксис, примеры, советы по производительности и практический чеклист для написания корректных запросов.

Введение: определение в одну строку — JOIN соединяет строки из двух (или более) таблиц по заданному условию соответствия.

Идея JOIN простыми словами

Представьте две таблицы как два списка: один с клиентами, другой — с заказами. JOIN отвечает на вопрос «какие строки из одного списка соответствуют строкам в другом списке по общему полю?».

  • INNER JOIN — только совпадающие строки (пересечение).
  • LEFT JOIN — все строки из левой таблицы и совпадения из правой (оставшиеся правые будут NULL).
  • RIGHT JOIN — зеркально: все из правой и совпадающие из левой.

Инициализация тестовой базы (необязательно)

Если хотите повторить примеры локально, можно клонировать репозиторий примера и загрузить дамп в MySQL:

git clone https://github.com/mdizak/sample-select-db.git
cd sample-select-db
sudo mysql < store.sql
sudo mysql sampledb
mysql> SELECT COUNT(*) FROM customers;

Ожидаемый результат: в таблице customers будет 2000 строк.

Основной пример: INNER JOIN (по умолчанию)

INNER JOIN возвращает только те строки, где есть совпадения в обеих таблицах. Это наиболее распространённый и логичный тип соединения.

Пример: получить id клиента, имя, фамилию, сумму заказа и дату для всех заказов больше 1000 долларов:

SELECT
  c.id,
  c.first_name,
  c.last_name,
  o.amount,
  o.created_at
FROM
  customers c
  INNER JOIN orders o ON o.customer_id = c.id
WHERE
  o.amount >= 1000;

Короткие пояснения:

  • Мы выбираем пять колонок из двух таблиц — три из customers и две из orders.
  • Алиасы c и o сокращают запись и повышают читаемость.
  • Условие o.customer_id = c.id связывает строки клиентов и заказов.

Примечание: Синтаксис “FROM customers c, orders o WHERE o.customer_id = c.id” технически равен приведённому INNER JOIN, но явный JOIN с ON лучше читается и предпочтителен в сложных запросах.

LEFT JOIN — когда нужно вернуть все записи слева

LEFT JOIN вернёт все строки из левой таблицы и совпадающие строки из правой. Если совпадений нет — соответствующие поля правой таблицы будут NULL.

Пример: суммарные продажи по продуктам, основанные на items в заказах:

SELECT
  p.name,
  SUM(item.amount) AS tamount
FROM
  orders_items item
  LEFT JOIN products p ON item.product_id = p.id
GROUP BY
  item.product_id
ORDER BY
  tamount DESC;

Такой запрос пройдёт по всем строкам orders_items и попытается сопоставить их с продуктами. Если некоторые product_id в items не имеют сопоставления, имя продукта будет NULL.

RIGHT JOIN — когда главный набор справа

RIGHT JOIN зеркален LEFT JOIN: он возвращает все строки правой таблицы и совпадения из левой. Это полезно, если «основная» таблица находится справа в записи запроса.

Если вы хотите увидеть все продукты (включая те, которые ещё не продавались):

SELECT
  p.name,
  SUM(item.amount) AS tamount
FROM
  orders_items item
  RIGHT JOIN products p ON item.product_id = p.id
GROUP BY
  p.id
ORDER BY
  tamount DESC;

Результат покажет все 22 продукта, при этом для непроданных товаров tamount будет NULL.

Важно: LEFT и RIGHT — это одно и то же с точки зрения результата, если поменять порядок таблиц. Выберите тот синтаксис, который делает запрос понятнее.

Соединение более чем двух таблиц

Часто требуется связать три и более таблиц. JOIN можно применять последовательно.

Пример: список клиентов, которые купили конкретный продукт (product_id = 1), с датой заказа и суммой:

SELECT
  c.first_name,
  c.last_name,
  o.amount,
  o.created_at
FROM
  customers c
  INNER JOIN orders o ON c.id = o.customer_id
  INNER JOIN orders_items item ON item.order_id = o.id
WHERE
  item.product_id = 1
ORDER BY
  o.created_at;

Логика: сначала сопоставляем клиентов и их заказы, затем к результату подсоединяем items, чтобы отфильтровать только те заказы, в которых есть нужный продукт.

Когда не стоит использовать подзапросы с IN

Подзапросы в WHERE … IN часто выглядят просто, но в ряде СУБД и при больших объёмах они дают худшую производительность. Пример менее эффективного подхода:

SELECT first_name, last_name
FROM customers
WHERE id IN (
  SELECT customer_id
  FROM orders
  WHERE status = 'approved' AND amount < 100
);

Лучше переписать через JOIN — это более ясно и обычно быстрее:

SELECT
  c.first_name,
  c.last_name
FROM
  customers c
  LEFT JOIN orders o ON o.customer_id = c.id
WHERE
  o.status = 'approved' AND o.amount < 100;

Замечание: иногда подзапросы более уместны — например, когда вы хотите агрегировать и использовать результат как фильтр (EXISTS/NOT EXISTS или агрегатные проверки). Всегда проверяйте план выполнения (EXPLAIN).

Практические советы по производительности

  • Используйте индексы по колонкам, участвующим в ON и WHERE (например, customer_id, order_id, product_id).
  • Избегайте SELECT * в продуктивных запросах — выбирайте только нужные колонки.
  • Проверяйте план выполнения через EXPLAIN, особенно если JOIN участвует в больших таблицах.
  • Если результат сильно фильтруется на одном из шагов, рассмотрите сначала сделать агрегат/фильтрацию, а затем JOIN.

Важно: оптимизация зависит от объёма данных и настроек сервера. Тестируйте изменения на реплике или DEV-среде.

Частые ошибки и как их избегать

  • Пропущенное условие JOIN приводит к декартову произведению (много лишних строк). Всегда проверяйте ON.
  • Неправильная группировка при использовании агрегатов (GROUP BY) — убедитесь, что вы группируете по нужным полям.
  • Путаница между LEFT/RIGHT — проще читать запрос, если основная таблица стоит слева и применять LEFT JOIN.

Краткая методология написания сложного JOIN-запроса

  1. Определите основной набор строк (основная таблица).
  2. Выберите поля, которые нужны в результате.
  3. Подключайте дополнительные таблицы по мере необходимости, начиная с самых селективных фильтров.
  4. Добавьте агрегаты и GROUP BY только когда действительно нужно.
  5. Запустите EXPLAIN и оптимизируйте индексы.

Чеклист перед отправкой запроса в прод

  • Есть ли индекс на колонке, используемой в JOIN/WHERE?
  • Не возвращаются ли лишние NULL или дубликаты?
  • Нужно ли преобразовать LEFT JOIN в INNER JOIN для сокращения объёма?
  • Проверен ли план выполнения (EXPLAIN)?
  • Нет ли неожиданного декартова произведения?

Модель мышления (heuristic)

Думайте о JOIN как о действии над множествами:

  • INNER = A ∩ B (только пересечение);
  • LEFT = A ∪ (A ∩ B) с сохранением всех A;
  • RIGHT = B ∪ (A ∩ B) с сохранением всех B.

Это помогает заранее понимать, какие строки попадут в результат.

Примеры, когда JOIN не подойдёт

  • Когда нужно проверить существование строки, лучше EXISTS, а не сложные агрегаты.
  • Когда надо получить односкалярное значение, подзапрос в SELECT может быть чище (и иногда быстрее) — проверяйте EXPLAIN.

Критерии приёмки

  • Запрос возвращает ожидаемое количество строк для тестовых данных.
  • Нет декартовых произведений.
  • План выполнения не содержит полного скана больших таблиц без индексов.
  • Результаты корректны для граничных случаев (отсутствие совпадений, NULL значения).

Резюме

JOIN — базовый и мощный инструмент в SQL, который делает возможным получение связанных данных из нескольких таблиц в одном запросе. Предпочитайте явный JOIN с ON для читаемости и контроля. Проверяйте индексы и план выполнения, особенно для больших таблиц.

Ключевые выносные мысли:

  • Используйте INNER для строго соответствующих строк, LEFT/RIGHT — когда нужно сохранить все строки одной стороны.
  • Перепишите простые подзапросы в JOINы для лучшей производительности, но тестируйте.
  • Всегда проверяйте EXPLAIN и индексы перед деплоем.

Спасибо за внимание — применяйте JOIN осознанно и ваш код будет быстрее, чище и проще для поддержки.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Universal Search в Clubhouse: как найти людей и клубы
Новости

Universal Search в Clubhouse: как найти людей и клубы

Как убрать всплывающие окна на Mac
Mac советы

Как убрать всплывающие окна на Mac

Запуск Android‑приложений в Chrome
Технологии

Запуск Android‑приложений в Chrome

Как перенести секретные чаты Telegram на Android
Мобильные приложения

Как перенести секретные чаты Telegram на Android

Пригласить друзей в Clubhouse — инструкция
Социальные сети

Пригласить друзей в Clubhouse — инструкция

Как удалить аккаунт Telegram — пошаговое руководство
Инструкции

Как удалить аккаунт Telegram — пошаговое руководство