Есть ли существенная разница между запросами, объединенными предложениями WHERE, и запросами, использующими фактическое JOIN?

32

В « Изучение SQL трудным путем» (упражнение шестое) автор представляет следующий запрос:

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

а затем продолжает говорить, что:

Есть на самом деле другие способы заставить эти виды запросов работать, называемые "соединения". Я пока избегаю этих концепций, потому что они безумно запутывают. Просто пока придерживайтесь этого способа присоединения к таблицам и игнорируйте людей, которые пытаются сказать [вам], что это как-то медленнее или «низкий класс».

Это правда? Почему или почему нет?

Роберт Харви
источник
3
Я не думаю, что это так, но вы можете попробовать сделать EXPLAIN, чтобы увидеть, есть ли разница в выполнении запроса.
GrandmasterB
6
Я хотел бы указать на противоречивые сигналы работы с «Жестким путем» в названии, пропускающем концепцию «потому что они безумно сбивают с толку». Но, может быть, просто мое представление о том, каким должен быть «трудный путь», неверно. Но опять же, может и нет.
Миндвин
7
JOIN очень хорошо переносит намерение (объединение таблиц), что оставляет часть WHERE для реальных фильтров и делает ее немного проще для чтения. (помимо других важных последствий)
Th 00 мс с
2
Вы изучаете SQL трудным путем, если автор не может быть обеспокоен написанием простых объединений! Как говорит ThomasS, при использовании JOIN намерения становятся более понятными, а предложения WHERE становятся намного проще. Также использование JOIN лучше иллюстрирует теорию множеств, которая лежит в основе SQL.
Даниэль Холлинрейк
1
Не уверен, что я чувствую к чему-то, что имеет целью научить вас чему-то, говоря: «Но, эй, мы собираемся пропустить эту фундаментальную концепцию, потому что это банановые бананы». Я думаю, что в итоге я искал другой источник для изучения. В какой-то момент вам нужно будет выполнять внешние соединения и перекрестные соединения и знать, как их выполнять.
Морис Ривз

Ответы:

23

При авторском подходе обучение ВНЕШНИМ СОЕДИНЕНИЯМ становится намного сложнее. Предложение ON в INNER JOIN никогда не было ошеломляющим для меня, как и многие другие вещи. Может быть, это потому, что я никогда не учился по-старому. Я хотел бы подумать, что есть причина, по которой мы избавились от этого, и это не было самодовольным, и мы назвали этот метод низким классом.

Это верно в очень узком сценарии, который создал автор:

  • Такой начальный уровень SQL, что использование ON является сложным
  • Только с учетом JOIN / INNER JOIN, а не каких-либо внешних соединений
  • Изолированный кодер, который не должен ни читать чужой код, ни иметь людей, имеющих опыт использования ПО для чтения / использования их кода.
  • Не требует сложных запросов с большим количеством: таблиц, если, но и или или.

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

Select * from table
select this, something, that from table
select this from table where that = 'this'
select this from table join anothertable on this.id = that.thisid

Концепции объединения и фильтрации таблиц на самом деле не одинаковы. Изучение правильный синтаксис теперь будет иметь больше Переходящий , когда вы узнаете OUTER JOINS если автор не намерен на обучение устаревшие / устаревшие вещи , как: *= or =*.

JeffO
источник
5
Причина, по которой оператор JOIN был добавлен, заключалась в том, что не было стандарта для выражения внешних объединений, поэтому у каждого поставщика базы данных был свой собственный «специальный» (несовместимый) синтаксис для него. У Oracle IIRC было *=или =*указано левое или правое внешнее объединение, другое, которое я использовал, поддерживало только левое внешнее объединение с использованием |=оператора.
TMN
1
@TMN IIRC Oracle использовал +=или, может быть, это было =+. Я считаю, что это *=был Transact-SQL (Sybase и позже MS-SQL). Тем не менее, хороший момент.
Дэвид
1
Когда все становится сложным (ИМХО), это когда у вас есть смесь внутренних и внешних объединений. В такой ситуации, я должен признаться, я иногда прибегаю к «низкоуровневой» технике выполнения моих объединений в WHEREпредложении. (Я слышал, что это называется тэта-присоединением , но я не уверен, что это правильно.)
Дэвид
Операторы IIRC, такие как «больше чем» или «равно», иногда назывались «тета-операторами», но поиск в Google приводит к некоторой операции в исчислении.
Уолтер Митти
12

