Почему несколько EXISTS нарушают запрос - PullRequest
0 голосов
/ 04 декабря 2018

Я пытаюсь включить новую таблицу со значениями, которые необходимо проверить и включить в хранимую процедуру.Оператор 1 - это существующая таблица, с которой необходимо проверить, а оператор 2 - это новая таблица, с которой нужно проверить.

В настоящее время у меня есть 2 EXISTS условия, которые работают независимо и дают ожидаемые результаты.Под этим я подразумеваю, если я закомментирую Утверждение 1, утверждение 2 работает и наоборот.Когда я собираю их вместе, запрос не завершается, ошибки нет, но время ожидания неожиданно, потому что каждое утверждение занимает всего несколько секунд.

Я понимаю, что, вероятно, есть лучший способ сделать это, нопрежде чем я сделаю это, я хотел бы знать, почему я не могу сделать несколько заявлений о существовании, как это?Разве в предложении WHERE не должно быть несколько EXISTS условий?

SELECT *
FROM table1 S    
WHERE
--Statement 1
EXISTS 
(
   SELECT 1
   FROM table2 P WITH (NOLOCK)
      INNER JOIN table3 SA ON SA.ID = P.ID
   WHERE P.DATE = @Date AND P.OTHER_ID = S.ID
   AND 
   (
      SA.FILTER = ''
      OR 
      (
          SA.FILTER = 'bar'
          AND 
          LOWER(S.OTHER) = 'foo'
       )
    )
)
OR 
(
   --Statement 2
   EXISTS 
   (
      SELECT 1
      FROM table4 P WITH (NOLOCK)
         INNER JOIN table5 SA ON SA.ID = P.ID
      WHERE P.DATE = @Date 
            AND P.OTHER_ID = S.ID 
            AND LOWER(S.OTHER) = 'foo'
    )
)

РЕДАКТИРОВАТЬ: Я включил детали запроса.В таблице 1-5 представлены разные таблицы, повторных таблиц нет.

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

Я обнаружил, что установка 2 EXISTS в состояние WHERE значительно ускорила весь процесс.То, что я нашел исправлено, это использование UNION и сохранение EXISTS в отдельных запросах.Конечный результат выглядел следующим образом:

SELECT *
FROM table1 S    
WHERE
--Statement 1
   EXISTS 
   (
      SELECT 1
      FROM table2 P WITH (NOLOCK)
         INNER JOIN table3 SA ON SA.ID = P.ID
      WHERE P.DATE = @Date AND P.OTHER_ID = S.ID
      AND 
      (
         SA.FILTER = ''
         OR 
         (
             SA.FILTER = 'bar'
             AND 
             LOWER(S.OTHER) = 'foo'
          )
       )
   )

UNION

--Statement 2 
SELECT *
FROM table1 S    
WHERE
   EXISTS 
   (
      SELECT 1
      FROM table4 P WITH (NOLOCK)
         INNER JOIN table5 SA ON SA.ID = P.ID
      WHERE P.DATE = @Date 
            AND P.OTHER_ID = S.ID 
            AND LOWER(S.OTHER) = 'foo'
    )
0 голосов
/ 04 декабря 2018

Слишком долго комментировать.

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

  • Перехват параметров на @Date.Попробуйте жестко запрограммировать это значение и посмотрите, получите ли вы такую ​​же медлительность
  • Нет индекса покрытия для P.OTHER_ID или P.DATE, или P.ID, или SA.ID, что может привести к сканированию таблицы для этих предикатов
  • Индексы для вышеперечисленных столбцов, которые не являются оптимальными (включая слишком много столбцов и т. Д.)
  • Ваш запрос является последовательным, когда он может выиграть от параллелизма.
  • Использование функции LOWER в базе данных, в которой нет сортировки с учетом регистра (в большинстве случаев нет, хотя эта функция не сильно замедляет работу)
  • У вас естьплохой план запроса в кеше.Попробуйте добавить OPTION (RECOMPILE) внизу, чтобы вы получили новый план запроса .Это также делается при сравнении скорости двух запросов, чтобы убедиться, что они не используют кэшированные планы, или один не, когда другой запрос искажает результаты.

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

...