ПРИСОЕДИНЯЕТСЯ, СУЩЕСТВУЕТ или IN, что лучше? Несколько вопросов по SQL - PullRequest
3 голосов
/ 07 января 2010

У меня есть несколько вопросов по SQL ..

  1. Как проанализировать производительность запрос? Любое программное обеспечение, встроенное особенности сервера MSSQL 2005/2008?

  2. Что следует использовать вместо in в запросах, чтобы производительность была лучше? Например:

    ВЫБРАТЬ * FROM enquiry_courses ГДЕ enquiry_id IN (ВЫБЕРИТЕ enquiry_id ОТ запросов WHERE session_id = '4cd3420a16dbd61c6af58f6199ac00f1')

  3. Что лучше: JOINS, EXISTS или IN с точки зрения производительности?

Комментарии / Помощь приветствуется ...

Ответы [ 8 ]

2 голосов
/ 07 января 2010
  1. Используйте SQL Server Management Studio и включайте Actual Execution Plan и SET STATISTICS TIME и SET STATISTICS IO.

  2. Это соответствует JOIN, но переписывание, вероятно, не будет иметь значения. Можно предположить, что вам нужны индексы для enquiry_courses.enquiry_id и enquiries.session_id для повышения производительности запросов.

0 голосов
/ 17 января 2010

Они ведут себя по-разному: это не выбор производительности

Единственный правильный и надежный выбор - это СУЩЕСТВУЕТ или НЕ СУЩЕСТВУЕТ, который работает постоянно.

  • JOIN может нуждаться в ОТЛИЧИИ
  • 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)
0 голосов
/ 07 января 2010

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

SELECT enquiry_courses.* 
FROM enquiry_courses 
INNER JOIN enquiries ON enquiries.enquiry_id=enquiry_courses 
                        AND session_id = '4cd3420a16dbd61c6af58f6199ac00f1' 
0 голосов
/ 07 января 2010
  1. Как уже говорили другие, проверьте «план выполнения». Студия управления SQL Server может показать вам два вида планов выполнения, оценочные и фактические. По оценкам, SQL Server предполагает, что он выполнит запрос и будет возвращен без фактического выполнения запроса, а фактический план возвращается вместе с набором результатов и показывает, что на самом деле было сделано.

  2. Этот запрос выглядит хорошо, но вы должны убедиться, что у вас есть индекс на enquiry_courses.enquiry_id, и, вероятно, лучше всего, чтобы enquiries.enquiry_id не обнулялся.

  3. Семантика IN и EXISTS немного отличается (IN не будет возвращать строк, если в подзапросе есть один или несколько NULL). Если подзапрос гарантированно не равен нулю, это не имеет значения . Существует некоторая «интернет-истина», что вы должны использовать EXISTS на SQL Server и IN на Oracle, но это могло бы быть правдой, когда динозавры правили планетой, но это больше не применяется. IN и EXISTS оба выполняют полусоединение, и оптимизатор более чем способен решить, как выполнить это объединение.

0 голосов
/ 07 января 2010

Этот вопрос говорит о том, что EXISTS быстрее, чему меня учили IN () против EXISTS () в SqlServer 2005 (или вообще в любой RDBMS)

Следует отметить, что EXISTS и IN следует использовать вместо NOT EXISTS и NOT IN

Немного касательно производительности, но это хорошая статья о тонких различиях между IN и EXISTS http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx

0 голосов
/ 07 января 2010

3: Я ожидаю, что предложение IN или EXIST будет сведено к JOIN механизмом базы данных, поэтому не должно быть различий в производительности. Я не знаю, что такое SQL Server, но в Oracle вы можете проверить это, проверив план выполнения.

0 голосов
/ 07 января 2010
  1. проверьте план
  2. Вы можете оптимизировать свой запрос:
    • Выполните «поиск аргументов», а не IN
    • Поместить индекс на идентификатор_сессии
    SELECT * FROM enquiry_courses as Courses, enquiries as Enquiries
    WHERE Enquiries.session_id = '4cd3420a16dbd61c6af58f6199ac00f1'   
    AND Courses.enquiry_id = Enquiries.enquiry_id

3. Существует лучше для производительности.

РЕДАКТИРОВАТЬ: Существует & IN лучше, чем JOIN для проблем с производительностью.

РЕДАКТИРОВАТЬ: я переписал запрос так, чтобы он был быстрее (я ставлю наиболее ограничивающее условие первым в WHERE закрытии)

0 голосов
/ 07 января 2010

MSSQL обычно поставляется со встроенным графическим инструментом 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' )

но я не могу поверить, что это повлияло бы на производительность в современной СУБД.

...