Будет ли он медленнее, зависит от оптимизатора запросов и от того, как он упростит запрос (на самом деле то, что вы пишете, не то, что выполняется). Однако большая проблема с этой цитатой состоит в том, что она полностью игнорирует тот факт, что существуют различные типы объединений, которые работают совершенно по-разному. Например, то, что говорится, (теоретически) верно для inner joins, но не верно для outer joins( left joinsи right joins).

Локк
источник
9
+1 Для других типов объединений. Большинство моих объединений либо либо, INNER JOINлибо LEFT OUTER JOIN. Они не "безумно смущают". SQL может стать безумно запутанным, но это не пример.
mgw854 15.01.15
по теме , но если заявление быть различными типами присоединиться к S или типов присоединиться ?
user1451111
9

Автор представляет простой случай, когда можно использовать старый или новый синтаксис. Я не согласен с его / ее утверждением о том, что объединения приводят в замешательство, поскольку объединение таблиц является фундаментальной концепцией SQL-запросов. Поэтому, возможно, автору следовало потратить некоторое время на то, чтобы объяснить, как работает JOINS, прежде чем произносить высказанное мнение, а также выполнить пример запроса к нескольким таблицам.

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

  • Выберите критерии
  • Присоединяйтесь Критерии
  • Критерии фильтра

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

Кроме того, можно получить декартово произведение, забыв критерии объединения в предложении фильтра:

 person_pet.person_id = person.id

используя старый синтаксис.

Использование более нового синтаксиса также определяет, как должно происходить соединение, что важно для того, хотите ли вы INNER, LEFT OUTER и т. Д., Поэтому он более явный в отношении синтаксиса JOIN, который, IMHO, повышает читаемость для тех, кто не знаком с объединением таблиц.

Джон Рейнор
источник
5

Не должно быть, анализатор запросов должен генерировать эквивалентное внутреннее представление для эквивалентных запросов независимо от того, как они написаны. Автор просто использует синтаксис pre-SQL-92, поэтому он упоминает, что его можно рассматривать как «старомодный» или «низший класс». Внутри анализатор и оптимизатор должны генерировать один и тот же план запроса.

TMN
источник
5

Я изучил SQL таким образом, включая *=синтаксис для внешних объединений. Для меня это было очень интуитивно понятно, так как все отношения имели равный приоритет и лучше выполняли настройку запросов в виде серии вопросов: что вы хотите? Откуда вы их хотите? Какие из них вы хотите?

Делая joinсинтаксис, он более сильно нарушает мыслительный процесс по отношению к отношениям. И лично я нахожу код гораздо менее читабельным, а таблицы и отношения перемешаны.

По крайней мере, в MSSQL нет существенной разницы в производительности запросов, при условии, что вы используете тот же порядок объединения. Тем не менее, существует одна очевидная, огромная проблема с изучением (и использованием) SQL таким образом. Если вы забудете одно из ваших отношений, вы получите неожиданные побочные продукты. Который в базе данных любого нетривиального размера является чрезмерно дорогим (и опасным для невыборщиков!). Гораздо сложнее забыть отношение при использовании joinсинтаксиса стиля.

Telastyn
источник
7
Это реляционная база данных, поэтому отношения очень важны для запроса. Мне лично гораздо сложнее разобраться в запросе, который смешивает истинные фильтры (foo.x = 5) со связями (foo.x = bar.x). Движок может легко оптимизировать это в объединение, но человек по существу должен рассуждать об этом построчно, в отличие от наборов и подмножеств.
Aaronaught
4

Существует два аспекта: производительность и ремонтопригодность .

Ремонтопригодность / Читаемость

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

Что выглядит лучше и читабельнее?

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e
inner join HumanResources.EmployeeDepartmentHistory edh
on e.BusinessEntityID = edh.BusinessEntityID
inner join HumanResources.Department d
on edh.DepartmentID = d.DepartmentID
where d.Name = 'Engineering';

Или...

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e, 
HumanResources.EmployeeDepartmentHistory edh,
HumanResources.Department d
where e.BusinessEntityID = edh.BusinessEntityID
and edh.DepartmentID = d.DepartmentID
and d.Name = 'Engineering';

Лично для меня первое вполне читабельно. Вы видите, что мы соединяем таблицы с INNER JOIN, что означает, что мы вытягиваем строки, которые соответствуют в последующем предложении соединения (т. Е. «Объединяем Employee с EmployeeDepartmentHistory в BusinessEntityID и включаем эти строки»).

Последнее, запятая ничего не значит для меня. Это заставляет меня задуматься о том, что вы делаете со всеми этими WHEREпредикатами.

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

