2010-01-22 2 views
4

Je suppose que ce n'est pas déterministe simplement parce que DB_NAME() n'est pas déterministe? Si DB_NAME() n'est pas déterministe, pourquoi n'est-elle pas déterministe?Y a-t-il un moyen de rendre cette fonction UDF déterministe?

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 

Mise à jour: Cette version fonctionne, est déterministe, permet le même code à utiliser dans une base de données et supprime le hardcoding du nom de base de données (ce qui me permet également de supprimer une autre exception de la santé du système automatique dans la base de données le nom de codage)

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

pour votre information C'est l'extrait de code dans mon système système d'autodéclaration santé que j'utilise pour surveiller les éventuels problèmes.

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 
+0

Parce que renommer la base de données ne se bloque pas toutes les données qu'il contient? Fondamentalement, quelqu'un serait en mesure de renommer la base de données au cours d'une longue requête. –

Répondre

4

Bien sûr, je peux penser à une façon de le rendre déterministe. Déployer cette fonction sur votre base de données de production:

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

et déployer celui-ci à votre base de données de test:

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

Cela peut sembler stupide, mais l'OMI le nom de la base de données ne doit pas être « codé en dur » plus si que la valeur de retour de certains UDF.

Mieux encore, mettez simplement cette information dans une table de configuration quelque part.

+0

Pour des raisons évidentes, je préférerais que le code soit identique entre les bases de données. Aussi, je préférerais encapsuler l'appel pour rendre le système un peu plus maintenable, clair et lisible. Une version qui utilise la table de configuration devient déterministe. Merci. –

+0

Il permet également d'effacer une autre exception d'intégrité concernant les noms de base de données codés en dur. Super. –

1

Une fonction déterministe, par définition, est une fonction dont la valeur retournée est identifiée de manière unique par les valeurs de ses agruments.

Maintenant, étant donné les arguments à DB_NAME() (qui ne sont pas), pouvez-vous dire ce que cela va-t-il renvoyer?

+0

C'est la définition de strictement déterministe, et toutes les fonctions internes doivent être strictement déterministes pour être marquées comme déterministes et ensuite utilisées pour faire des fonctions définies par l'utilisateur soit strictement déterministes, soit déterministes. –

1

Dans le sens strict du déterminisme, le résultat n'est pas basé sur les paramètres d'entrée, mais sur l'état d'un objet externe qui n'est pas sous votre contrôle.

Le nom pourrait être modifié etc,

Alter Database Modify Name = new_name 

En 2005, SQL n'empêche pas la fonction en cours de création mais quand je l'ai essayé contre le schéma par défaut. Si vous vous trouvez dans une situation où il refuse d'accepter une fonction basée sur le non-déterminisme et que vous devez contourner ce problème (avec les risques, etc.), l'itinéraire consiste à créer une vue utilisant cette fonction, puis à sélectionner à partir de la vue dans la fonction.

+0

La fonction est valide et fonctionne correctement, elle est juste non-déterministe. J'ai un rapport d'état automatique du système qui signale toute fonction scalaire non déterministe pour révision. Apparemment, DB_NAME n'est pas strictement déterministe, et pour toutes les fonctions intégrées, strictement déterministes et déterministes sont traités de la même façon - seules les fonctions strictement déterministes sont marquées comme déterministes. Les FDU qui dépendent de l'état de la base de données sont encore déterministes, mais pas strictement déterministes. –

+0

Votre rapport semble être très précis et spécifique à strictement déterministe, en ce sens, il est correct. – Andrew

+0

Je vais ajouter mon code de rapport de santé à la réponse - il n'y a qu'un indicateur déterministe pour les fonctions définies par l'utilisateur. –

2

Vous ne pourriez peut-être pas réécrire votre fonction pour ne pas déterminer le DB_NAME() en interne, mais l'envoyer en paramètre ??

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 

Cela ne devrait pas être déterministe, n'est-ce pas?

Lorsque vous appelez, vous pouvez utiliser DB_NAME() en fonction pour déterminer le nom de la base de données

+0

Je préférerais ne pas avoir les appelants faire ce travail, il pourrait les encourager à simplement en ligne la logique de toute façon, en vain l'objectif de l'encapsulation. J'ai posté ma solution finale. –

Questions connexes