В каком порядке оцениваются MySQL JOINs?

У меня есть следующий запрос:

SELECT c.*
FROM companies AS c
JOIN users AS u USING(companyid)
JOIN jobs AS j USING(userid)
JOIN useraccounts AS us USING(userid)
WHERE j.jobid = 123;

У меня есть следующие вопросы:

  • Является синтаксисом синтаксиса USING синтаксисом ON?
  • Согласованы ли эти объединения слева направо? Другими словами, отвечает ли этот запрос: x = компании JOIN users; y = x JOIN заданий; z = y JOIN useraccounts;
  • Если ответ на вопрос 2 да, можно ли предположить, что таблица компаний имеет столбцы companyid, userid и jobid?
  • Я не понимаю, как предложение WHERE может использоваться для выбора строк в таблице компаний, когда оно ссылается на псевдоним "j"

Любая помощь будет оценена!

Ответ 1

  • ИСПОЛЬЗОВАНИЕ (имя поля) является сокращенным способом указания ON table1.fieldname = table2.fieldname.

  • SQL не определяет "порядок", в котором выполняются JOINS, потому что это не характер языка. Очевидно, что порядок должен быть указан в инструкции, но INNER JOIN можно считать коммутативным: вы можете перечислить их в любом порядке, и вы получите те же результаты.

    Тем не менее, при создании SELECT... JOIN, особенно в том, что включает в себя LEFT JOINs, я нашел смысл рассматривать третий JOIN как присоединение к новой таблице к результатам первого JOIN, четвертого JOIN как присоединение к результатам второй JOIN и т.д.

    Реже, указанный порядок может влиять на поведение оптимизатора запросов из-за того, как он влияет на эвристику.

  • Нет. Способ сборки запроса, это требует, чтобы компании и пользователи имели companyid, у заданий есть идентификатор пользователя, а у jobid и useraccounts есть идентификатор пользователя. Тем не менее, только одна из компаний или пользователей нуждается в идентификаторе пользователя для работы JOIN.

  • Предложение WHERE фильтрует весь результат - то есть все столбцы JOINed - используя столбец, предоставленный таблицей заданий.

Ответ 2

Я не могу ответить на вопрос о синтаксисе USING. Тот странный. Я никогда раньше этого не видел, всегда использовал предложение ON.

Но то, что я могу вам сказать, заключается в том, что порядок операций JOIN динамически определяется оптимизатором запросов при построении его плана запросов на основе системы эвристик оптимизации, некоторые из которых:

  • Выполняется ли JOIN в поле первичного ключа? Если это так, это получает высокий приоритет в плане запроса.

  • Выполняется ли JOIN в поле внешнего ключа? Это также получает высокий приоритет.

  • Существует ли индекс в объединенном поле? Если это так, выберите приоритет.

  • Выполняется ли операция JOIN в поле в предложении WHERE? Можно ли оценивать выражение предложения WHERE, анализируя индекс (а не выполняя сканирование таблицы)? Это основная возможность оптимизации, поэтому она получает основной приоритет.

  • Какова мощность объединенного столбца? Столбцы с высокой мощностью дают оптимизатору больше возможностей для распознавания ложных совпадений (те, которые не удовлетворяют предложению WHERE или предложение ON), поэтому соединения с высокой производительностью обычно обрабатываются до присоединения низкой мощности.

  • Сколько фактических строк находится в объединенной таблице? Присоединение к таблице с только 100 значениями приведет к созданию меньшего количества взрыва данных, чем к соединению с таблицей с десятью миллионами строк.

Во всяком случае... точка... есть много переменных, которые входят в план выполнения запроса. Если вы хотите увидеть, как MySQL оптимизирует свои запросы, используйте синтаксис EXPLAIN.

И вот хорошая статья:

http://www.informit.com/articles/article.aspx?p=377652


ON EDIT:

Чтобы ответить на ваш четвертый вопрос: вы не запрашиваете таблицу "компании". Вы запрашиваете объединенный кросс-продукт из ВСЕ четырех таблиц в предложениях FROM и USING.

Псевдоним "j.jobid" - это просто полное имя одного из столбцов в объединенной коллекции таблиц.

Ответ 4

СМ. http://dev.mysql.com/doc/refman/5.0/en/join.html

И начните читать здесь:


Присоединить изменения к обработке в MySQL 5.0.12

Начиная с MySQL 5.0.12, естественные объединения и объединения с USING, включая варианты внешнего соединения, обрабатываются в соответствии со стандартом SQL: 2003. Целью было согласование синтаксиса и семантики MySQL в отношении NATURAL JOIN и JOIN... ИСПОЛЬЗОВАНИЕ в соответствии с SQL: 2003. Однако эти изменения в обработке соединений могут приводить к разным выходным столбцам для некоторых объединений. Кроме того, некоторые запросы, которые, как представляется, корректно работают в старых версиях, должны быть переписаны в соответствии со стандартом.