Есть на самом деле другие способы заставить эти виды запросов работать, называемые "соединения"

Они все присоединяются. Даже запятые это соединение. Тот факт, что автор не называет их, это действительно их падение ... это не очевидно. Это должно быть очевидно. Вы объединяете реляционные данные, независимо от того, указали ли вы JOINили ,.

Спектакль

Это определенно будет зависеть от RDBMS. Я могу говорить только от имени Microsoft SQL Server. По производительности они эквивалентны. Откуда вы знаете? Захватите планы после выполнения и посмотрите, что именно делает SQL Server для каждого из этих операторов:

введите описание изображения здесь

На изображении выше я подчеркнул, что я использую оба запроса, как указано выше, отличающиеся только явными символами для соединения ( JOINпротив ,). SQL Server делает то же самое.

Резюме

Не используйте запятые. Используйте явные JOINзаявления.

Томас Стрингер
источник
Я выучил ВНУТРЕННИЕ СОЕДИНЕНИЯ задолго до того, как понял, что вариант с предложениями WHERE эквивалентен, и оба ваших примера выглядят очень читабельными для меня. Тот, с WHERE и запятыми, может быть еще более читабельным. Я думаю, что там, где это происходит, речь идет о больших сложных запросах, а не об этих относительно простых.
Роберт Харви
Дело в том, что думать, что вариант с запятой не является реляционным соединением, вообще не правильно.
Томас Стрингер
Я думаю, что вы неправильно интерпретируете запятые как объединения. Запятые просто отдельные таблицы; это условия WHERE, которые создают соединения, а не запятые.
Роберт Харви
1
Я могу совершенно определенно сказать, что в предложениях предикатов нет никакого присоединения. Я думаю, что вы неправильно интерпретируете конструкции вашего реляционного запроса. Вы пробовали вводить запятую без предложений WHERE? Это все еще работает. Это декартово соединение. Как вы думаете, что вы получаете, используя запятые? Пожалуйста, не говорите, что вы пытаетесь спасти персонажей.
Томас Стрингер
1
Я бы сказал, что первое лучше, потому что ваши намерения прояснились. Здесь гораздо меньше двусмысленности.
Даниэль Холлинрейк
4

Нет, это совсем не так. Автор настраивает своих читателей на путаницу и поощряет программирование грузового культа, которое позволяет избежать очень сильного структурного различия между стандартным синтаксисом и этим более старым вариантом, который он предпочитает. В частности, загроможденное предложение WHERE усложняет выяснение того, что делает его запрос особенным.

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

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

Грубо говоря, выше:

Получите ID питомца, ИМЯ, ВОЗРАСТ и СМЕРТЬ для всех питомцев, person_pet и лиц, у которых ID питомца совпадает с pet_id person_pet, а person_id этой записи совпадает с person_id человека, чье имя FIRST_NAME - "Zed"

С такой ментальной картой читатель (который по какой-то причине пишет SQL вручную) может очень легко совершить ошибку, возможно, пропустив одну или несколько таблиц. И читателю кода, написанного таким образом, придется работать усерднее, чтобы точно понять, что пытается сделать автор SQL. («Сложнее» находится на уровне чтения SQL с подсветкой синтаксиса или без нее, но разница все равно больше нуля.)

Есть причина, почему JOIN распространены, и это старый классический слух «разделения проблем». В частности, для SQL-запроса есть веская причина отделить структуру данных от их фильтрации.

Если запрос написан чище, например

SELECT pet.id, pet.name, pet.age
FROM pet
  JOIN person_pet ON pet.id = person_pet.pet_id
  JOIN person ON person.id = person_pet.person_id
WHERE 
  person.first_name = "Zed";

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


Конечно, любая современная система баз данных не должна видеть значимой разницы между этими двумя стилями. Но если бы производительность базы данных была единственным фактором, SQL-запрос также не имел бы пробелов или заглавных букв.

DougM
источник
2
Поскольку я уже несколько раз слышал этот рефрен, позвольте мне сыграть адвоката дьявола. Learn X the Hard Way - это техническая глубина; Любой, кто хорошо разбирается в SQL, должен знать, что оба подхода эквивалентны с точки зрения результатов, которые они производят.
Роберт Харви
1
Я вижу это, но автор не просто утверждает, что они эквивалентны утверждениям достойного SQL-сервера; они утверждают, что использование JOIN "сбивает с толку", то есть путь, по которому ожидает грязный код. («Нет, не используйте LINQ, просто напишите оператор FOR вручную.» «Компилятору не важно, как я называю этот метод, поэтому нет причин не называть его FN1»)
DougM
3

