Ändern Sie die systemweite Standardeinstellung für maxrecursion

12

Wie ändere ich den systemweiten Standardwert von MAXRECURSION?

Standardmäßig ist es 100, aber ich muss es auf ungefähr 1000 erhöhen.

Ich kann keine Abfragehinweise verwenden, da ich ein Programm verwende, das meine Abfrage aufnimmt und für mich ausführt, und ich kann diese Einschränkung leider nicht umgehen.

Ich habe jedoch Administratorrechte für die Serverinstanz. Ich habe mich in den Server-Facetten umgesehen, sehe dort jedoch nichts in Bezug auf Abfrageoptionen oder Rekursion. Ich gehe davon aus , dass es irgendwo einen Ort geben muss, an dem ich den systemweiten Standard aktualisieren kann.

Irgendwelche Ideen?

carl.anderson
quelle
3
Ich wollte nur überprüfen, ob Sie verstanden haben, dass das Limit von 100 nur für Ansichten und Funktionen gilt und dass Sie eine gespeicherte Prozedur verwenden und dort lokal überschreiben können. Gibt es eine besondere Notwendigkeit, eine Funktion zu verwenden? Da die Rekursion ziemlich ineffizient ist, würde ich auch vorschlagen, die Hierarchie nur einmal zu durchlaufen und die Ausgabe in einer Tabelle zu speichern. Sie können dann eine Funktion erstellen, die auf diese Tabelle verweist. Was denkst du?
wBob

Antworten:

10

Wenn Ihre Abfragen eine gemeinsame Form haben, können Sie möglicherweise den erforderlichen Hinweis zur maximalen Rekursion mithilfe einer oder mehrerer Planhilfslinien hinzufügen.

Es kann ein Händchen sein, sie richtig zu machen. Wenn Sie Ihrer Frage bestimmte Abfragedetails hinzufügen, können wir dies möglicherweise für Sie klären. In der Regel verfolgen Sie die SQL, die tatsächlich auf den Server trifft, oder rufen mithilfe der integrierten Prozedur sys.sp_get_query_template ein parametrisiertes Formular ab und erstellen dann eine TEMPLATE- und / oder OBJECT / SQL-Plananleitung.

Weitere Informationen finden Sie in der Dokumentation:

Planhandbücher müssen erneut validiert werden, wenn sich der Anwendungscode ändert und wenn SQL Server gepatcht oder aktualisiert wird. Dies sollte nur ein Teil Ihres normalen Testzyklus sein.

Beachten Sie, dass die Planleitfadenvalidierung mit sys.fn_validate_plan_guide möglicherweise fälschlicherweise einen Fehler meldet, wenn die geführte Anweisung auf eine temporäre Tabelle verweist. Siehe diese Frage:

Die Validierung des Planleitfadens mit fn_validate_plan_guide führt zu falsch positiven Ergebnissen

Die Klassen Plan Guide Successful und Plan Guide Unsuccessful Profiler und Extended Events können auch zum Überwachen von Plan Guide-Anwendungen verwendet werden.

Connect wurde eingestellt, bevor der Vorschlag zur Produktverbesserung andere MAXRECURSION-Grenzwerte als 100 für Ansichten und UDFs von Steve Kass zulassen implementiert wurde. Wenn Sie es jetzt mit Microsoft aufnehmen möchten, lesen Sie die Optionen in der SQL Server-Hilfe und im Feedback .

Paul White 9
quelle
Das ist frustrierend und beantwortet nicht die Frage, sondern begräbt uns in einem Kaninchenbau der Dokumentation. EF Core (ein typisches ORM) generiert Abfragen für Sie, selbst wenn Sie ihm eine unformatierte SQL-Anweisung geben, die umschließt, dass in einer übergeordneten Auswahl jeder, der EF Core verwendet, dieses Problem hat. Ihre Lösung lautet "Planen Sie Ihre Anfragen".
Krieg
@ War Es ist die beste Antwort, die ich auf diese spezielle Frage mit den bereitgestellten Details geben kann. Die einzige Möglichkeit, einen Hinweis zur maximalen Rekursion hinzuzufügen, besteht in einem SQL Server-Element namens Plan Guide, das nichts mit "Planen Ihrer Abfragen" zu tun hat. Wenn Sie eine bestimmte Frage haben, stellen Sie diese bitte separat mit einem minimal reproduzierbaren Beispiel .
Paul White 9
9

