SQL присоединяется к SQL-подзапросам (производительность)? - PullRequest
93 голосов
/ 04 октября 2010

Я хочу знать, есть ли у меня запрос join что-то вроде этого -

Select E.Id,E.Name from Employee E join Dept D on E.DeptId=D.Id

и подзапрос что-то вроде этого -

Select E.Id,E.Name from Employee Where DeptId in (Select Id from Dept)

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

Также есть время, когда я должен предпочесть один другому?

Извините, если это слишком тривиально и спрашивалось раньше, но я в замешательстве.Кроме того, было бы здорово, если бы вы, ребята, могли бы предложить мне tools , которые я должен использовать для измерения производительности двух запросов.Большое спасибо!

Ответы [ 8 ]

43 голосов
/ 04 октября 2010

Я бы ожидал, что первый запрос будет быстрее, в основном потому, что у вас есть эквивалентность и явное JOIN.По моему опыту IN является очень медленным оператором, поскольку SQL обычно оценивает его как серию WHERE предложений, разделенных «ИЛИ» (WHERE x=Y OR x=Z OR...).

Как и в случае с ВСЕМИ ВЕЩАМИ SQL, вашпробег может варьироваться.Скорость будет во многом зависеть от индексов (у вас есть индексы для обоих столбцов идентификаторов? Это очень поможет ...).

Единственный РЕАЛЬНЫЙ способ сказать со 100% уверенностью, что быстрееэто включить отслеживание производительности (особенно полезна статистика ввода-вывода) и запустить их оба.Обязательно очищайте кэш между запусками!

28 голосов
/ 05 июля 2013

Ну, я полагаю, что это "старый, но золотой" вопрос.Ответ: «Это зависит!».Спектакли - настолько деликатная тема, что было бы слишком глупо говорить: «Никогда не используйте подзапросы, всегда присоединяйтесь».В следующих ссылках вы найдете некоторые базовые рекомендации, которые я считаю очень полезными: Здесь 1 Здесь 2 Здесь 3

У меня есть таблица с 50000 элементами, в результате я искал 739 элементов.

Сначала мой запрос был таким:

SELECT  p.id,
    p.fixedId,
    p.azienda_id,
    p.categoria_id,
    p.linea,
    p.tipo,
    p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND p.anno = (
    SELECT MAX(p2.anno) 
    FROM prodotto p2 
    WHERE p2.fixedId = p.fixedId 
)

, и для его выполнения потребовалось 7,9 с.

Мой запрос наконец-то такой:

SELECT  p.id,
    p.fixedId,
    p.azienda_id,
    p.categoria_id,
    p.linea,
    p.tipo,
    p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND (p.fixedId, p.anno) IN
(
    SELECT p2.fixedId, MAX(p2.anno)
    FROM prodotto p2
    WHERE p.azienda_id = p2.azienda_id
    GROUP BY p2.fixedId
)

, и это заняло 0,0256 с

Хороший SQL, хороший.

10 голосов
/ 04 октября 2010

Начните смотреть на планы выполнения, чтобы увидеть различия в том, как SQl Server будет их интерпретировать.Вы также можете использовать Profiler для фактического выполнения запросов несколько раз и получения различий.

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

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

6 голосов
/ 29 июня 2012

Производительность основана на количестве данных, которые вы выполняете на ...

Если данных меньше около 20 КБ. JOIN работает лучше.

Если данные больше похожи на 100k +, то IN работает лучше.

Если вам не нужны данные из другой таблицы, IN - это хорошо, но лучше использовать EXISTS.

Все эти критерии, которые я проверял, и таблицы имеют правильные индексы.

4 голосов
/ 09 сентября 2011

Два запроса не могут быть семантически эквивалентными.Если сотрудник работает более чем в одном отделе (возможно, на предприятии, в котором я работаю; по общему признанию, это будет означать, что ваша таблица не полностью нормализована), то первый запрос будет возвращать дублирующиеся строки, тогда как второй запрос - нет.Чтобы сделать запросы эквивалентными в этом случае, к предложению SELECT необходимо добавить ключевое слово DISTINCT, что может повлиять на производительность.

Обратите внимание, что существует практическое правило, в котором говоритсятаблица должна моделировать сущность / класс или отношения между сущностями / классами, но не оба.Поэтому я предлагаю вам создать третью таблицу, скажем OrgChart, для моделирования отношений между сотрудниками и отделами.

3 голосов
/ 04 октября 2010

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

(отредактировано с учетом обновленного вопроса)

2 голосов
/ 15 августа 2018

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

Я также расскажу о следующих наблюдениях. У меня около 45 миллионов записей в моей таблице ([данные]) и около 300 записей в моей таблице [кошки]. У меня есть обширная индексация для всех запросов, о которых я собираюсь поговорить.

Рассмотрим пример 1:

UPDATE d set category = c.categoryname
FROM [data] d
JOIN [cats] c on c.id = d.catid

против примера 2:

UPDATE d set category = (SELECT TOP(1) c.categoryname FROM [cats] c where c.id = d.catid)
FROM [data] d

Пример 1 занял около 23 минут. Пример 2 занял около 5 минут.

Итак, я бы пришел к выводу, что подзапрос в этом случае намного быстрее. Конечно, имейте в виду, что я использую SSD-накопители M.2, способные работать со скоростью ввода / вывода @ 1 ГБ / с (то есть, байты, а не биты), поэтому мои индексы тоже очень быстрые. Так что это может повлиять и на скорость в ваших обстоятельствах

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

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

0 голосов
/ 04 октября 2010

Вы можете использовать План объяснения, чтобы получить объективный ответ.

Для вашей проблемы фильтр Exists , вероятно, будет работать быстрее всего.

...