2017-02-14 5 views
3

Я пытаюсь ускорить мой запрос. Мне нужно запустить 2 скалярнозначных функции для каждой строки с несколькими столбцами в качестве параметров.Самый эффективный способ выполнения нескольких скалярных функций в строке

функция делает расчет на основе текущих итогов, и нет простого способа (что я знаю), чтобы сделать это в сервере SQL 2008.

Часть КТР моего запрос получает все строки Мне нужны расчеты, и его нужно запускать индивидуально для каждого уровня. Связь для клиентов в магазинах - «один ко многим», но вы не можете получить расчет на уровне клиента (Store = «All») на основе каждого из своих расчетов магазинов.

Моя первая попытка состояла в том, чтобы вызовы функций выполнялись в инструкции SELECT, но я читал, что они будут работать синхронно, что не обязательно. Попытка, приведенная ниже, пыталась превратить вычисление в значение таблицы в попытке запустить их асинхронно.

Мне было интересно, если OUTER APPLY - это путь, или если бы был более эффективный способ сделать это.

Дайте мне знать, если вам нужна дополнительная информация!

DECLARE @StartTime INT 
SET @StartTime=20170101 

DECLARE @EndTime INT 
SET @EndTime=20170131 


;WITH IsAvgStores AS (
    SELECT 
     COALESCE(ParentClient,'All') AS ParentClient, 
     COALESCE(Client,'All') AS Client, 
     COALESCE(Store,'All') AS Store, 
     MAX(Answer_Threshold), 
     MAX(SL_Threshold) 
    FROM 
     client_hierarchy 
    WHERE 
     GETDATE() BETWEEN EFF_BEGIN_DATE AND EFF_END_DATE 
    GROUP BY ROLLUP(ParentClient,Client,Store) 
) 
SELECT I.ParentClient,I.Client,I.Store 
    ,SL.isAvg_SL_String 
    ,A.isAvg_ASA_String 
INTO #isAvgTemp 
FROM IsAvgStores I 
    OUTER APPLY (SELECT dbo.isAvg_S_B(ParentClient,Client,Store,Answer_Threshold,@StartTime,@EndTime) AS isAvg_SL_String 
       ) SL 
    OUTER APPLY (SELECT dbo.isAvg_A_B(ParentClient,Client,Store,SL_Threshold,@StartTime,@EndTime)  AS isAvg_ASA_String 
       ) A 
WHERE ParentClient<>'All' 

SELECT * 
FROM #isAvgTemp 
+0

Я не вижу, как работает rollup – Paparazzi

+0

@Paparazzi, вы правы, я забыл добавить MAX() на порогах. – reidodorito

ответ

5

Это слишком долго для комментария.

outer apply является избыточным для скалярной функции. Вы можете просто:

SELECT I.ParentClient, I.Client, I.Store, 
     dbo.isAvg_S_B(ParentClient, Client, Store,A nswer_Threshold, @StartTime, @EndTime) AS isAvg_SL_String, 
     dbo.isAvg_A_B(ParentClient, Client, Store, SL_Threshold, @StartTime, @EndTime) as isAvg_ASA_String 
INTO #isAvgTemp 
FROM IsAvgStores I 
WHERE ParentClient <> 'All'; 

Это не будет иметь абсолютно никакого влияния на производительность; он просто упрощает запрос.

Для выполнения, у вас есть три варианта:

  • переписать код, чтобы удалить функции; используйте outer apply для текущих сумм.
  • Перепишите код для удаления функций; используйте рекурсивные CTE для текущих сумм.
  • Перепишите код для удаления функций; используйте курсоры для текущих сумм.

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

Или, что лучше всего: переход на более позднюю версию SQL Server и использование функции суммирования суммы, предоставленной в SQL Server 2012+.

0

Другой вариант - попытаться преобразовать скалярные функции в inline table-valued functions (ITVF), которые возвращают скалярное значение. Это может работать или не работать в вашем сценарии. По моему опыту, complex scalar functions generally perform poorly in SQL Server on larger result sets, потому что они запускаются RBAR. С помощью ITVF SQL Server может встроить запрос для оптимизации плана запросов.

Ваш запрос будет выглядеть так, что вы пытаетесь достичь с OUTER APPLY:

SELECT I.ParentClient, I.Client, I.Store, SL.isAvg_SL_String A.isAvg_ASA_String 
INTO #isAvgTemp 
FROM IsAvgStores I 
OUTER APPLY dbo.isAvg_S_B(ParentClient,Client,Store,Answer_Threshold,@StartTime,@EndTime)SL 
OUTER APPLY dbo.isAvg_A_B(ParentClient,Client,Store,SL_Threshold,@StartTime,@EndTime) A 
WHERE ParentClient <> 'All'; 

Разница в том, что ваши функции будут возвращать таблицу с одного результата вместо:

CREATE FUNCTION dbo.isAvg_S_B (...) 
RETURNS TABLE 
AS 
(
    SELECT ... AS 'isAvg_SL_String' 
    FROM ... 
); 

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

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