0

У меня есть хранимая процедура, которая объединяет данные из нескольких таблиц через UNION ALL. Если параметры, переданные в хранимую процедуру, не применяются к конкретной таблице, я пытаюсь «закоротить» эту таблицу, используя «вспомогательные биты», например. @DataSomeTableExists и добавление соответствующего условия в предложение WHERE, например.Awkward JOIN вызывает низкую производительность

Стол для одного (psuedo) в хранимой процедуре немного неудобен и вызывает у меня некоторое горе.

DECLARE @DataSomeTableExists BIT = (SELECT CASE WHEN EXISTS(SELECT * FROM #T WHERE StorageTable = 'DATA_SomeTable') THEN 1 ELSE 0 END); 
... 

UNION ALL 

SELECT * 
FROM REF_MinuteDimension AS dim WITH (NOLOCK) 
CROSS JOIN (SELECT * FROM #T WHERE StorageTable = 'DATA_SomeTable') AS T  
CROSS APPLY dbo.fGetLastValueFromSomeTable(T.ParentId, dim.TimeStamp) dpp 
WHERE @DataSomeTableExists = 1 AND dim.TimeStamp >= @StartDateTime AND dim.TimeStamp <= @EndDateTime 

UNION ALL 

... 

Примечание: REF_MinuteDimension не более чем smalldatetimes с шагом в минуту.

(1) План выполнения (ниже) указывает на предупреждение оператора вложенных циклов, говорящего, что предиката соединения нет. Это, вероятно, не очень хорошо, но между таблицами действительно нет естественного соединения. Есть ли лучший способ написать такой запрос? Для каждого ParentId в T я хочу получить значение из UDF за каждую минуту между @StartDateTime и @EndDateTime.

(2) Даже когда @DataSomeTableExists = 0, в этом запросе есть активность ввода-вывода, как сообщается SET STATISTICS IO ON, и фактический план выполнения. В плане выполнения указано 14,2% стоимости, что слишком сильно, учитывая, что эти таблицы даже не применяются в этом случае.

SELECT * FROM #T WHERE StorageTable = 'DATA_SomeTable' возвращается пустым.

Это так, как мой запрос написан? Почему бы не вспомогательный бит или пустое Т короткое замыкание этого запроса?

enter image description here

+0

Вы должны изменить что 'DECLARE' вещь это:' объявить @DataSomeTableExists бит = 0 , если существует (SELECT * FROM #T WHERE StorageTable = 'DATA_SomeTable') начало \t комплект @DataSomeTableExists = 1 конец'. Трудно читать, так вот [pastebin] (http://pastebin.com/4y0VTJCD). И почему у вас нет вашего аргумента «короткое замыкание» 'WHERE' в запросе' CROSS JOIN'? Я должен упомянуть, у меня нет подсказки *, если это когда-либо будет работать, поскольку это нечетный способ написать sproc. –

ответ

0

Для 2) Я могу с уверенностью сказать, что линию

CROSS JOIN (SELECT * FROM #T WHERE StorageTable = 'DATA_SomeTable') AS T 

Ill силы #T проанализировать и ввести объединение. Вы можете создавать версии SP с этим соединением и без него и использовать этот флаг для выполнения того или другого, но я не могу сказать, что я плохо знаю время отклика || cpu clocks || I/O bandwith || memory.

Для 1) Я предлагаю удалить (nolock), если вы используете SQL Server 2005 или лучше, и внимательно следить за этим UDF. Не могу сказать больше без хорошей скрипты SQL.

0

Я должен упомянуть, у меня есть no clue, если это когда-нибудь будет работать, так как это нечетный способ написать sproc и табличные UDF, которые не понятны оптимизатору запросов. Возможно, вам придется построить свой набор результатов в табличной переменной или временной таблице условно, на основе операторов IF, а затем вернуть эти данные. Но я хотел бы попробовать это, во-первых:

--helper bit declared 
declare @DataSomeTableExists BIT = 0x0 
if exists (select 1 from #T where StorageTable = 'DATA_SomeTable') 
begin 
    set @DataSomeTableExists = 0x1 
end 

... 

UNION ALL 

SELECT * 
FROM REF_MinuteDimension AS dim WITH (NOLOCK) 
CROSS JOIN (SELECT * FROM #T WHERE StorageTable = 'DATA_SomeTable' and @DataSomeTableExists = 0x1) AS T 
CROSS APPLY dbo.fGetLastValueFromSomeTable(T.ParentId, dim.TimeStamp) dpp 
WHERE @DataSomeTableExists = 0x1 AND dim.TimeStamp >= @StartDateTime AND dim.TimeStamp <= @EndDateTime 

UNION ALL 

... 

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

+0

Спасибо за ответ. Кажется, это трюк. Любопытно, почему вы изменили объявление вспомогательного бита? Это просто для чтения? –

+0

Да. Вы объявляете переменную, устанавливая ее значение по умолчанию, а также запрашивая использование 'EXISTS' с подзапросом' SELECT'. Это много для следующего разработчика, чтобы сесть и прочитать, когда есть другие способы легко написать его. –

-1

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

Есть минусы динамического SQL, так read up

+0

Лучшей альтернативой, как предположил @jean, является создание одной хранимой процедуры каждый раз, когда данные нужно вытащить и когда данных нет. Затем, из мастера sproc, условно запускайте один sproc или другой. Затем вы используете * динамическую логику * (и сохраняете планы запросов), но не * динамический SQL * (который почти никогда не требуется, поэтому его следует избегать). –

Смежные вопросы