Внутреннее соединение против Где

257

Есть ли разница в производительности (в оракуле) между

Select * from Table1 T1 
Inner Join Table2 T2 On T1.ID = T2.ID

И

Select * from Table1 T1, Table2 T2 
Where T1.ID = T2.ID

?

хуан
источник
1
для
справки:
12
@ BlackTigerX: разные результаты? Были ли какие-либо внешние соединения? Потому что я не вижу, как будут отличаться результаты в inner join ... onсравнении с положением эквивалентных критериев соединения в whereпредложении.
Шеннон Северанс
в старой версии базы данных Oracle не существуетjoin
MajidTaheri
2
@MajidTaheri: о каком возрасте версии Oracle вы говорите? Любая версия, поддерживаемая Oracle, поддерживает обозначение JOIN.
Джонатан Леффлер
Ищите общие ответы или лучшие практики, основанные на тривиальных случаях. Хотелось бы увидеть «повторное совпадение» с более сложными пунктами where, включающими несколько условий AND'd. По крайней мере, в SQL Server есть точка пересечения.
Crokusek

Ответы:

195

Нет! Тот же план выполнения, посмотрите на эти две таблицы:

CREATE TABLE table1 (
  id INT,
  name VARCHAR(20)
);

CREATE TABLE table2 (
  id INT,
  name VARCHAR(20)
);

План выполнения запроса с использованием внутреннего соединения:

-- with inner join

EXPLAIN PLAN FOR
SELECT * FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.id;

SELECT *
FROM TABLE (DBMS_XPLAN.DISPLAY);

-- 0 select statement
-- 1 hash join (access("T1"."ID"="T2"."ID"))
-- 2 table access full table1
-- 3 table access full table2

И план выполнения для запроса с использованием предложения WHERE.

-- with where clause

EXPLAIN PLAN FOR
SELECT * FROM table1 t1, table2 t2
WHERE t1.id = t2.id;

SELECT *
FROM TABLE (DBMS_XPLAN.DISPLAY);

-- 0 select statement
-- 1 hash join (access("T1"."ID"="T2"."ID"))
-- 2 table access full table1
-- 3 table access full table2
kiewic
источник
4
Я действительно хочу посмотреть, есть ли официальные документы от Oracle, говорящие об этом
4 Leave Cover
68

Если оптимизатор запросов делает свою работу правильно, между этими запросами не должно быть никакой разницы. Это всего лишь два способа указать один и тот же желаемый результат.

Крейг Трейдер
источник
22
Да, производительность должна быть такой же. Но синтаксис SELECT * FROM Table1, Table2 WHERE ... ЗЛО!
Джоэл Коухорн
2
Я считаю, что гораздо проще понять для внутренних соединений, чем синтаксис SQL-92. Ваш пробег может варьироваться.
Крейг Трейдер,
25
Я считаю, что синтаксис WHERE легче читать, чем INNER JION - я думаю, он похож на Vegemite. Большинство людей в мире, вероятно, находят это отвратительным, но дети, воспитанные, едят это, любят это.
ScottCher
3
Вегемит действительно противный, но опять же я люблю драку. Пойди разберись.
StingyJack
2
@Darryl Я думаю, что JOINs легче читать, потому что условие для объединения таблиц определяется тут же, а не «где-то» в WHEREпредложении. Я предпочитаю зарезервировать WHEREпункт для ограничения набора данных (например WHERE DATE > (SYSDATE - 1)), а не определять, как таблицы связаны друг с другом (например WHERE T1.ID = T2.ID). Для небольшой таблицы, такой как рассматриваемый пример, не имеет большого значения, но для больших запросов, включающих несколько таблиц и несколько условий, я думаю, что это делает запрос намного проще для понимания.
ImaginaryHuman072889
61

Они должны быть точно такими же. Однако, как практика кодирования, я бы предпочел увидеть Join. Это ясно выражает ваши намерения,

Nescio
источник
8
Я согласен. Особенно, если вы присоединяетесь к нескольким таблицам, намного проще проанализировать оператор выбора, если вы делаете явные объединения.
Пол Мори
13
На самом деле. Объединения представляют собой семантические отношения между двумя наборами данных, но где предлагается отфильтрованный набор. +1
EightyOne Unite
26

С помощью JOIN делает код более легким для чтения, поскольку он не требует пояснений.

Там нет разницы в скорости ( я только что проверил ) и план выполнения такой же.

