Является ли объединение эквивалентным фильтруемому декартовому произведению? [Дубликат]

Обновление:

Как упоминается в первом ответе, с ES6 / Babel вы можете теперь создавать многострочные строки просто с помощью обратных ссылок:

const htmlString = `Say hello to 
multi-line
strings!`;

Интерполирующие переменные являются популярная новая функция, которая поставляется с строками с разделителями обратной ссылки:

const htmlString = `${user.name} liked your post about strings`;

Это просто переходит к конкатенации:

user.name + ' liked your post about strings'

Оригинальный ответ ES5:

Руководство по стилю JavaScript в стиле Google рекомендует использовать конкатенацию строк вместо экранирования строк:

Не делайте этого:

var myString = 'A rather long string of English text, an error message \
                actually that just keeps going and going -- an error \
                message to make the Energizer bunny blush (right through \
                those Schwarzenegger shades)! Where was I? Oh yes, \
                you\'ve got an error and all the extraneous whitespace is \
                just gravy.  Have a nice day.';

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

Вместо этого используйте конкатенацию строк:

var myString = 'A rather long string of English text, an error message ' +
               'actually that just keeps going and going -- an error ' +
               'message to make the Energizer bunny blush (right through ' +
               'those Schwarzenegger shades)! Where was I? Oh yes, ' +
               'you\'ve got an error and all the extraneous whitespace is ' +
               'just gravy.  Have a nice day.';
765
задан Uwe Keim 14 April 2018 в 15:58
поделиться

10 ответов

INNER JOIN - это синтаксис ANSI, который вы должны использовать.

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

Его также можно легко заменить OUTER JOIN всякий раз, когда возникает необходимость.

Синтаксис WHERE более ориентирован на реляционную модель.

Результат двух таблиц JOIN ed является декартовым произведением таблиц к которому применяется фильтр, который выбирает только те строки с совпадающими столбцами.

Легче это увидеть с синтаксисом WHERE.

Что касается вашего примера, в MySQL ( и в SQL вообще) эти два запроса являются синонимами.

Также обратите внимание, что MySQL также имеет предложение STRAIGHT_JOIN.

Используя этот пункт, вы можете управлять порядком JOIN: какая таблица проверяется во внешнем цикле и какая из них находится во внутреннем цикле.

Вы не можете управлять этим в MySQL с помощью синтаксиса WHERE.

614
ответ дан Ry- 17 August 2018 в 11:29
поделиться
  • 1
    Спасибо, Квасной. У вас много деталей в ваших анах; справедливо ли говорить, что «да», эти запросы эквивалентны, но вы должны использовать внутреннее соединение, потому что оно более читаемо и проще модифицировать & quot ;? – allyourcode 25 July 2009 в 22:00
  • 2
    @allyourcode: для Oracle, SQL Server, MySQL и PostgreSQL - да. Для других систем, вероятно, тоже, но лучше проверить. – Quassnoi 26 July 2009 в 12:49
  • 3
    FWIW, используя запятые с условиями соединения в предложении WHERE, также находится в стандарте ANSI. – Bill Karwin 13 January 2010 в 23:41
  • 4
    Тем не менее, ANSI SQL-89 указывает соединения, которые должны выполняться с запятыми и условиями в предложении WHERE (без условий, соединение эквивалентно перекрестному соединению, как вы сказали). ANSI SQL-92 добавил ключевое слово JOIN и соответствующий синтаксис, но синтаксис в стиле запятой по-прежнему поддерживается для обратной совместимости. – Bill Karwin 14 January 2010 в 00:03
  • 5
    @ArvindSridharan: нет – Quassnoi 16 October 2013 в 11:19

Синтаксис ANSI join определенно более переносимый.

Я собираюсь обновить Microsoft SQL Server, и я бы также упомянул, что синтаксис = * и * = для внешних соединений в SQL Server не поддерживается (без режима совместимости) для SQL Server 2005 года и позже.

