Является ли JOIN быстрее, чем ГДЕ? - PullRequest
53 голосов
/ 15 июля 2009

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

CREATE TABLE Document (
  Id INT PRIMARY KEY,
  Name VARCHAR 255
)

CREATE TABLE DocumentStats (
  Id INT PRIMARY KEY,
  DocumentId INT, -- this is a foreign key to table Document
  NbViews INT
)

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

Теперь я хочу получить все документы, которые имеют более 500 просмотров. Мне приходят на ум два решения:

SELECT *
FROM Document, DocumentStats
WHERE DocumentStats.Id = Document.Id
  AND DocumentStats.NbViews > 500

или:

SELECT *
FROM Document
INNER JOIN DocumentStats
ON Document.Id = DocumentStats.Id
WHERE DocumentStats.NbViews > 500

Оба запроса эквивалентны, или есть один способ, который намного лучше, чем другой? Если так, то почему?

Я знаю, что мой пример не идеален, и что запросы могут нуждаться в некоторой настройке, но я надеюсь, что вы поняли;)!

РЕДАКТИРОВАТЬ: как и требовалось в ответах, этот вопрос был нацелен на MSSQL, но мне было бы интересно узнать, отличается ли он для других механизмов БД (MySQL и т. Д.)

Ответы [ 10 ]

41 голосов
/ 15 июля 2009

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

17 голосов
/ 16 июля 2009

Производительность «JOIN» против «WHERE» ... все зависит от того, насколько хорошо ядро ​​базы данных способно оптимизировать запрос для вас. Он будет учитывать все индексы, которые могут у вас быть в возвращаемых столбцах, и учитывать, что производительность предложений WHERE и JOIN также зависит от самого физического файла базы данных, уровня его фрагментации и даже от технологии хранения, которую вы используете для хранения файлов базы данных. .

Сервер MSSql выполняет запросы в следующем порядке (это должно дать вам представление о функциях предложений WHERE и JOIN)

Порядок обработки запросов Microsoft Sql Server

следующее взято из превосходной серии книг о Microsoft SQL Server, Внутри Microsoft SQL Server 2005: T-SQL Querying , которую можно найти здесь

(Шаг 8) SELECT (Шаг 9) DISTINCT (Шаг 11)
(Шаг 1) ОТ left_table
(Шаг 3) join_type JOIN right_table
(шаг 2) ON join_condition
(шаг 4) WHERE where_condition
(шаг 5) GROUP BY group_by_list
(шаг 6) С [CUBE | ROLLUP]
(шаг 7) with_clause
(Шаг 10) ЗАКАЗАТЬ ПО order_by_list

12 голосов
/ 15 июля 2009

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

Для MS-SQL оба запроса приводят к одним и тем же планам выполнения, но имейте в виду:

SELECT *
FROM Document, DocumentStats
WHERE DocumentStats.Id = Document.Id
  AND DocumentStats.NbViews > 500

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

4 голосов
/ 15 июля 2009

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

2 голосов
/ 16 июля 2009

Если вы говорите конкретно о SQL Server, то вам определенно следует использовать синтаксис INNER JOIN. Помимо того, что (оповещение о личном мнении!) Легче читать и лучше понимать, с SQL Server 2005 не существует эквивалентного синтаксиса для внешних объединений. Синтаксис * = и = * не поддерживается по умолчанию в 2005 году - для его поддержки необходимо включить режим совместимости. В конечном итоге он будет удален, возможно, как только выйдет следующий релиз (или, возможно, нет!)

Это означает:

  • Если вам нужно изменить запрос с внутреннего на внешнее соединение, вам нужно либо переписать его (argh), либо включить режим Compat (yuk)
  • Без режима Compat вы не можете быть последовательными с тем, как вы реализуете различные типы объединений (внутреннее по сравнению с внешним), что создает кошмар обслуживания (и, когда оба они объединены в одном запросе, некоторое поведение не интуитивное).

Заметьте также, что вопреки распространенному мнению, эти не эквивалентны. Некоторые вещи гораздо более неловкие, а некоторые просто невозможны. Inside SQL Server 2000 от Kalen Delaney содержит несколько примеров; не уверен, что более новые выпуски так делают, потому что этот синтаксис объединения в любом случае устарел.

2 голосов
/ 15 июля 2009

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

Если вам когда-либо понадобится использовать внешние объединения, вы должны знать, что синтаксис * = устарел в SQL Server и скоро будет удален. Кроме того, в настоящее время он не работает должным образом все время и может не дать правильных результатов и, следовательно, никогда не должен использоваться. Сочетание явных внешних объединений и того, где объединения выражений (неявные объединения) усложняют запрос для чтения и понимания сопровождающим.

2 голосов
/ 15 июля 2009

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

2 голосов
/ 15 июля 2009

Использование стандарта INNER JOIN является «стандартным», хотя практически эквивалентно. Основная причина, по которой его следует использовать, - для ясности и мобильности, поскольку он соответствует синтаксису OUTER JOIN.

1 голос
/ 15 июля 2009

Я думаю, что это тоже не имеет значения. Чтобы убедиться, что вы можете проверить, совпадает ли план объяснения этих двух запросов. Чтобы посмотреть план объяснения в MySQL, вы должны поставить ключевое слово «объяснение» перед оператором, например:

EXPLAIN
SELECT *
FROM Document, DocumentStats
WHERE DocumentStats.Id = Document.Id
  AND DocumentStats.NbViews > 500

Я уверен, что в MSSQL есть аналог.

Кстати: Похоже, что это отношение 1: 1, поэтому я бы просто включил атрибут nbviews непосредственно в таблицу документа, поэтому вы можете сохранить соединение.

1 голос
/ 15 июля 2009

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

...