user21241
источник
Спасибо. я искал сжатие скорости между этими двумя методами.
Фархад Наваяздан
14

Я не знаю об Oracle, но я знаю, что старый синтаксис устарел в SQL Server и со временем исчезнет. Прежде чем использовать этот старый синтаксис в новом запросе, я проверю, что Oracle планирует с ним делать.

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

И опять же, я не знаю Oracle конкретно, но я знаю, что версия левого соединения старого стиля SQL Server имеет недостатки даже в SQL Server 2000 и дает противоречивые результаты (иногда левое соединение, иногда перекрестное соединение), поэтому никогда не следует используемый. Надеюсь, Oracle не сталкивается с той же проблемой, но, конечно, левые и правые объединения могут быть намного сложнее правильно выразить в старом синтаксисе.

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

HLGEM
источник
1
Аминь, брат. Долой СОЕДИНИТЕЛЕЙ !!
ScottCher
14

[Для получения бонусного балла ...]

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

Как и все остальные, они функционально одинаковы, однако JOIN более четко выражает намерение. Поэтому он может помочь оптимизатору запросов в текущих версиях Oracle в определенных случаях (я понятия не имею, так ли это), он может помочь оптимизатору запросов в будущих версиях Oracle (никто не имеет представления) или может помочь, если Вы меняете поставщика базы данных.

Крис Гилл
источник
2
Или ... легко измените ВНУТРЕННИЕ СОЕДИНЕНИЯ на ЛЕВЫЕ СОЕДИНЕНИЯ, чтобы вы увидели, какое соединение вызывает пропуск ожидаемых строк. Я делаю это, потому что я делаю весь запрос одновременно. Если вы прокомментируете INNER JOINS, вы должны выполнить процесс исключения. Это займет больше времени. Но +1 для вас, потому что это одна из моих любимых причин для ВНУТРЕННИХ СОЕДИНЕНИЙ кроме читабельности!
Мэтью Макпик
13

Они логически идентичны, но в более ранних версиях Oracle, в которых использовался синтаксис ANSI, часто возникали ошибки с ним в более сложных случаях, поэтому вы иногда сталкиваетесь с сопротивлением разработчиков Oracle при его использовании.

Дэвид Олдридж
источник
Более ранние версии Oracle имели ошибки с этим? Как рано? Какая версия (ы)?
ScottCher
У Металинка есть детали ... они всплывают повсюду.
Дэвид Олдридж
7

Производительность должна быть одинаковой, но я бы предложил использовать версию join из-за улучшенной ясности, когда речь идет о внешних объединениях.

Также можно избежать непреднамеренных декартовых продуктов, используя версию join.

Третий эффект - более легкий для чтения SQL с более простым условием WHERE.

STILI
источник
Я действительно думаю, что ключ к непреднамеренным последствиям, когда критерии неоднозначны. Если вы указываете тип объединения, вы точно знаете, что вы получаете. Я обнаружил, что разные базы данных и даже разные версии одной и той же платформы баз данных будут обрабатывать нулевые значения по-разному в подразумеваемом соединении. Когда вы указываете левый / правый внутренний / внешний, вы тратите время на то, чтобы подумать, что является правильным. Когда вы используете неоднозначный метод, вы предполагаете, что он работает так, как вы надеетесь / намереваетесь.
Стив Каллестад
6

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

select *
from Table1 inner join Table2 using (ID);

Это также имеет тот же план запроса, конечно.

cheduardo
источник
Я rollbacked издания , потому что предыдущая редакция изменила смысл ответа
JUAN
5

В сценарии, где таблицы находятся в 3-й нормальной форме, соединения между таблицами не должны изменяться. Т.е. присоединяйтесь к ЗАКАЗЧИКАМ, и ОПЛАТЫ всегда должны оставаться неизменными.

Однако мы должны отличать объединения от фильтров . Объединения связаны с отношениями, а фильтры - с разделением целого.

Некоторые авторы, ссылаясь на стандарт (например, Джим Мелтон; Алан Р. Саймон (1993). Понимание нового SQL: Полное руководство. Морган Кауфманн. С. 11–12. ISBN 978-1-55860-245-8.) , писал о преимуществах применения синтаксиса JOIN над таблицами, разделенными запятыми, в предложении FROM.

Я полностью согласен с этой точкой зрения.

Существует несколько способов написания SQL-кода и достижения тех же результатов, но для многих из тех, кто работает в команде, удобочитаемость исходного кода является важным аспектом, и, конечно, отделить то, как таблицы связаны друг с другом от определенных фильтров, было большим скачком в смысле выяснения источника код.

