SQL объединяется с подзапросами SQL (производительность)?

110

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

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)

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

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

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

Vishal
источник
5
@Lucero, этот вопрос помечен как sql-server-2008, а сообщение, которое вы упомянули, помечено как MySql. Вы можете сделать вывод, что ответы будут такими же. Оптимизация производительности в двух СУБД выполняется по-разному.
Франсуа Бота,

Ответы:

48

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

Однако, как и в случае с ALL THINGS SQL, ваш опыт может отличаться. Скорость будет во многом зависеть от индексов (есть ли у вас индексы для обоих столбцов идентификатора? Это очень поможет ...), среди прочего.

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

JNK
источник
16
Я серьезно сомневаюсь в этом ответе, поскольку большинство СУБД, особенно SQL Server 2008 и более поздних версий, переводят подзапрос с одним идентификатором (не коррелированным, что означает отсутствие ссылки на несколько столбцов внешнего запроса) в относительно быстрое полусоединение. Кроме того, как ранее отмечалось в другом ответе, первое, реальное соединение будет возвращать строку для КАЖДОГО совпадения идентификатора в Dept - это не имеет значения для уникального идентификатора, но даст вам множество дубликатов в другом месте. Сортировка их с помощью DISTINCT или GROUP BY будет еще одной большой нагрузкой на производительность. Проверяйте планы выполнения в SQL Server Management Studio!
Эрик Харт
2
Предложение IN как эквивалент OR применяется к спискам параметров / значений, но не к подзапросам, которые в основном обрабатываются как объединения.
Эрик Харт
42

Что ж, я считаю, что это вопрос "старый, но золотой". Ответ: «Как много!». Спектакли - настолько деликатная тема, что было бы слишком глупо сказать: «Никогда не используйте подзапросы, всегда присоединяйтесь». По следующим ссылкам вы найдете некоторые основные передовые методы, которые, как я считаю, очень полезны:

У меня есть таблица с 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, хорошо.

linuxatico
источник
3
Интересно, не могли бы вы объяснить, как это исправило добавление GROUP BY?
cozos
6
Временная таблица, созданная подзапросом, была меньше. Таким образом, выполнение происходит быстрее, так как данных для проверки меньше.
Самсеба
2
Я думаю, что в первом запросе у вас есть общая переменная между внешним запросом и подзапросом, поэтому для каждой строки в основном запросе выполняется подзапрос, но во втором подзапрос выполняется только один раз, и таким образом производительность улучшается.
Али Фараджпур
1
Сервер Sql, MySql и ... Sql (за исключением NoSql) настолько похожи по инфраструктуре. У нас есть своего рода механизм оптимизации запросов, который преобразует предложения IN (...) для объединения (если это было возможно). Но когда у вас есть группа по хорошо проиндексированному столбцу (в зависимости от его мощности), это будет намного быстрее. Так что это действительно зависит от ситуации.
Аликс
10

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

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

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

HLGEM
источник
9

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

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

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

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

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

JP Emvia
источник
4

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

(Отредактировано, чтобы отразить обновленный вопрос)

Lucero
источник
4

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

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

один день, когда
источник
4

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

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

Рассмотрим пример 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 минут.

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

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

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

Арвин Амир
источник
0

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

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

Снексе
источник
2
«Фильтр Exists, вероятно, будет работать быстрее всех» - я думаю, вероятно, нет, хотя для окончательного ответа потребуется проверка фактических данных. Существующие фильтры, вероятно, будут работать быстрее, если есть несколько строк с одинаковыми значениями поиска - поэтому существующий фильтр может работать быстрее, если запрос проверяет, были ли другие сотрудники записаны из того же отдела, но, вероятно, не при поиске по отделу стол.
Будет ли он работать медленнее в последнем сценарии?
Snekse
Это будет зависеть от оптимизатора - при определенных обстоятельствах может, но обычно я ожидал очень похожей производительности.