Что-то не так с объединениями, которые не используют ключевое слово JOIN в SQL или MySQL?
Когда я начал писать запросы к базе данных, я еще не знал ключевое слово JOIN, и, естественно, я просто расширил то, что уже знал, и писал такие запросы:
SELECT a.someRow, b.someRow
FROM tableA AS a, tableB AS b
WHERE a.ID=b.ID AND b.ID= $someVar
Теперь, когда я знаю, что это то же самое, что и INNER JOIN Я нахожу все эти запросы в своем коде и спрашиваю себя, следует ли мне переписать их. Есть что-то вонючее о них или они просто прекрасны?
EDIT:
Резюме ответа: в этом вопросе нет ничего плохого, но использование ключевых слов, скорее всего, сделает код более удобочитаемым/поддерживаемым.
Мой вывод. Я не буду изменять свои старые запросы, но я исправлю свой стиль письма и буду использовать ключевые слова в будущем.
СПАСИБО за ваши ответы!
Ответы
Ответ 1
Фильтрация соединений только с использованием WHERE
может быть крайне неэффективной в некоторых распространенных сценариях. Например:
SELECT * FROM people p, companies c
WHERE p.companyID = c.id AND p.firstName = 'Daniel'
Большинство баз данных будут выполнять этот запрос буквально, сначала беря декартово произведение таблиц people
и companies
, а затем фильтруя те, которые имеют соответствующие поля companyID
и id
. Хотя полностью безусловный продукт не существует нигде, кроме памяти, а затем только на мгновение, его расчет занимает некоторое время.
Лучшим подходом является группировка ограничений с JOIN
, если это необходимо. Это не только субъективно легче читать, но и намного эффективнее. Thusly:
SELECT * FROM people p JOIN companies c ON p.companyID = c.id
WHERE p.firstName = 'Daniel'
Это немного дольше, но база данных может смотреть на предложение ON
и использовать его для вычисления полностью ограниченного JOIN
напрямую, а не начинать со всего, а затем ограничивать. Это быстрее вычислять (особенно с большими наборами данных и/или соединениями со многими таблицами) и требует меньше памяти.
Я изменяю каждый запрос, который я вижу, который использует синтаксис "запятая JOIN
". На мой взгляд, единственной целью его существования является краткость. Учитывая влияние производительности, я не думаю, что это веская причина.
Ответ 2
Более подробные INNER JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN
взяты из синтаксиса ANSI SQL/92 для соединения. Для меня эта многословность делает соединение более понятным для разработчика/администратора баз данных того, что подразумевается в соединении.
Ответ 3
В SQL Server всегда проверяются планы запросов, вывод текста можно сделать следующим образом:
SET SHOWPLAN_ALL ON
GO
DECLARE @TABLE_A TABLE
(
ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
Data VARCHAR(10) NOT NULL
)
INSERT INTO @TABLE_A
SELECT 'ABC' UNION
SELECT 'DEF' UNION
SELECT 'GHI' UNION
SELECT 'JKL'
DECLARE @TABLE_B TABLE
(
ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
Data VARCHAR(10) NOT NULL
)
INSERT INTO @TABLE_B
SELECT 'ABC' UNION
SELECT 'DEF' UNION
SELECT 'GHI' UNION
SELECT 'JKL'
SELECT A.Data, B.Data
FROM
@TABLE_A AS A, @TABLE_B AS B
WHERE
A.ID = B.ID
SELECT A.Data, B.Data
FROM
@TABLE_A AS A
INNER JOIN @TABLE_B AS B ON A.ID = B.ID
Теперь я опускаю план создания переменной таблицы, план для обоих запросов идентичен, хотя:
SELECT A.Data, B.Data FROM @TABLE_A AS A, @TABLE_B AS B WHERE A.ID = B.ID
|--Nested Loops(Inner Join, OUTER REFERENCES:([A].[ID]))
|--Clustered Index Scan(OBJECT:(@TABLE_A AS [A]))
|--Clustered Index Seek(OBJECT:(@TABLE_B AS [B]), SEEK:([B].[ID][email protected]_A.[ID] as [A].[ID]) ORDERED FORWARD)
SELECT A.Data, B.Data FROM @TABLE_A AS A INNER JOIN @TABLE_B AS B ON A.ID = B.ID
|--Nested Loops(Inner Join, OUTER REFERENCES:([A].[ID]))
|--Clustered Index Scan(OBJECT:(@TABLE_A AS [A]))
|--Clustered Index Seek(OBJECT:(@TABLE_B AS [B]), SEEK:([B].[ID][email protected]_A.[ID] as [A].[ID]) ORDERED FORWARD)
Итак, короткий ответ - не нужно переписывать, если вы не тратите много времени на чтение их каждый раз, когда вы их поддерживаете?
Ответ 4
Это больше выбор синтаксиса. Я предпочитаю группировать условия соединения с моими соединениями, поэтому я использую синтаксис INNER JOIN
SELECT a.someRow, b.someRow
FROM tableA AS a
INNER JOIN tableB AS b
ON a.ID = b.ID
WHERE b.ID = ?
(? являющийся заполнителем)
Ответ 5
В вашем примере ничего не работает с синтаксисом. Синтаксис "INNER JOIN" обычно называют синтаксисом "ANSI" и появился после стиля, показанного в вашем примере. Он существует, чтобы прояснить тип/направление/составляющие соединения, но обычно не функционально отличается от того, что у вас есть.
Поддержка соединений ANSI является платформой для каждой базы данных, но она более или менее универсальна в наши дни.
В качестве побочного примечания одним дополнением с синтаксисом ANSI является "ПОЛНАЯ ВНЕШНЯЯ СОЕДИНИТЕЛЬ" или "ПОЛНАЯ ПРИСОЕДИНЯЙТЕСЬ".
Надеюсь, что это поможет.
Ответ 6
В общем:
Используйте ключевое слово JOIN для связывания первичных ключей и внешних ключей (например, "join" ).
Используйте предложение WHERE, чтобы ограничить набор результатов только теми учетными записями, которые вас интересуют.
Ответ 7
Единственная проблема, которая может возникнуть, заключается в том, что вы пытаетесь смешивать старое соединение "в стиле запятой" с соединениями SQL-92 в одном запросе, например, если вам нужно одно внутреннее соединение и другое внешнее соединение.
SELECT *
FROM table1 AS a, table2 AS b
LEFT OUTER JOIN table3 AS c ON a.column1 = c.column1
WHERE a.column2 = b.column2;
Проблема в том, что последние стандарты SQL говорят, что JOIN оценивается перед объединением запятой. Таким образом, ссылка на "a" в предложении ON дает ошибку, поскольку имя корреляции еще не определено, поскольку это предложение ON вычисляется. Это очень запутанная ошибка.
Решение состоит в том, чтобы не смешивать два стиля объединений. Вы можете продолжать использовать стиль запятой в своем старом коде, но если вы напишете новый запрос, преобразуйте все соединения в стиль SQL-92.
SELECT *
FROM table1 AS a
INNER JOIN table2 AS b ON a.column2 = b.column2
LEFT OUTER JOIN table3 AS c ON a.column1 = c.column1;
Ответ 8
Я избегаю неявных объединений; когда запрос действительно большой, они делают код сложным для расшифровки
С явным соединением и хорошим форматированием код более читабельен и понятен без комментариев.
Ответ 9
Еще одна вещь, которую следует учитывать в синтаксисе старого соединения, заключается в том, что очень легко получить соединение с карточками случайно, так как нет предложения on. Если ключевое слово Distinct находится в запросе и использует старые сочетания стилей, преобразуйте его в стандартное соединение ANSI и посмотрите, все ли вам нужны разные. Если вы исправляете случайную сортировку, этот способ значительно улучшает производительность, переписывая, чтобы указать соединения и поля объединения.
Ответ 10
Это также зависит от того, будете ли вы просто делать внутренние соединения таким образом или внешние соединения. Например, синтаксис MS SQL Server для внешних соединений в предложении WHERE (= * и * =) может давать разные результаты, чем синтаксис OUTER JOIN и больше не поддерживается (http://msdn.microsoft.com/en-us/library/ms178653(SQL.90).aspx) в SQL Server 2005.