ПРИСОЕДИНЯЙТЕСЬ, СУЩЕСТВУЕТ ИЛИ 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)