1
ответ дан Benzo 17 August 2018 в 11:29
поделиться
  • 1
    Даже в SQL Server 2000 = и = могут давать неправильные результаты и никогда не должны использоваться. – HLGEM 19 June 2009 в 19:36
  • 2
    *= и =* никогда не были ANSI и никогда не были хорошей нотой. Именно поэтому ON был необходим - для ВЗАИМОДЕЙСТВУЮЩИХ СОЕДИНЕНИЙ в отсутствие подзапросов (которые были добавлены одновременно, поэтому они фактически не нужны в CROSS & amp; INNER JOINs.) – philipxy 26 November 2015 в 23:43

Стандарт SQL: 2003 изменил некоторые правила приоритета, поэтому оператор JOIN имеет преимущество перед соединением «запятая». Это может фактически изменить результаты вашего запроса в зависимости от того, как он настроен. Это вызывает некоторые проблемы для некоторых людей, когда MySQL 5.0.12 переключился на соблюдение стандарта.

Итак, в вашем примере ваши запросы будут работать одинаково. Но если вы добавили третью таблицу: SELECT ... FROM table1, table2 JOIN table3 ON ... WHERE ...

До MySQL 5.0.12 сначала будут объединены table1 и table2, а затем table3 , Теперь (5.0.12 и далее), table2 и table3 соединяются сначала, а затем table1. Он не всегда меняет результаты, но может, и вы даже не можете этого понять.

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

10
ответ дан Brent Baisley 17 August 2018 в 11:29
поделиться
  • 1
    Стандартный SQL не изменился. MySQL был просто неправильным и amp; теперь правильно. См. Руководство по MySQL. – philipxy 21 April 2018 в 04:43

Синтаксис неявного соединения ANSI является более старым, менее очевидным и не рекомендуется.

Кроме того, реляционная алгебра допускает взаимозаменяемость предикатов в предложении WHERE и INNER JOIN, поэтому даже INNER JOIN с предложениями WHERE могут иметь предикаты, переупорядоченные оптимизатором.

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

Иногда это включает в себя создание INNER JOIN относительно «неполным» и поместив некоторые из критериев в WHERE просто, чтобы сделать списки критериев фильтрации более легко поддерживаемыми.

Например, вместо:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
    AND c.State = 'NY'
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
    AND a.Status = 1

Запись:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
WHERE c.State = 'NY'
    AND a.Status = 1

Но это зависит, конечно.

55
ответ дан Cade Roux 17 August 2018 в 11:29
поделиться
  • 1
    Ваш первый фрагмент определенно причиняет боль моему мозгу. Кто-нибудь на самом деле это делает? Если я встречу кого-то, кто это сделает, нормально ли мне бить его по голове? – allyourcode 25 July 2009 в 22:10
  • 2
    Я определяю критерии, в которых это имеет смысл. Если я присоединяюсь к временной согласованной таблице поиска моментальных снимков (и у меня нет представления или UDF, который обеспечивает выбор допустимой даты), я буду включать дату вступления в действие, а не в WHERE, потому что это меньше вероятно, случайно удалятся. – Cade Roux 26 July 2009 в 02:25
  • 3
    @allyourcode: хотя редко бывает видно, что этот тип синтаксиса соединения в INNER JOINs, это довольно распространено для RIGHT JOINs и LEFT JOINS - указание более подробных сведений в предикате соединения устраняет необходимость в подзапросе и предотвращает непреднамеренное превращение внешних соединений в INNER JOINs. (Хотя я согласен, что для INNER JOINs я почти всегда ставил c.State = 'NY' в предложение WHERE) – Dave Markle 10 November 2011 в 22:33
  • 4
    @allyourcode Я определенно делаю это! И я согласен с Кейдом ... Мне любопытно, есть ли порядочная причина не для – Arth 12 August 2014 в 20:49

Другие отметили, что INNER JOIN помогает читаемости для человека, и это главный приоритет; Согласен. Позвольте мне попытаться объяснить , почему синтаксис соединения более читабельен.

Основной запрос SELECT таков:

SELECT stuff
FROM tables
WHERE conditions

Предложение SELECT сообщает нам, что мы возвращаемся; предложение FROM сообщает нам, откуда мы его получаем, а предложение WHERE сообщает нам, какие из них мы получаем.

