Могу ли я получить более высокую производительность, используя JOIN или EXISTS? - PullRequest
26 голосов
/ 22 октября 2008

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

Могу ли я получить более высокую производительность, используя JOIN или EXISTS?

Спасибо,
-Nimesh

Ответы [ 12 ]

18 голосов
/ 22 октября 2008

В зависимости от оператора, статистики и сервера БД это может не иметь значения - может быть создан тот же оптимизированный план запроса.

Существует три основных способа присоединения БД к таблицам:

  • Вложенный цикл - для одного стола намного больше второго. Каждая строка в меньшей таблице проверяется для каждой строки в большей.

  • Слияние - для двух таблиц в одном порядке сортировки. Оба проходят по порядку и сопоставляются там, где они соответствуют.

  • Хеш - все остальное. Временные таблицы используются для построения матчей.

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

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

Например, если [Institutions] и [Results] имеют одинаковые размеры и оба кластеризованы на InstitutionID, соединение слиянием будет самым быстрым Если [Results] намного больше, чем [Institutions], вложенный цикл может быть быстрее.

14 голосов
/ 22 октября 2008

Это зависит.

В конечном счете, 2 служат совершенно другим целям.

Вы присоединяетесь к 2 таблицам для доступа к связанным записям. Если вам не нужен доступ к данным в связанных записях, вам не нужно присоединяться к ним.

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

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


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

select Institutions.institution_name 
from Institutions
inner join Results on (Institutions.institution_id = Results.institution_id)

Если у вас имеется идентификатор института и вы просто хотите узнать, есть ли у него результаты, использование EXISTS может быть быстрее:

if exists(select 1 from Results where institution_id = 2)
  print "institution_id 2 has results"
else
  print "institution_id 2 does not have results"
5 голосов
/ 22 октября 2008

Это зависит от вашего оптимизатора. Я попробовал следующие два в Oracle 10g и 11g. В 10g второй был чуть быстрее. В 11г они были идентичны.

Однако # 1 на самом деле является неправильным использованием предложения EXISTS. Используйте соединения, чтобы найти совпадения.

select *
from
  table_one t1
where exists (
             select *
             from table_two t2
             where t2.id_field = t1.id_field
             )
order by t1.id_field desc


select t1.*
from 
  table_one t1
 ,table_two t2
where t1.id_field = t2.id_field
order by t1.id_field desc 
4 голосов
/ 22 октября 2008

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

3 голосов
/ 22 октября 2008

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

РЕДАКТИРОВАТЬ: Но это зависит от запроса. Об этом следует судить в каждом конкретном случае.

1 голос
/ 03 апреля 2012

В подобных случаях оператор Exists работает быстрее, чем оператор Joins. Exists даст вам одну запись и сэкономит время. В случае объединений количество записей будет больше, и должны использоваться все записи.

1 голос
/ 23 октября 2008

Если таблица RESULTS имеет более одной строки на INSTITUTION, EXISTS() имеет дополнительное преимущество, заключающееся в том, что вам не требуется выбирать отдельные учреждения.

Что касается производительности, я видел joins, IN(), and EXISTS(), каждый из которых был самым быстрым в различных областях применения. Чтобы найти лучший метод для ваших целей, вы должны проверить.

1 голос
/ 23 октября 2008

LEFT OUTER JOIN будет иметь тенденцию работать лучше, чем NOT EXISTS **, но в вашем случае вы хотите выполнить EXISTS, и использование простого INNER JOIN точно не повторяет поведение EXISTS. Если у вас есть несколько результатов для учреждения, выполнение INNER JOIN вернет несколько строк для этого учреждения. Вы можете обойти это, используя DISTINCT, но тогда EXISTS, вероятно, будет лучше для производительности в любом случае.

** Для тех, кто не знаком с этим методом:

SELECT
     MyTable.MyTableID
FROM
     dbo.MyTable T1
LEFT OUTER JOIN dbo.MyOtherTable T2 ON
     T2.MyTableID = T1.MyTableID
WHERE
     T2.MyOtherTableID IS NULL

эквивалентно

SELECT
     MyTable.MyTableID
FROM
     dbo.MyTable T1
WHERE NOT EXISTS (SELECT * FROM MyOtherTable T2 WHERE T2.MyTableID = T1.MyTableID)

при условии, что MyOtherTableID является столбцом NOT NULL. Первый метод обычно работает быстрее, чем метод NOT EXISTS.

1 голос
/ 23 октября 2008

На самом деле, из вашего расплывчатого описания проблемы мне кажется, что запрос NOT IN - самый очевидный способ его кодирования:

SELECT *
  FROM Institutions
  WHERE InstitutionID NOT IN (
     SELECT DISTINCT InstitutionID
       FROM Results
     )
1 голос
/ 22 октября 2008

Используете ли вы EXISTS как часть коррелированного подзапроса? Если это так, объединение будет почти всегда быстрее.

В вашей базе данных должны быть способы сравнения запросов. Используйте их, чтобы увидеть, какой запрос выполняется быстрее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...