Лучший способ использовать Scalar UDF, который должен появляться в предложениях Select и Where - PullRequest
1 голос
/ 11 августа 2009

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

Запуск UDF дважды на строку выглядит просто неправильно:

Select someField, 
       someOtherField, 
       dbo.MyExpensiveScalarUDF(someField, someOtherField)
from someTable
where dbo.MyExpensiveScalarUDF(someField, someOtherField) in (aHandfulOfValues)

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

Ответы [ 3 ]

4 голосов
/ 11 августа 2009

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

Взгляните на примерный план выполнения. Может быть, вы обнаружите, что вы ни о чем не беспокоитесь.

Если он рассчитан дважды, вы можете попробовать это и посмотреть, изменит ли он план, но это все еще не гарантирует:

WITH T(someField,someOtherField,expensiveResult) as (
  select someField, someOtherField, dbo.MyExpensiveScalarUDF(someField, someOtherField)
  from someTable
)
  select * from T
  where expensiveResult in (thisVal,thatVal,theotherVal);
4 голосов
/ 11 августа 2009

Стив прав: план запроса, вероятно, не будет переоценивать идентичные выражения, если UDF является детерминированным.

Однако повторение - это потенциальная проблема обслуживания:

WITH temp AS (
Select someField, 
       someOtherField, 
       dbo.MyExpensiveScalarUDF(someField, someOtherField) AS scalar
from someTable
)
SELECT *
FROM temp
where scalar in (aHandfulOfValues)

Вы можете избежать этого с помощью CTE или вложенного запроса.

Лучше всего избегать скалярных UDF, если это вообще возможно для наборов строк любого значительного размера (скажем, полмиллиона оценок). Если вы развернете его встроенным образом (а с CTE вам не придется повторяться), вы, вероятно, найдете огромный прирост производительности. Скалярные UDF должны быть последним средством. По моему опыту, гораздо лучше использовать постоянный вычисляемый столбец, либо встроенный, либо почти любой другой метод, прежде чем полагаться на скалярный UDF.

3 голосов
/ 11 августа 2009

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

(1) Можете ли вы сделать ее табличной функцией, присоединить ее к предложению FROM и работать оттуда?

(2) Просмотрите предложения OUTER APPLY и CROSS APPLY. По сути, они допускают объединения в табличных функциях, где параметры, передаваемые в функцию, основаны на соединяемой строке (в отличие от одного вызова). Хорошие примеры этого в BOL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...