Wenn Sie unbedingt eine Funktion verwenden müssen (eine Einschränkung Ihres ETL-Tools, wie Sie implizieren), können Sie diese OPTIONals Teil einer Funktion mit Tabellenwerten mit mehreren Anweisungen angeben , z.

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

Dies funktionierte auch für mich, wenn ich in eine Ansicht eingebunden wurde, wie Sie es von Ihren ETL-Tools vorschlagen. Es gibt keine Möglichkeit, dies systemweit zu ändern, aber da Rekursion ineffizient sein kann, ist dies wahrscheinlich eine gute Sache. Sie können keinen Abfragehinweis (using OPTION) im Hauptteil einer Inline-Tabellenwertfunktion angeben , wie in Ihrem Beispiel.

Ändern Sie Ihren Prozess so, dass die Hierarchie nur einmal durchlaufen wird, wenn Sie Ihre Episoden erhalten und die Ausgabe in einer relationalen Tabelle speichern. Sie könnten dazu einen gespeicherten Prozess verwenden, damit diese Einschränkung nicht auftritt.

Ich denke auch, dass es einen Fehler in Ihrem Code geben könnte: Wenn Ihr CTE bei personId beitritt und bei eventId rekursiv ist, würde die eventId 101 meiner Meinung nach zweimal als Duplikat angezeigt. Möglicherweise habe ich Ihren Code falsch interpretiert. Lassen Sie mich wissen, was Sie denken.

HTH

wBob
quelle
Dies funktioniert nicht, da der Parameter "OPTIONS" auf Anweisungsebene angewendet werden muss und die betreffende Anweisung der Aufruf der Funktion ist. Dies gibt eine Ausnahme zurück.
Krieg
0

Ich habe mich von diesem Thema inspirieren lassen .

Folgendes habe ich getan, um das Problem zu lösen.

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

Dann rufe ich diese Funktion folgendermaßen auf:

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

Auf diese Weise muss keine meiner CTE-Logik wiederholt werden und ich zahle nichts extra in Bezug auf die Leistung. Es ist ein Ärgernis, dass es so gemacht werden muss, aber ich kann damit leben.

carl.anderson
quelle
3
Ich sehe nicht, wie dies ein Rekursionsproblem löst. Der Aufruf der Funktion ist nicht rekursiv.
Ypercubeᵀᴹ
@ ypercubeᵀᴹ - das rekursive Bit des CTE geht dahin, wo ich meine Ellipse habe - meine spezielle rekursive Logik ist für das Problem nicht wirklich relevant, aber Sie können davon ausgehen, dass der CTE tatsächlich rekursiv ist. Die whereKlausel nach den Auslassungspunkten verhindert, dass zu viele Rekursionen auftreten, indem der Funktionsparameter als Einschränkung verwendet wird. Ich denke, es sollte jedoch eine Aussage nach der CTE-Definition geben. Ich werde das hinzufügen.
Carl.anderson
3
Ich verstehe sehr gut, dass der CTE rekursiv ist. Das Problem ist, dass der Aufruf (Funktionsaufrufe) nicht rekursiv ist . Beispielsweise rufen Sie die Funktionen mit Startpunkten (Zeilen) mit EventID=1(und 101,201, ... 901) auf. Die ursprüngliche Abfrage (wenn sie mit MAXRECURSION = 100000000 ausgeführt wird) besucht die Zeile jedoch möglicherweise nie mit EventID=101(und 201, .., 901). Die beiden Abfragen (Original und Ihre Lösung) können also unterschiedliche Ergebnisse liefern (keine Zeile mit 101 in der ersten, ja in der zweiten)! Oder es besucht die 101, aber vor Schritt 100, sodass Ihre Lösung die Zeile zweimal in die Ergebnisse
einbezieht
2
Es sei denn natürlich, die Daten werden durch sequentielle EventID-Werte (1,2 ,, 3 ..., 99,100,101, ..) verbunden. In diesem Fall benötigen Sie überhaupt keinen rekursiven CTE.
Ypercubeᵀᴹ
Wie löst dies das Problem der unbekannten Tiefe für so etwas wie ... einen Baum aus einem bestimmten DMS-Pfad als Rowset abzurufen?
Krieg