JOIN - это утверждение о таблицах, как они связаны друг с другом (концептуально, на самом деле , в одну таблицу). Любые элементы запроса, которые управляют таблицами - откуда мы получаем материал - семантически, относятся к предложению FROM (и, конечно же, здесь идут элементы JOIN). Ввод элементов соединения в предложение WHERE объединяет то, что и где-из; поэтому предпочтительным является синтаксис JOIN.

146
ответ дан Carl Manaster 17 August 2018 в 11:29
поделиться
  • 1
    Спасибо за разъяснение, почему внутреннее соединение предпочтительнее Карла. Я думаю, что ваш ans был скрыт в других, но явный обычно лучше (да, я фанат Python). – allyourcode 25 July 2009 в 22:08
  • 2
    Семантика ON и WHERE означает, что для JOINs после последнего OUTER JOIN это не имеет значения , который вы используете. Хотя вы характеризуете ON как часть JOIN, это также фильтрация после декартова произведения. Оба ON и WHERE фильтруют декартово произведение. Но либо ON, либо подзапрос с WHERE должны использоваться before последний OUTER JOIN. (JOINs не входят в «пары столбцов». Любые две таблицы могут быть подключены к любому условию. Это всего лишь способ интерпретировать JOINs ON the equal of columns.) – philipxy 26 November 2015 в 23:33

Я также укажу, что использование более старого синтаксиса более подвержено ошибкам. Если вы используете внутренние соединения без предложения ON, вы получите синтаксическую ошибку. Если вы используете старый синтаксис и забыли одно из условий соединения в предложении where, вы получите кросс-соединение. Разработчики часто исправляют это, добавляя отдельное ключевое слово (вместо того, чтобы фиксировать соединение, потому что они все еще не понимают, что само соединение не работает), что может показаться исцеляющим проблему, но значительно замедлит запрос.

Кроме того, для обслуживания, если у вас есть крест-соединение в старом синтаксисе, как разработчик узнает, хотите ли вы его иметь (есть ситуации, когда нужны перекрестные соединения) или если это была авария, которая должна быть исправлена?

Позвольте мне указать вам на этот вопрос, чтобы понять, почему неявный синтаксис является плохим, если вы используете левые соединения. Sybase * = для Ansi Standard с двумя разными внешними таблицами для одной и той же внутренней таблицы

Plus (личный rant здесь), стандарт с использованием явных объединений старше 20 лет, что означает синтаксис неявного соединения устарел для этих 20 лет. Вы могли бы написать код приложения, используя синтаксис, устаревший в течение 20 лет? Почему вы хотите написать код базы данных?

21
ответ дан Community 17 August 2018 в 11:29
поделиться
  • 1
    @HLGEM: Хотя я полностью согласен с тем, что явные JOINs лучше, бывают случаи, когда вам просто нужно использовать старый синтаксис. Пример в реальном мире: ANSI JOIN попал в Oracle только в версии 9i, выпущенной в 2001 году, и только год назад (16 лет с момента публикации стандарта) мне пришлось поддерживать кучу установки 8i, для которой мы для выпуска критических обновлений. Я не хотел поддерживать два набора обновлений, поэтому мы разработали и протестировали обновления для всех баз данных, включая 8i, а это значит, что мы не смогли использовать ANSI JOIN. – Quassnoi 19 June 2009 в 22:37
  • 2
    +1 Интересный момент, когда вы указываете, что синтакс без INNER JOIN более подвержен ошибкам. Я смущен о вашем последнем предложении, когда вы говорите «... стандарт, использующий явные объединения, составляет 17 лет». так вы предлагаете использовать ключевое слово INNER JOIN или нет? – Marco Demaio 11 February 2011 в 19:56
  • 3
    @Marco Demaio, да всегда используйте INNER JOIN или JOIN (эти два одинаковые) или LEFT JOIN или RIGHT JOIN или CROSS JOIN и никогда не используйте неявные объединения в запятую. – HLGEM 11 February 2011 в 19:59
  • 4
    «Почему вы хотите написать код базы данных, который является [20 лет]? & quot; - Я замечаю , что вы записываете SQL, используя HAVING, который был «устаревшим», поскольку SQL начал поддерживать производные таблицы. Я также замечаю, что вы не используете NATURAL JOIN, хотя я бы сказал, что он сделал INNER JOIN «устаревшим». Да, у вас есть свои причины (нет необходимости указывать их здесь снова!): Я хочу сказать, что те, кому нравится использовать старый синтаксис, тоже имеют свои причины, а относительный возраст синтаксиса мало, если есть какая-либо значимость. – onedaywhen 14 October 2016 в 13:45
  • 5
    ГДЕ все еще в стандарте (покажи мне, где это не так). Итак, ничего устаревшего, видимо. Кроме того, "вместо фиксации соединения" показывает мне разработчика, которого следует хранить вдали от СУБД в целом, far . – Jürgen A. Erhard 23 February 2017 в 04:52

