Modifier la valeur par défaut à l'échelle du système pour maxrecursion

12

Comment modifier la valeur par défaut de l'ensemble du système MAXRECURSION?

Par défaut, il est de 100, mais je dois l'augmenter à quelque chose comme 1000.

Je ne peux pas utiliser d'indices de requête car j'utilise un programme qui prend ma requête et l'exécute pour moi et je ne peux malheureusement pas contourner cette limitation.

Cependant, j'ai des droits d'administrateur sur l'instance de serveur. J'ai fouillé dans les facettes du serveur, mais je n'y vois rien lié aux options de requête ou à la récursivité. Je suppose qu'il doit y avoir un endroit quelque part où je peux mettre à jour la valeur par défaut à l'échelle du système.

Des idées?

carl.anderson
la source
3
Je voulais juste vérifier que vous compreniez que la limite de 100 ne concernait que les vues et les fonctions et que vous pouviez utiliser une procédure stockée et remplacer localement là-bas? Y a-t-il un besoin particulier d'utiliser une fonction? Comme la récursivité est assez inefficace, je suggérerais également de parcourir la hiérarchie une seule fois et de stocker la sortie dans une table. Vous pouvez ensuite créer une fonction qui fait référence à ce tableau. Qu'est-ce que tu penses?
wBob

Réponses:

10

Si vos requêtes ont une forme commune, vous pourrez peut-être ajouter le conseil maxrecursion requis à l'aide d'un ou de plusieurs guides de plan.

Il peut y avoir un talent pour les faire correctement. Si vous ajoutez des détails de requête spécifiques à votre question, nous pourrons peut-être les résoudre pour vous. En règle générale, vous suivrez le SQL qui frappe réellement le serveur ou vous obtiendrez un formulaire paramétré à l'aide de la procédure intégrée sys.sp_get_query_template , puis vous créerez un guide de plan TEMPLATE et / ou OBJECT / SQL.

Voir la documentation pour plus d'informations:

Les guides de plan devront être revalidés chaque fois que le code d'application change et lorsque SQL Server est corrigé ou mis à niveau. Cela devrait simplement faire partie de votre cycle de test normal.

Notez que la validation du guide de plan à l'aide de sys.fn_validate_plan_guide peut signaler de manière incorrecte un échec si l'instruction guidée fait référence à une table temporaire. Voir cette question:

La validation du guide de plan avec fn_validate_plan_guide donne des faux positifs

Les classes Plan Guide Successful et Plan Guide Unsuccessful Profiler et Extended Events peuvent également être utilisées pour surveiller les applications de guide de plan.

Connect a été retiré avant la mise en œuvre de la suggestion d'amélioration du produit Autoriser les valeurs limites MAXRECURSION autres que 100 pour les vues et les FDU de Steve Kass . Si vous souhaitez en discuter avec Microsoft maintenant, consultez les options de l' aide et des commentaires de SQL Server .

Paul White 9
la source
C'est frustrant et ne répond pas à la question au lieu de nous enfouir dans un trou de lapin de documentation. EF Core (un ORM typique) génère des requêtes pour vous même si vous lui donnez une instruction SQL brute qu'il enveloppe que dans une sélection parent, toute personne utilisant EF Core a ce problème. Votre solution est de "planifier vos requêtes".
War
@War C'est la meilleure réponse que je puisse donner à cette question particulière avec les détails fournis. Le seul moyen que je connaisse pour ajouter un indice de récursivité maximale est via une chose SQL Server appelée Plan Guide, qui n'a rien à voir avec la "planification de vos requêtes". Si vous avez une question spécifique, posez-la séparément avec un exemple reproductible minimal .
Paul White 9
9