Эти изменения имеют пять основных аспектов:

  • Способ, которым MySQL определяет столбцы результатов NATURAL или USING операций объединения (и, следовательно, результат всего предложения FROM).

  • Расширение SELECT * и SELECT tbl_name. * в список выбранных столбцов.

  • Разрешение имен столбцов в приложениях NATURAL или USING.

  • Преобразование NATURAL или USING соединений в JOIN... ON.

  • Разрешение имен столбцов в состоянии ON для JOIN... ON.

Ответ 5

Я не уверен относительно части ON и USING (хотя этот веб-сайт говорит, что они такие же)

Что касается вопроса упорядочения, то его конкретная реализация (и, вероятно, запрос). MYSQL скорее всего выбирает заказ при компиляции запроса. Если вы хотите принудительно выполнить определенный заказ, вам придется "разыгрывать" ваши запросы:

SELECT c.*
FROM companies AS c 
    JOIN (SELECT * FROM users AS u 
        JOIN (SELECT * FROM  jobs AS j USING(userid) 
              JOIN useraccounts AS us USING(userid) 
              WHERE j.jobid = 123)
    )

как для части 4: предложение where ограничивает, какие строки из таблицы заданий могут быть включены в JOINed. Поэтому, если есть строки, которые будут объединены из-за совпадающих идентификаторов пользователя, но не имеют правильного значения, то они будут опущены.

Ответ 6

1) Использование не совсем то же самое, что и на, но это короткая рука, где обе таблицы имеют столбец с тем же именем, с которым вы соединяетесь... см. http://www.java2s.com/Tutorial/MySQL/0100__Table-Join/ThekeywordUSINGcanbeusedasareplacementfortheONkeywordduringthetableJoins.htm

Сложнее читать, по моему мнению, поэтому я бы сказал, что вы можете объединиться.

3) Это непонятно из этого запроса, но я бы предположил, что это не так.

2) Предполагая, что вы присоединяетесь к другим таблицам (не все непосредственно по компаниям), порядок в этом запросе имеет значение... см. сравнения ниже:

оригинальный:

SELECT c.* 
    FROM companies AS c 
    JOIN users AS u USING(companyid) 
    JOIN jobs AS j USING(userid) 
    JOIN useraccounts AS us USING(userid) 
WHERE j.jobid = 123

Я думаю, что это, вероятно, предполагает:

SELECT c.* 
    FROM companies AS c 
    JOIN users AS u on u.companyid = c.companyid
    JOIN jobs AS j on j.userid = u.userid
    JOIN useraccounts AS us on us.userid = u.userid 
WHERE j.jobid = 123

Вы можете переключать свои линии, соединяющие задания и учетные записи пользователей здесь.

Как это выглядело бы, если бы все присоединилось к компании:

SELECT c.* 
    FROM companies AS c 
    JOIN users AS u on u.companyid = c.companyid
    JOIN jobs AS j on j.userid = c.userid
    JOIN useraccounts AS us on us.userid = c.userid
WHERE j.jobid = 123

Это не делает логического смысла... если у каждого пользователя нет собственной компании.

4.) Магия sql заключается в том, что вы можете показывать только определенные столбцы, но все они предназначены для сортировки и фильтрации...

если вы вернули

SELECT c.*, j.jobid....  

вы могли бы четко видеть, на что он фильтруется, но серверу базы данных все равно, выводит ли строка или нет для фильтрации.

Ответ 7

Ниже приведен более подробный ответ на приоритет JOIN. В вашем случае JOIN являются коммутативными. Попробуйте один, где они не являются.

Схема сборки:

CREATE TABLE users (
  name text
);

CREATE TABLE orders (
  order_id text,
  user_name text
);

CREATE TABLE shipments (
  order_id text,
  fulfiller text
);

Добавить данные:

INSERT INTO users VALUES ('Bob'), ('Mary');

INSERT INTO orders VALUES ('order1', 'Bob');

INSERT INTO shipments VALUES ('order1', 'Fulfilling Mary');

Запустить запрос:

SELECT *
  FROM users
       LEFT OUTER JOIN orders
       ON orders.user_name = users.name
       JOIN shipments
       ON shipments.order_id = orders.order_id

Результат:

Возвращается только строка Bob

Анализ:

В этом запросе сначала был оценен LEFT OUTER JOIN, а JOIN был оценен в составном результате LEFT OUTER JOIN.

Второй запрос:

SELECT *
  FROM users
       LEFT OUTER JOIN (
         orders
         JOIN shipments
         ON shipments.order_id = orders.order_id)
         ON orders.user_name = users.name

Результат:

Одна строка для Боба (с данными выполнения) и одна строка для Марии с NULL для выполнения данных.

Анализ:

Скобка изменила порядок оценки.


Дополнительная документация MySQL находится на https://dev.mysql.com/doc/refman/5.5/en/nested-join-optimization.html