Есть ли способ сделать этот UDF детерминированным? - PullRequest
4 голосов
/ 22 января 2010

Я предполагаю, что это не является детерминированным просто потому, что DB_NAME() не является детерминированным? Если DB_NAME() не является детерминированным, почему он не является детерминированным?

ALTER FUNCTION [TheSchema].[udf_IS_PRODUCTION] ()
RETURNS bit
    WITH SCHEMABINDING
AS 
    BEGIN
        RETURN CASE WHEN DB_NAME() = 'PRODUCTION' THEN CONVERT(bit, 1) ELSE CONVERT(bit, 0) END
    END

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

ALTER FUNCTION [TheSchema].[udf_IS_PRODUCTION] ()
RETURNS bit
    WITH SCHEMABINDING
AS 
    BEGIN
        RETURN (SELECT IS_PRODUCTION FROM TheSchema.IS_PRODUCTION)
    END

FYI Это фрагмент кода в моей системе самоотчета о состоянии системы, который я использую для мониторинга потенциальных проблем.

    SELECT  'Non-deterministic Scalar UDF' AS Problem
           ,QUOTENAME(ROUTINE_SCHEMA) + '.' + QUOTENAME(ROUTINE_NAME) AS ROUTINE_NAME
    FROM    INFORMATION_SCHEMA.ROUTINES WITH (NOLOCK)
    WHERE   IS_DETERMINISTIC = 'NO'
            AND ROUTINE_TYPE = 'FUNCTION'
            AND DATA_TYPE <> 'TABLE'
    ORDER BY ROUTINE_SCHEMA
           ,ROUTINE_NAME

Ответы [ 4 ]

5 голосов
/ 22 января 2010

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

ALTER FUNCTION [TheSchema].[udf_IS_PRODUCTION] ()
RETURNS bit
    WITH SCHEMABINDING
AS 
BEGIN
    RETURN CONVERT(bit, 1)
END

И разверните его в своей тестовой базе данных:

ALTER FUNCTION [TheSchema].[udf_IS_PRODUCTION] ()
RETURNS bit
    WITH SCHEMABINDING
AS 
BEGIN
    RETURN CONVERT(bit, 0)
END

Это может показаться глупым, но ИМО имя базы данных не должно быть "жестко закодировано" больше, чем возвращаемое значение некоторого UDF.

Еще лучше, просто поместите эту информацию в конфигурационную таблицу где-нибудь.

2 голосов
/ 22 января 2010

Не могли бы вы, возможно, переписать свою функцию, чтобы не определять DB_NAME () внутри, а получать ее в качестве параметра ??

ALTER FUNCTION [TheSchema].[udf_IS_PRODUCTION] (DatabaseName VARCHAR(255))
RETURNS bit
WITH SCHEMABINDING
AS 
    BEGIN
        RETURN CASE WHEN DatabaseName = 'PRODUCTION' 
                    THEN CONVERT(bit, 1) 
                    ELSE CONVERT(bit, 0) 
               END
    END

Разве это не должно быть детерминированным, верно?

Когда вы вызываете его, вы можете использовать DB_NAME() как функцию для определения имени базы данных

1 голос
/ 22 января 2010

В строгом смысле детерминизма результат основан не на входных параметрах, а на состоянии внешнего объекта, который не находится под вашим контролем.

Имя может быть изменено и т. Д.,

Alter Database Modify Name = new_name

В 2005 году SQL не препятствует созданию функции, хотя, когда я пробовал ее по схеме по умолчанию. Если вы попадаете в ситуацию, когда он отказывается принимать функцию, основанную на недетерминизме, и вам приходится обходить ее (с учетом рисков и т. Д.), Обходной путь заключается в создании представления, использующего функцию, и затем выборе вид внутри функции.

1 голос
/ 22 января 2010

Детерминированная функция по определению - это функция, возвращаемое значение которой однозначно определяется значениями ее агрегатов.

Теперь, учитывая аргументы DB_NAME() (которых нет), вы можете сказать, что он вернет?

...