2013-07-19 2 views
2

интересуется этим поведением с SQL Server.SELECT в подзапросе внутри оператора IN, зависающего SQL Server

Этот запрос дает результаты очень быстро, так же, как я бы ожидать:

SELECT * 
FROM dbo.v_View1 View1 FULL OUTER JOIN 
    dbo.v_View2 View2 ON View1.Portfolio = View2.Portfolio AND 
    View1.AsOfDate = View2.AsOfDate 
where (View1.AsOfDate IN (NULL, '20130717')) 

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

SELECT * 
FROM dbo.v_View1 View1 FULL OUTER JOIN 
    dbo.v_View2 View2 ON View1.Portfolio = View2.Portfolio AND 
    View1.AsOfDate = View2.AsOfDate 
where (View1.AsOfDate IN (NULL, (SELECT MAX(AsOfDate) FROM dbo.v_View1))) 

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

Я знаю, что я делаю что-то неправильно или что-то не хватает (возможно, оба) - что это? Я хотел бы иметь подзапрос в инструкции IN или, по крайней мере, иметь возможность запускать это как представление без переменных. Благодаря!

+2

Посмотрите план выполнения. –

ответ

4

Я подозреваю, что оптимизатор запросов делает что-то очень странное, потому что наивная реализация включает в себя два сканирования на v_View1, возможно, оптимизатор не понимает, что подзапрос SELECT MAX(AsOfDate) ... будет одинаковым для каждой строки. Я подозреваю, что это может не понять, что подзапрос не коррелирован с каждой строкой и, таким образом, запускает его для каждой строки вашего результирующего набора. Учитывая полное внешнее соединение, с большим количеством данных, что означает много ненужного сканирования таблиц.

Самое простое решение:

DECLARE @MaxAsOfDate datetime; 
SET @MaxAsOfDate = (SELECT MAX(AsOfDate) FROM dbo.v_View1) 

SELECT * 
FROM dbo.v_View1 View1 FULL OUTER JOIN 
    dbo.v_View2 View2 ON View1.Portfolio = View2.Portfolio AND 
    View1.AsOfDate = View2.AsOfDate 
where (View1.AsOfDate IN (NULL, @MaxAsOfDate)) 

И что заставит подзапрос один раз запустить, сохранить результат в переменной, а затем использовать его для следующего запроса.

+0

Да, я делал это в хранимой процедуре, а не в представлении, которое должно было быть (это выглядело более «правильным», поскольку дизайнер View не имеет визуальной поддержки переменных), но надеялся, что я просто отсутствует что-то. Ну ладно - спасибо! –

2

Я считаю, что он пересчитывает MAX (AsOfDate) для каждой записи, с которой он компарится. Простым решением было бы использовать предложение WITH (также известное как общее табличное выражение), которое будет вычисляться только в начале.

0

Простой способ переписать, чтобы избежать этой проблемы, является:

where View1.AsOfDate is null or View1.AsOfDate = (SELECT MAX(AsOfDate) FROM dbo.v_View1) 

EDIT:

Ваша проблема не, что запрос выполняется несколько раз. Ваша проблема в том, что представление сильно неоптимизировано. Вероятно, вы можете исправить это, просто перекомпилировав представление. Запишите его как оператор ALTER в SSMS и выполните его. С тех пор, как было создано представление, таблицы, вероятно, изменились.

Я думаю, вы также можете исправить это, указав SQL Server не использовать вложенные объединения циклов (это является причиной вашей проблемы с производительностью). Вы можете сделать это, добавив option (hash join, merge join) в конец инструкции SQL.

+0

Спасибо, но это создает для меня ту же проблему - в настоящее время она работает в течение 5 минут. –

1

я бы предложил использовать верхний один и изменить его так, чтобы не имею NULL в операторе IN так писать, как этот

SELECT * 
FROM dbo.v_View1 View1 FULL OUTER JOIN 
    dbo.v_View2 View2 ON View1.Portfolio = View2.Portfolio AND 
    View1.AsOfDate = View2.AsOfDate 
where View1.AsOfDate IN ('20130717') AND View1.AsOfDate IS NULL 

также является FULL OUTER JOIN нужен? или может использоваться INNER JOIN?

также, если вы посмотрите на план выполнения и пост, что я буду иметь возможность размещать больше информации о том, как наилучшим образом оптимизировать этот запрос, который вы также увидите на каком этапе запроса принимает самый длинный

Picture of execution plan and how to show it

+0

Спасибо - это не устраняет проблему, когда я пытаюсь создать динамический AsOfDate в инструкции 'WHERE'. Я посмотрю план выполнения и посмотрю, есть ли там что-то подозрительное, спасибо за подсказку. –