Применение условных операторов в ON / WHERE

Здесь я объяснил о шагах обработки логических запросов.


Ссылка: внутри Microsoft® SQL Server ™ 2005 T-SQL Querying Издатель: Microsoft Press Pub Дата: 07 марта 2006 г. Печать ISBN-10: 0-7356-2313-9 Печать ISBN-13: 978-0-7356-2313-2 Страницы: 640

Внутри Microsoft SQL Server ™ 2005 T-SQL Querying

(8)  SELECT (9) DISTINCT (11) TOP <top_specification> <select_list>
(1)  FROM <left_table>
(3)       <join_type> JOIN <right_table>
(2)       ON <join_condition>
(4)  WHERE <where_condition>
(5)  GROUP BY <group_by_list>
(6)  WITH {CUBE | ROLLUP}
(7)  HAVING <having_condition>
(10) ORDER BY <order_by_list>

Первым заметным аспектом SQL, который отличается от других языков программирования, является порядок в который обрабатывается кодом. В большинстве языков программирования код обрабатывается в том порядке, в котором он написан. В SQL первое обрабатываемое предложение - это предложение FROM, в то время как первое предложение SELECT, которое появляется первым, обрабатывается почти последним.

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

Краткое описание фаз обработки логических запросов

Не беспокойтесь слишком много, если описание шаги пока не имеют большого смысла. Они приведены в качестве ссылки.

  1. FROM: Декартово произведение (кросс-соединение) выполняется между двумя первыми двумя таблицами в предложении FROM и в качестве результат, создается виртуальная таблица VT1.
  2. ВКЛ: фильтр ВКЛ применяется к VT1. Только строки, для которых <join_condition> TRUE, вставляются в VT2.
  3. OUTER (join): Если задан OUTER JOIN (в отличие от CROSS JOIN или INNER JOIN), строки из сохраненного таблица или таблицы, для которых совпадение не было найдено, добавляются к строкам из VT2 в качестве внешних строк, генерируя VT3. Если в предложении FROM указано более двух таблиц, шаги с 1 по 3 применяются повторно между результатом последнего соединения и следующей таблицей в предложении FROM до тех пор, пока все таблицы не будут обработаны.
  4. ГДЕ: ГДЕ фильтр применяется к VT3. Только строки, для которых значение <where_condition> TRUE, вставлены в VT4.
  5. GROUP BY: Строки из VT4 расположены в группах на основе списка столбцов, указанного в предложении GROUP BY. VT5 генерируется.
  6. CUBE | ROLLUP: Супергруппы (группы групп) добавляются к строкам из VT5, генерируя VT6.
  7. HAVING: Фильтр HAVING применяется к VT6. В VT7 вставляются только те группы, для которых значение <having_condition> равно TRUE.
  8. SELECT: обрабатывается список SELECT, генерирующий VT8.
  9. DISTINCT: Дублирующие строки удаляются из VT8. VT9 генерируется.
  10. ORDER BY: строки из VT9 сортируются в соответствии с списком столбцов, указанным в предложении ORDER BY. Создается курсор (VC10).
  11. TOP: указанное число или процент строк выбирается с начала VC10. Таблица VT11 генерируется и возвращается вызывающему абоненту.

Поэтому, (INNER JOIN) ON будет фильтровать данные (количество данных VT будет уменьшено здесь сами) перед применением предложения WHERE. Последующие условия соединения будут выполняться с отфильтрованными данными, что улучшает производительность. После этого условие WHERE будет применяться только к условиям фильтра.

