sp_executesql против определяемой пользователем скалярной функции

В таблице ниже я сохраняю некоторые условия, подобные этому:

введите здесь описание изображения

Затем, как правило, во второй таблице у меня есть следующие записи:

введите здесь описание изображения

и мне нужно сравнить эти значения, используя правильное условие, и сохранить результат (скажем, «0» для false и «1» для true в дополнительном столбце).

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

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

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

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


person gotqn    schedule 21.08.2013    source источник


Ответы (1)


Я не вижу необходимости в использовании sp_executesql в этом случае. Вы можете получить результат для всех записей сразу в одном выражении:

select Result = case
    when ct.Abbreviation='=' and t.ValueOne=t.ValueTwo then 1
    when ct.Abbreviation='>' and t.ValueOne>t.ValueTwo then 1
    when ct.Abbreviation='>=' and t.ValueOne>=t.ValueTwo then 1
    when ct.Abbreviation='<=' and t.ValueOne<=t.ValueTwo then 1
    when ct.Abbreviation='<>' and t.ValueOne<>t.ValueTwo then 1
    when ct.Abbreviation='<' and t.ValueOne<t.ValueTwo then 1
    else 0 end
from YourTable t
    join ConditionType ct on ct.ID = t.ConditionTypeID

и обновите дополнительный столбец примерно так:

;with cte as (
    select t.AdditionalColumn, Result = case
        when ct.Abbreviation='=' and t.ValueOne=t.ValueTwo then 1
        when ct.Abbreviation='>' and t.ValueOne>t.ValueTwo then 1
        when ct.Abbreviation='>=' and t.ValueOne>=t.ValueTwo then 1
        when ct.Abbreviation='<=' and t.ValueOne<=t.ValueTwo then 1
        when ct.Abbreviation='<>' and t.ValueOne<>t.ValueTwo then 1
        when ct.Abbreviation='<' and t.ValueOne<t.ValueTwo then 1
        else 0 end
    from YourTable t
        join ConditionType ct on ct.ID = t.ConditionTypeID
)
update cte
set AdditionalColumn = Result

Если вышеприведенная логика должна применяться во многих местах, а не только в одной таблице, то да, вы можете подумать о функции. Хотя я бы предпочел использовать встроенную функцию с табличным значением (а не скалярную), из-за накладных расходов, связанных с использованием определяемых пользователем скалярных функций (вызов и возврат, а также чем больше строк нужно обработать, тем больше времени уходит).

create function ftComparison
(
    @v1 float,
    @v2 float,
    @cType int
)
returns table
as return
    select
        Result = case
            when ct.Abbreviation='=' and @v1=@v2 then 1
            when ct.Abbreviation='>' and @v1>@v2 then 1
            when ct.Abbreviation='>=' and @v1>=@v2 then 1
            when ct.Abbreviation='<=' and @v1<=@v2 then 1
            when ct.Abbreviation='<>' and @v1<>@v2 then 1
            when ct.Abbreviation='<' and @v1<@v2 then 1
            else 0
        end
    from ConditionType ct
    where ct.ID = @cType

который затем можно применить как:

select f.Result
from YourTable t
    cross apply ftComparison(ValueOne, ValueTwo, t.ConditionTypeID) f

or

select f.Result
from YourAnotherTable t
    cross apply ftComparison(SomeValueColumn, SomeOtherValueColumn, @someConditionType) f
person i-one    schedule 23.08.2013