abrittaf
источник
Внутреннее соединение означает перекрестное соединение где. Запятая является перекрестным соединением с более низким приоритетом, чем ключевые соединения. На vs «фильтр» не имеет значения для внутреннего соединения. Национальные федерации не имеют отношения к запросам. Ничто в стандарте не способствует объединению ключевых слов через запятую. Тривиальные оптимизации относятся и к тому, и к чему. Этот ответ - куча заблуждений.
Philipxy
1) Я думаю, @philipxy пытается сказать: «В предложениях FROM таблицы, разделенные запятой, имеют то же значение, что и таблицы CROSS JOINed». Я согласен с этим. Конечно, вы можете придерживаться старого синтаксиса, который может сосуществовать с предложениями JOIN. Оптимизаторы СУБД прекрасно понимают оба случая как одинаковые (если они, конечно, эквивалентны) и разработают один и тот же план.
abrittaf
4

В PostgreSQL, безусловно, нет никакой разницы - они оба соответствуют одному и тому же плану запросов. Я на 99% уверен, что это касается и Oracle.

Ник Джонсон
источник
2

Они оба являются внутренними объединениями, которые делают одно и то же, один просто использует более новый синтаксис ANSI.

Боб Геттис
источник
2

Функционально они такие же, как было сказано. Я согласен, хотя, что объединение лучше для описания именно того, что вы хотите сделать. Много раз я думал, что знаю, как я хочу что-то запрашивать, пока я не начал делать объединения и не понял, что хочу сделать запрос, отличный от исходного в моей голове.

MattC
источник
1

Это правда, что функционально оба запроса должны обрабатываться одинаково. Однако опыт показывает, что если вы выбираете из представлений, которые используют новый синтаксис объединения, важно также структурировать свои запросы, используя его. Оптимизатор Oracle может запутаться, если представление использует оператор «join», но запрос, обращающийся к представлению, использует традиционный метод объединения в предложении «where».

JoshL
источник
Это больше проблема с представлениями, чем с соединениями вообще.
существует
0

Хотя идентичность двух запросов кажется очевидной, иногда происходят странные вещи. Я пришел по запросу, который имеет разные планы выполнения при перемещении предиката соединения из JOIN в WHERE в Oracle 10g (для плана WHERE лучше), но я не могу воспроизвести эту проблему в упрощенных таблицах и данных. Я думаю, что это зависит от моих данных и статистики. Оптимизатор является довольно сложным модулем и иногда он ведет себя волшебно.

Вот почему мы не можем ответить на этот вопрос в целом, потому что это зависит от внутренних данных БД. Но мы должны знать, что ответ должен быть « без различий ».

greatvovan
источник
0

У меня была эта загадка сегодня, когда я проверял время ожидания одного из наших sp в производственной среде, вместо этого я изменил внутреннее соединение таблицы, построенной из xml-фида, на условие 'where' .... среднее время выполнения теперь составляет 80 мс для 1000 выполнений, тогда как до того, как среднее значение exec составило 2,2 секунды ... главное отличие в плане выполнения - это исчезновение поиска ключа ... Сообщение, о котором вы не узнаете, пока не протестируете оба метода.

веселит.

trbullet81
источник
0

Как сказал киевик, план выполнения такой же.

Оператор JOIN легче читать, так что легче не забывать условие ON и получать декартово произведение. Эти ошибки могут быть довольно трудно обнаружить в длинных запросах с использованием нескольких объединений типа: SELECT * FROM t1, t2 WHERE t1.id = t2.some_field.

Если вы забудете только одно условие соединения, вы получите очень длинный запрос, возвращающий слишком много записей ... действительно слишком много. Некоторые люди используют DISTINCT для исправления запроса, но он все еще очень длинный для выполнения.

Именно поэтому использование оператора JOIN, безусловно, является лучшей практикой: лучшая ремонтопригодность и лучшая читаемость.

Более того, если я хорошо помню, JOIN оптимизирован в отношении использования памяти.

ROQUEFORT Франсуа
источник
0

У меня есть дополнение к этому хорошему ответу :

Это то, что определяется как SQL92 и SQL89 соответственно, между ними нет разницы в производительности, хотя вы можете опустить слово INNER (достаточно просто использовать JOIN, и в простейшем запросе вы сохраняете 5 нажатий клавиш, теперь представьте, сколько штрихов в большом из них).

Ivanzinho
источник