(Применение условных операторов в ON / WHERE не будет иметь большого значения в нескольких случаях. Это зависит от того, сколько таблиц вы присоединились и количество строк доступно в каждой таблице соединений)

113
ответ дан cp.engr 17 August 2018 в 11:29
поделиться
  • 1
    "Следовательно, (INNER JOIN) ON будет фильтровать данные (количество данных VT будет уменьшено здесь непосредственно) перед применением предложения WHERE. & quot; Не обязательно. Статья посвящена порядку обработки logical . Когда вы говорите, что конкретная реализация будет делать что-то еще перед другим, вы говорите о порядке выполнения внедренного . Реализациям разрешено делать любые оптимизации, которые им нравятся, до тех пор, пока результат будет таким же, как если бы реализация соответствовала логическому порядку. Джо Селко много написал об этом на Usenet. – Mike Sherrill 'Cat Recall' 4 July 2013 в 01:58
  • 2
    @rafidheen "(INNER JOIN) ON будет фильтровать данные ... перед применением предложения WHERE ... которое улучшает производительность. & quot; Хорошая точка зрения. «После этого только условие WHERE будет применять условия фильтра». Как насчет предложения HAVING? – James 30 January 2018 в 05:09
  • 3
    @James Это утверждение rafidheen неверно. См. «Оптимизация соединения» в руководстве. Также мои другие комментарии на этой странице. (И MikeSherrill'CatRecall's.) Такой "логический" описания описывают значение результата, а не как оно фактически вычисляется. И такое поведение реализации не гарантировано не изменится. – philipxy 24 June 2018 в 06:17

Я знаю, что вы говорите о MySQL, но так или иначе: В Oracle 9 явные объединения и неявные объединения будут генерировать разные планы выполнения. AFAIK, который был решен в Oracle 10+: больше нет такой разницы.

4
ответ дан João Marcus 17 August 2018 в 11:29
поделиться

У них есть другое понятное для человека значение.

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

Вы всегда должны указывать, чтобы быть читаемый.

То есть, если это встроенное отношение, используйте явное соединение. если вы согласны с слабо связанными данными, используйте предложение where.

12
ответ дан John Gietzen 17 August 2018 в 11:29
поделиться

Неявные объединения (что и называется вашим первым запросом) становятся намного более запутанными, трудными для чтения и сложными для поддержания, когда вам нужно начать добавлять в ваш запрос больше таблиц. Представьте, что вы делаете тот же запрос и тип соединения в четырех или пяти разных таблицах ... это кошмар.

Использование явного соединения (ваш второй пример) гораздо читабельнее и прост в обслуживании.

25
ответ дан matt b 17 August 2018 в 11:29
поделиться
  • 1
    Я не мог больше не согласиться. Синтаксис JOIN чрезвычайно многословен и сложен для организации. У меня есть много запросов, соединяющих 5, 10 и даже 15 таблиц с помощью предложений WHERE clause, и они прекрасно читаемы. Перезапись такого запроса с использованием синтаксиса JOIN приводит к искажению беспорядка. Это просто показывает, что нет правильного ответа на этот вопрос и что это зависит в большей степени от того, с чем вам удобно. – Noah Yetter 19 June 2009 в 21:40
  • 2
    Ной, я думаю, ты можешь быть здесь в меньшинстве. – matt b 21 June 2009 в 20:42
  • 3
    Я получаю +1 к мату и Ною. Мне нравится разнообразие :). Я вижу, откуда приходит Ной; внутреннее соединение не добавляет ничего нового в язык и, безусловно, более многословно. С другой стороны, это может сделать ваше условие «где» намного короче, что обычно означает, что его легче читать. – allyourcode 25 July 2009 в 22:05
  • 4
    Я лично пошла бы на удобочитаемость по лаконичности – matt b 27 July 2009 в 13:45
  • 5
    Я бы предположил, что любая разумная СУБД переведет два запроса в один и тот же план выполнения; однако на самом деле каждая СУБД различна, и единственный способ узнать наверняка - это фактически проверить план выполнения (т. е. вам придется самому протестировать его). – matt b 14 September 2009 в 15:53
Другие вопросы по тегам:

Похожие вопросы: