Подтвердить что ты не робот

Что-то не так с объединениями, которые не используют ключевое слово 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:

Резюме ответа: в этом вопросе нет ничего плохого, но использование ключевых слов, скорее всего, сделает код более удобочитаемым/поддерживаемым.

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

СПАСИБО за ваши ответы!

4b9b3361

Ответ 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.