Парень делает классическую ошибку. Он пытается преподавать абстрактную концепцию с конкретной реализацией. Как только вы это сделаете, вы попадете в этот беспорядок.

Нужно было сначала научить основным понятиям базы данных, а затем показать SQL как один из способов их описания.

Левые и правые соединения, можно утверждать, что они не имеют большого значения. Outer Join, вы можете использовать старый *=и =*синтаксис.

Теперь вы можете утверждать, что синтаксис проще, но только для простых запросов. Как только вы начинаете пытаться выполнить сложный запрос с этой версией, вы можете попасть в ужасную неразбериху. «Новый» синтаксис не был введен, чтобы вы могли делать сложные запросы, он был таким, чтобы вы делали сложные запросы в удобочитаемом и, следовательно, удобном для обслуживания виде.

Тони Хопкинсон
источник
3
«Learn X the Hard Way» - это другой подход к обучению. Вы пишете код, а потом понимаете это позже.
Роберт Харви
7
@RobertHarvey Это не другой подход к обучению, он стандартный. Позже случается, только если вы все еще на месте, когда колеса отрываются. слишком много людей, пишущих на SQL, думают, что таблица представляет собой прямоугольный массив ячеек, чтобы быть уверенными в этом методе.
Тони Хопкинсон
2

Пример эквивалентен простой переформулировке с внутренними соединениями. Разница заключается только в дополнительных возможностях, которые предоставляет синтаксис JOIN. Например, вы можете указать порядок, в котором обрабатываются столбцы двух задействованных таблиц; см., например, https://stackoverflow.com/a/1018825/259310 .

Полученная мудрость заключается в том, чтобы в случае сомнений писать свои запросы так, чтобы они были более читабельными. Но легче ли читать формулировки «ПРИСОЕДИНИТЬСЯ» или «ГДЕ», это вопрос личных предпочтений, поэтому обе формы так широко распространены.

Килиан Фот
источник
Хороший ответ, хотя, используете ли вы WHEREили помещаете предложение в JOINутверждение, на самом деле может повлиять на производительность в зависимости от оптимизатора запросов. Я видел это не раз.
Локк
Мой опыт влияния на производительность таков: неявные объединения позволят оптимизатору запросов иметь больше возможностей для оптимизации запроса, что может показаться хорошим, но может быть проблемой. В частности, оптимизатор запросов может настраивать запрос в процессе разработки, а в производстве - другим. Оптимизатор может быть обманут в настройке, которая снижает производительность. Я рекомендую использовать явный синтаксис объединения И подтвердить, что при объединении используются столбцы с индексами, обеспечивающими предсказуемость производительности.
Майкл Поттер
2

Когда я изучал SQL, формы INNER JOIN, LEFT JOIN и т. Д. Не существовали. Как уже говорилось в других ответах, на разных диалектах SQL каждое реализовало внешние объединения с использованием своеобразного синтаксиса. Это повредило переносимость кода SQL. Объединение языка потребовало некоторых изменений, и LEFT JOIN и т. Д. Были тем, на чем они остановились.

Это правда, что для каждого INNER JOIN может быть записано эквивалентное запятое соединение с условием соединения в предложении WHERE. Мне потребовалось некоторое время, чтобы перейти от симпатии к старой форме к предпочтению новой формы. По-видимому, автор «Изучения SQL трудным путем» все еще считает, что старый способ проще.

Есть ли различия? Ну да, есть. Во-первых, INNER JOIN с предложением ON раскрывает намерение автора более четко, чем соединение старого стиля. Тот факт, что предложение ON на самом деле является условием соединения, а не каким-либо другим видом ограничения, более очевиден. Это делает код, который использует INNER JOIN, легче для изучения при чтении, чем старый стиль. Это важно при поддержке чужого кода.

Второе отличие заключается в том, что новый стиль значительно облегчает оптимизатору запросов обнаружение выигрышной стратегии. Это очень маленький эффект, но это реально.

Третье отличие состоит в том, что когда вы учитесь, используя INNER JOIN (или просто JOIN), это облегчает изучение LEFT JOIN и т. Д.

Кроме того, нет никакой существенной разницы.

Уолтер Митти
источник
0

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

Если вы не используете ключевое слово «join», это упрощает переход от формальной логики к SQL.

Но если, как и 99% людей, вы не наслаждались формальной логикой в ​​своей математике, то ключевое слово join облегчает изучение. Раньше в университете SQL представлялся просто как способ записать формальные логические запросы ...

Ян
источник