loading..
Русский    English
23:37
листать

FULL JOIN и MySQL

Полное внешнее соединение (FULL JOIN) не поддерживается в MySQL. Можно считать, что это – «избыточная» операция, т.к. она представляется через объединение левого и правого внешних соединений. Например, запрос

Консоль
Выполнить
  1. --(1)--
  2. SELECT * FROM Income_o I FULL JOIN Outcome_o O
  3.      ON I.point = O.point AND I.date = O.date;
который на каждый рабочий день по каждому пункту выводит в одну строку приход и расход (схема «Вторсырье»), можно переписать в виде:

Консоль
Выполнить
  1. --(2)--
  2. SELECT * FROM Income_o I LEFT JOIN Outcome_o O
  3.       ON I.point = O.point AND I.date = O.date
  4. UNION
  5. SELECT * FROM Income_o I RIGHT JOIN Outcome_o O
  6.       ON I.point = O.point AND I.date = O.date;

С логической точки зрения эти запросы эквивалентны; оба они выводят как дни, когда был и приход, и расход, так и дни, когда отсутствовала одна из операций (отсутствующие значения заменяются NULL). Однако с точки зрения производительности второй запрос проигрывает первому вдвое по оценке стоимости плана. Это связано с тем, что операция UNION приводит к выполнению сортировки, которая отсутствует в плане первого запроса. Сортировка же необходима для процедуры исключения дубликатов, т.к. левое и правое соединения оба содержат строки, соответствующие внутреннему соединению, т.е. случаю, когда есть как приход, так и расход. Поэтому, если вместо UNION написать UNION ALL, то такие строки будут присутствовать в результирующем наборе в двух экземплярах.

Тем не менее, чтобы получить план, близкий по стоимости FULL JOIN, нужно избавиться от сортировки. Например, использовать UNION ALL, но в одном из объединяемых запросов исключить строки, соответствующие внутреннему соединению:

Консоль
Выполнить
  1. --(3)--
  2. SELECT * FROM Income_o I LEFT JOIN Outcome_o O
  3.       ON I.point = O.point AND I.date = O.date
  4. UNION ALL
  5. SELECT NULL, NULL, NULL,* FROM Outcome_o O
  6. WHERE NOT EXISTS (SELECT 1 FROM Income_o I
  7.                   WHERE I.point = O.point AND I.date = O.date);

Обратите внимание, что заведомо отсутствующие значения, которые появлялись в правом соединении решения (2), здесь формируются явным заданием NULL-значений. Если по каким-то причинам, явное задание NULL вместо соединения вам не подходит, можно оставить соединение, но это даст более дорогой план, хотя и он будет дешевле плана с сортировкой (2):

Консоль
Выполнить
  1. SELECT * FROM Income_o I LEFT JOIN Outcome_o O
  2.       ON I.point = O.point AND I.date = O.date
  3. UNION ALL
  4. SELECT * FROM Income_o I RIGHT JOIN Outcome_o O
  5.       ON I.point = O.point AND I.date = O.date
  6. WHERE NOT EXISTS (SELECT 1 FROM Income_o I
  7.                   WHERE I.point = O.point AND I.date = O.date);
Bookmark and Share
Тэги:
ALL AND AUTO_INCREMENT AVG battles CASE CAST CHAR CHARINDEX CHECK classes COALESCE CONSTRAINT Convert COUNT CROSS APPLY CTE DATEADD DATEDIFF DATENAME DATEPART DATETIME DDL DEFAULT DELETE DISTINCT DML EXCEPT EXISTS EXTRACT FOREIGN KEY FROM FULL JOIN GROUP BY Guadalcanal HAVING IDENTITY IN INNER JOIN insert INTERSECT IS NOT NULL ISNULL laptop LEFT LEFT OUTER JOIN LEN maker MAX MIN Больше тэгов
Учебник обновлялся
несколько дней назад
©SQL-EX,2008 [Развитие] [Связь] [О проекте] [Ссылки] [Team]
Перепечатка материалов сайта возможна только с разрешения автора.
Rambler's Top100