Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Проблемы с производительностью SQL Server при использовании EXCEPT в запросе

Автор вопроса: user11034064Ответов: 4

В общем, у меня есть запрос SELECT в сочетании с тремя независимыми запросами SELECT. Я использую операторы EXCEPT и UNION в запросе. При самостоятельном выполнении запросов я получу результаты за 1-2 секунды, но при наличии оператора EXCEPT запрос займет часы.

Структура запроса (в упрощенном виде) выглядит следующим образом:

SELECT DISTINCT FIELD_1, FIELD_2, FIELD_3 FROM MYTABLE

EXCEPT

(
SELECT DISTINCT FIELD_1, FIELD_2, FIELD_3 FROM MYTABLE WHERE XXX

UNION

SELECT DISTINCT FIELD_1, FIELD_2, FIELD_3 FROM MYTABLE WHERE YYY
)

Есть ли способы ускорить весь запрос или оператор EXCEPT в целом настолько медленный, что его следует избегать?

  • В таблицах есть столбцы, а не поля. jarlh 08.02.2019
  • Я бы начал здесь и здесь и здесь. Вы не показали план выполнения, а это необходимо... но поскольку вы используете одну и ту же таблицу во всех трех запросах, я уверен, что есть гораздо более элегантное решение, например NOT EXISTS as @jarlh предложил. Я не понимаю, зачем вам здесь нужны UNION и EXCEPT. Кроме того, DISTINCT не нужен scsimon 08.02.2019
  • Как насчет SELECT DISTINCT FIELD_1, FIELD_2, FIELD_3 FROM MYTABLE WHERE NOT XXX AND NOT YYY? Peter B 08.02.2019
  • Действительно ли все эти три запроса относятся к одной и той же таблице или это просто ваше запутывание? Tab Alleman 08.02.2019
  • В последней статье вы увидите вывод Аарона о том, что это был просто очень многословный способ сообщить вам, что для шаблона поиска всех строк в таблице A, где какое-то условие не существует в таблице B, НЕ СУЩЕСТВУЕТ, как правило, будет вашим лучшим выбором scsimon 08.02.2019
  • Tab: это та же таблица. Первый запрос в основном дает почти всю таблицу, а второй + третий запросы - это подмножества, которые мне нужно убрать из результатов первого запроса. user11034064 08.02.2019

sqlsql-serverunionexcept

Ответы

Ответ 1 · рейтинг 3 · Martin Smith

Вы можете сделать это с помощью GROUP BY

SELECT FIELD_1, FIELD_2, FIELD_3
FROM MYTABLE
GROUP BY FIELD_1, FIELD_2, FIELD_3
HAVING MAX(CASE WHEN (XXX) OR (YYY) THEN 1 ELSE 0 END) = 0

Ответ 2 · Yogesh Sharma

Я бы использовал NOT EXISTS вместо CTE :

WITH CTE AS (
     <your union query>
)
SELECT mt.*
FROM MYTABLE mt
WHERE NOT EXISTS (SELECT 1 FROM CTE c WHERE c.FIELD_1 = mt.FIELD_1 AND . . . );

Ответ 3 · Alen.Toma

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

Карьер ниже будет иметь гораздо более высокую производительность.

Вот как бы я это сделал.

SELECT DISTINCT FIELD_1, FIELD_2, FIELD_3 FROM MYTABLE
where Id not in (
SELECT Id FROM MYTABLE WHERE XXX and YYY
)

Ответ 4 · Alexander Volok

Иногда полезно упростить задачу оптимизатора запросов, разделив рабочую нагрузку на несколько этапов. Особенно, если выполнение может занять несколько часов:

-- Step 1
SELECT FIELD_1, FIELD_2, FIELD_3 INTO #Step1 FROM
(
SELECT FIELD_1, FIELD_2, FIELD_3 FROM MYTABLE WHERE XXX
UNION
SELECT FIELD_1, FIELD_2, FIELD_3 FROM MYTABLE WHERE YYY
) d

-- Step 2:
SELECT DISTINCT FIELD_1, FIELD_2, FIELD_3 FROM MYTABLE
EXCEPT
SELECT FIELD_1, FIELD_2, FIELD_3  FROM #Step1

Обратите внимание, что некоторые предложения DISTINCT удалены.


Обновление, версия 3. На основе последнего обновления OP:

Tab: это та же таблица. Первый запрос в основном дает почти всю таблицу, а второй + третий запрос - это подмножества, которые мне нужно убрать из результатов первого запроса.

Я считаю, что весь запрос можно переписать так:

SELECT DISTINCT FIELD_1, FIELD_2, FIELD_3 FROM MYTABLE ext
WHERE NOT EXISTS (

SELECT * FROM (
    SELECT FIELD_1, FIELD_2, FIELD_3 FROM MYTABLE
    WHERE  ( (XXX) OR (YYY))  -- original filter
)   list
WHERE
    list.FIELD_1 = ext.FIELD_1
AND list.FIELD_2 = ext.FIELD_2
AND list.FIELD_3 = ext.FIELD_3
)

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы