2010-10-04 2 views
72

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

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) 

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

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

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

+3

См. Также http://stackoverflow.com/questions/2577174/sql-join-vs-subquery – Lucero

+3

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

ответ

36

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

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

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

+9

У меня есть серьезные сомнения в этом ответе, так как большинство СУБД, определенно SQL Server 2008 и более поздних версий, переводят один подзапрос ID (не коррелированный, то есть: не ссылаясь на несколько внешних столбцов запроса) в относительно быстрое полусоединение.Кроме того, как ранее отмечалось в другом ответе, первое, реальное соединение вернет строку для КАЖДОГО появления идентификатора соответствия в Dept - это не имеет никакого значения для уникального идентификатора, но даст вам тонны дубликатов в другом месте. Сортировка их с помощью DISTINCT или GROUP BY будет другой, большой нагрузкой. Проверьте планы выполнения в SQL Server Management Studio! –

+1

Предложение IN как эквивалент OR применяется к спискам параметров/значений, но не к подзапросам, которые в основном обрабатываются как объединения. –

2

Исполнение должно быть одинаковым; гораздо важнее иметь правильные индексы и кластеризацию, применяемые к вашим таблицам (на эту тему существует some good resources).

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

+0

Я обновил свой вопрос, чтобы немного изменить запросы ... спасибо за ваш ответ. – Vishal

0

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

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

+2

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

+0

Будет ли он работать медленнее в этом последнем сценарии? – Snekse

+0

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

9

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

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

EXISTS часто лучше, чем любой из этих двух, и когда вы говорите о левом соединении, где вы хотите, чтобы все записи не были в левой таблице соединений, то НЕ СУЩЕСТВУЕТ, часто намного лучший выбор.

3

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

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

4

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

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

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

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

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

22

Ну, я считаю, что это вопрос «Старый, но Золотой». Ответ: «Это зависит!». Спектакли - такая деликатная тема, что было бы слишком глупо говорить: «Никогда не используйте подзапросы, всегда присоединяйтесь». В следующих ссылках вы найдете некоторые основные рекомендации, которые я нашел, чтобы быть очень полезными: Here 1 Here 2 Here 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.9s выполнить.

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

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.0256s

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

+0

Интересно, не могли бы вы объяснить, как было добавлено GROUP BY? – cozos

+0

Временная таблица, созданная подзапросом, была меньше. Поэтому выполнение выполняется быстрее, поскольку для регистрации требуется меньше данных. – Sirmyself

-1

Окончательный запрос включал azienda_id в посылковом подзапросе, но ваш первоначальный запрос не включал azienda_id в завершенный подзапрос. Таким образом, сравнение не является таким же.

+0

Это должен быть комментарий к запросу linuxatico. – jojonas

-1

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

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

Смежные вопросы