Si vous devez absolument utiliser une fonction (une limitation de votre outil ETL comme vous l'impliquez), vous pouvez spécifier OPTIONdans le cadre d'une fonction table multi-instructions, par exemple quelque chose comme ceci:

CREATE FUNCTION dbo.udf_MyFunction ( @StartID INT ) 
RETURNS @tv TABLE
(
id INT
)
AS
BEGIN

    WITH Episodes( xlevel, PersonID, EventID, EpisodeID, StartDT, EndDT ) AS (
    -- Anchor case - the first EventID for each person.
    SELECT 1 AS xlevel, PersonID, EventID, @StartID, StartDT, EndDT 
    FROM dbo.EventTable
    WHERE EventID = @StartID

    UNION ALL

    SELECT xlevel + 1, et.PersonID, et.EventID, c.EventID + 1, et.StartDT, et.EndDT
    FROM Episodes c
        INNER JOIN dbo.EventTable et ON c.PersonID = et.PersonID
            AND et.EventID = c.EventID + 1
    --WHERE c.EventID <= (@StartID + 99)
    )
    INSERT INTO @tv
    SELECT PersonID
    FROM Episodes
    OPTION ( MAXRECURSION 1000 )

    RETURN

END
GO

Cela a également fonctionné pour moi lorsqu'il est enveloppé dans une vue, comme vous le suggérez pour vos outils ETL. Il n'y a aucun moyen de modifier ce système, mais comme la récursivité peut être inefficace, c'est probablement une bonne chose. Vous ne pouvez pas spécifier d'indicateur de requête (à l'aide OPTION) dans le corps d'une fonction de valeur de table en ligne, comme dans votre exemple.

Envisagez de modifier votre processus pour parcourir la hiérarchie une seule fois lorsque vous recevez vos épisodes et stockez la sortie dans une table relationnelle. Vous pouvez utiliser un proc stocké pour ce faire afin de ne pas rencontrer cette limitation.

Je pense également qu'il pourrait y avoir un bug dans votre code: si votre CTE se joint à personId et se reproduit sur eventId, le eventId 101 présenterait deux fois je pense, en double. J'ai peut-être mal interprété votre code, faites-moi savoir ce que vous en pensez.

HTH

wBob
la source
cela ne fonctionne pas car le paramètre "OPTIONS" doit être appliqué au niveau de l'instruction et l'instruction en question est l'appel à la fonction, cela retournera une exception.
War
0

Je me suis inspiré de ce sujet .

Voici ce que j'ai fait pour résoudre le problème.

CREATE FUNCTION MySchema.udf_MyFunction(@StartID INT) 
RETURNS TABLE 
AS RETURN
WITH
Episodes(PersonID, EventID, EpisodeID, StartDT, EndDT) AS (
  -- Anchor case - the first EventID for each person.
  SELECT PersonID, EventID, @StartID, StartDT, EndDT 
  FROM MySchema.EventTable
  WHERE EventID = @StartID
UNION ALL
  SELECT
    ...
  WHERE
    EventID <= (@StartID + 99)
)
SELECT * FROM Episodes

Ensuite, j'appelle cette fonction comme ceci:

WITH
Episodes AS (
  SELECT * FROM MySchema.udf_MyFunction(1)
UNION ALL
  SELECT * FROM MySchema.udf_MyFunction(101)
UNION ALL
  SELECT * FROM MySchema.udf_MyFunction(201)
-- ...
UNION ALL
  SELECT * FROM MySchema.udf_MyFunction(901)
)
SELECT * FROM Episodes

De cette façon, aucune de mes logiques CTE ne doit être répétée et je ne paie rien de plus en termes de performances. C'est une nuisance que cela doive être fait de cette façon, mais je peux vivre avec.

carl.anderson
la source
3
Je ne vois pas comment cela résout un problème de récursivité. L'invocation de la fonction n'est pas récursive.
ypercubeᵀᴹ
@ ypercubeᵀᴹ - le bit récursif du CTE va là où j'ai mes points de suspension - ma logique récursive particulière n'est pas vraiment pertinente pour le problème, mais vous pouvez supposer que le CTE est, en fait, récursif. La whereclause après les points de suspension empêche trop de récursions de se produire en utilisant le paramètre de fonction comme contrainte. Je suppose qu'il devrait y avoir une déclaration après la définition CTE, cependant. Je vais ajouter ça.
carl.anderson du
3
Je comprends très bien que le CTE est récursif. Le problème est que l'invocation (appels de fonction) n'est pas récursive . Par exemple, vous appelez les fonctions avec des points de départ (lignes) avec EventID=1(et 101,201, ... 901). Mais la requête d'origine (si exécutée avec MAXRECURSION = 100000000) peut ne jamais visiter la ligne avec EventID=101(et 201, .., 901). Ainsi, les deux requêtes (d'origine et votre solution) peuvent renvoyer des résultats différents (pas de ligne avec 101 dans la première, oui dans la 2ème)! Ou il peut visiter le 101 mais avant l'étape 100, donc votre solution inclurait la ligne deux fois dans les résultats (encore différent)
ypercubeᵀᴹ
2
Sauf si, bien sûr, les données sont connectées via des valeurs EventID séquentielles (1,2,, 3 ..., 99,100,101, ..). Dans ce cas, vous n'auriez pas du tout besoin d'un CTE récursif.
ypercubeᵀᴹ
Comment cela résout-il le problème de profondeur inconnue pour quelque chose comme ... obtenir un arbre à partir d'un chemin DMS donné en tant qu'ensemble de lignes?
War