ПРИСОЕДИНЯЙТЕСЬ, СУЩЕСТВУЕТ ИЛИ IN, что лучше? Несколько вопросов по SQL
У меня мало вопросов по SQL.
-
Как анализировать производительность
запрос? Любое программное обеспечение, встроенное
функции сервера MSSQL 2005/2008?
-
Что следует использовать вместо in
в запросах, чтобы производительность была лучше?
Например:
SELECT *
FROM enquiry_courses
ГДЕ
enquiry_id IN
(SELECT enquiry_id ОТ запросов WHERE session_id = '4cd3420a16dbd61c6af58f6199ac00f1')
-
Что лучше: JOINS
, EXISTS
или in
с точки зрения производительности?
Комментарии/Помогите оценить...
Ответы
Ответ 1
-
Используйте SQL Server Management Studio и включите Actual Execution Plan
и SET STATISTICS TIME
и SET STATISTICS IO
.
-
Это соответствует a JOIN
, но переписывание, вероятно, не имеет значения. Догадка может заключаться в том, что для повышения производительности запросов вам нужны индексы enquiry_courses.enquiry_id
и enquiries.session_id
.
Ответ 2
В MSSQL обычно входит встроенный инструмент gui, называемый Query Analyzer, который описывает, как будет выполняться запрос.
Для 2) вы можете переписать как:
SELECT *
FROM enquiry_courses ec
WHERE EXISTS (select 1 FROM enquiries e
WHERE e.enquiry_id = ec.enquiry_id
and e.session_id ='4cd3420a16dbd61c6af58f6199ac00f1' )
но я не могу поверить, что это изменит производительность в современной СУБД.
Ответ 3
3: Я ожидал бы, что предложение IN или EXIST будет сплющено JOIN механизмом базы данных, поэтому не должно быть разницы в производительности. Я не знаю о SQL Server, но в Oracle вы можете проверить это, проверив план выполнения.
Ответ 4
Этот вопрос подсказывает, что EXISTS быстрее, чем я учил IN() vs EXISTS() в SqlServer 2005 (или вообще в любой СУБД)
Следует отметить, что EXISTS и IN должны использоваться вместо NOT EXISTS и NOT IN
Немного касательной от производительности, но это хорошая статья о тонких различиях между IN и EXISTS http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx
Ответ 5
-
Как говорили другие, проверьте "план выполнения". Студия SQL Server Management может показать вам два вида планов выполнения, оцененных и актуальных. Предполагается, что SQL Server догадается, что он выполнит запрос и будет возвращен без фактического выполнения запроса, и фактический план будет возвращен вместе с результирующим набором и покажет, что на самом деле было сделано.
-
Этот запрос выглядит хорошо, но вы должны убедиться, что у вас есть указатель на enquiry_courses.enquiry_id, и, вероятно, лучше всего, чтобы request.enquiry_id не мог быть нулевым.
-
Семантика IN и EXISTS несколько отличается (IN не будет возвращать строки, если в подзапросе есть один или несколько NULL). Если подзапрос гарантированно не равен null, это не имеет значения. Существует некоторая "истина в Интернете", в которой вы должны использовать EXISTS на SQL Server и IN на Oracle, но это могло бы быть правдой, когда динозавры правили планетой, но она больше не применяется. IN и EXISTS выполняют как полусоединение, так и оптимизатор более чем способен решить, как выполнить это соединение.
Ответ 6
Я предполагаю, что соединение дает больше возможностей движку для выбора лучшего плана запроса.
В вашем конкретном случае, возможно, все решения аналогичны.
SELECT enquiry_courses.*
FROM enquiry_courses
INNER JOIN enquiries ON enquiries.enquiry_id=enquiry_courses
AND session_id = '4cd3420a16dbd61c6af58f6199ac00f1'
Ответ 7
Они ведут себя по-другому: это не выбор производительности
Единственный правильный и надежный выбор - EXISTS или NOT EXISTS, который работает все время.
- JOIN может потребоваться DISTINCT
- WHERE/LEFT JOIN потребует правильного размещения фильтра
- NOT IN терпит неудачу в NULL
Пример:
DECLARE @Parent TABLE (foo int NULL)
INSERT @Parent (foo) VALUES (1)
INSERT @Parent (foo) VALUES (2)
INSERT @Parent (foo) VALUES (3)
INSERT @Parent (foo) VALUES (4)
DECLARE @Child TABLE (bar int NULL, foo int NULL)
INSERT @Child (bar, foo) VALUES (100, 1)
INSERT @Child (bar, foo) VALUES (200, 2)
INSERT @Child (bar, foo) VALUES (201, 2)
INSERT @Child (bar, foo) VALUES (300, NULL)
INSERT @Child (bar, foo) VALUES (301, NULL)
INSERT @Child (bar, foo) VALUES (400, 4)
INSERT @Child (bar, foo) VALUES (500, NULL)
--"positive" checks
SELECT -- multiple "2" = FAIL without DISTINCT
P.*
FROM
@Parent P JOIN @Child C ON P.foo = C.foo
SELECT -- correct
P.*
FROM
@Parent P
WHERE
P.foo IN (SELECT c.foo FROM @Child C)
SELECT -- correct
P.*
FROM
@Parent P
WHERE
EXISTS (SELECT * FROM @Child C WHERE P.foo = C.foo)
--"negative" checks
SELECT -- correct
P.*
FROM
@Parent P LEFT JOIN @Child C ON P.foo = C.foo
WHERE
C.foo IS NULL
SELECT -- no rows = FAIL
P.*
FROM
@Parent P
WHERE
P.foo NOT IN (SELECT c.foo FROM @Child C)
SELECT -- correct
P.*
FROM
@Parent P
WHERE
NOT EXISTS (SELECT * FROM @Child C WHERE P.foo = C.foo)
Примечание: с помощью EXISTS SELECT в подзапросе не имеет значения, как указано в стандарте ANSI 92...
NOT EXISTS (SELECT * FROM @Child C WHERE P.foo = C.foo)
NOT EXISTS (SELECT NULL FROM @Child C WHERE P.foo = C.foo)
NOT EXISTS (SELECT 1 FROM @Child C WHERE P.foo = C.foo)
NOT EXISTS (SELECT 1/0 FROM @Child C WHERE P.foo = C.foo)
Ответ 8
- проверьте План экстренной помощи
- Вы можете оптимизировать свой запрос:
- Сделайте "поиск аргументов", а не IN
- Поместить указатель на session_id
SELECT * FROM enquiry_courses as Courses, enquiries as Enquiries
WHERE Enquiries.session_id = '4cd3420a16dbd61c6af58f6199ac00f1'
AND Courses.enquiry_id = Enquiries.enquiry_id
3. Существует лучше для производительности.
EDIT: Exists и IN лучше, чем JOIN для проблем с производительностью.
EDIT: я переписал запрос так, чтобы он был быстрее (я ставлю наиболее ограничительное условие сначала в закрытии WHERE)