Modifica il valore predefinito di sistema per maxrecursion


12

Come posso modificare il valore predefinito a livello di sistema di MAXRECURSION?

Di default è 100, ma devo aumentarlo a qualcosa come 1000.

Non riesco a utilizzare i suggerimenti per le query poiché sto utilizzando un programma che accetta la mia query e la esegue per me e, purtroppo, non posso aggirare questa limitazione.

Tuttavia, ho i diritti di amministratore sull'istanza del server. Ho sfogliato le sfaccettature del server, ma non vedo nulla correlato alle opzioni di query o alla ricorsione. Presumo che ci debba essere un posto da qualche parte dove posso aggiornare il valore predefinito a livello di sistema.

Qualche idea?


3
Volevo solo verificare che hai capito che il limite di 100 era solo su viste e funzioni e che potresti usare una procedura memorizzata e sovrascrivere localmente lì? C'è qualche bisogno particolare di usare una funzione? Poiché la ricorsione è abbastanza inefficiente, suggerirei anche di camminare una volta nella gerarchia e di archiviare l'output in una tabella. È quindi possibile creare una funzione che fa riferimento a quella tabella. Cosa ne pensi?
wBob,

Risposte:


10

Se le tue query hanno una forma comune, potresti essere in grado di aggiungere il suggerimento richiesto per la ricorrenza massima usando una o più guide di piano.

Ci può essere un talento per farli bene. Se aggiungi dettagli specifici della query alla tua domanda, potremmo essere in grado di risolverlo per te. In genere, tracciare l'SQL effettivamente colpire il server o ottenere un modulo con parametri utilizzando la procedura integrata sys.sp_get_query_template , quindi creare una guida di piano TEMPLATE e / o OBJECT / SQL.

Vedere la documentazione per ulteriori informazioni:

Le guide di piano dovranno essere riconvalidate ogni volta che cambia il codice dell'applicazione e quando SQL Server viene aggiornato o aggiornato. Questo dovrebbe far parte del normale ciclo di test.

Si noti che la convalida della guida di piano utilizzando sys.fn_validate_plan_guide potrebbe segnalare erroneamente un errore se l'istruzione guidata fa riferimento a una tabella temporanea. Vedi questa domanda:

La convalida della guida di piano con fn_validate_plan_guide fornisce falsi positivi

La guida Plan Plan Successful and Plan Guide Le classi Profiler non riuscita ed Eventi estesi possono essere utilizzate anche per monitorare le applicazioni della guida plan.

Connect è stato ritirato prima che il suggerimento di miglioramento del prodotto Consenti valori limite MAXRECURSION diversi da 100 per le viste e le UDF di Steve Kass fosse implementato. Se desideri occuparti subito di Microsoft, consulta le opzioni nella guida e nel feedback di SQL Server .


Questo è frustrante e non risponde alla domanda invece seppellirci in una tana di coniglio della documentazione. EF Core (un tipico ORM) genera query per te anche se gli dai un'istruzione SQL non elaborata, che racchiude che in una selezione padre, chiunque utilizzi EF Core ha questo problema. La tua soluzione è "pianifica le tue query".
Guerra il

@War È la migliore risposta che posso dare a questa particolare domanda con i dettagli forniti. L'unico modo che conosco per aggiungere un suggerimento di ricorsione massima è tramite una cosa di SQL Server chiamata Guida del piano, che non ha nulla a che fare con la "pianificazione delle query". Se hai una tua domanda specifica, chiedila separatamente con un esempio riproducibile minimo .
Paul White 9

9

Se devi assolutamente utilizzare una funzione (una limitazione del tuo strumento ETL come intendi), puoi specificare OPTIONcome parte di una funzione con valori di tabella multiistruzione, ad esempio qualcosa del genere:

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

Questo ha funzionato anche per me se visto in una prospettiva come suggerisce i tuoi strumenti ETL. Non c'è modo di modificare tutto questo sistema, ma poiché la ricorsione può essere inefficiente, questa è probabilmente una buona cosa. Non è possibile specificare un suggerimento per la query (usando OPTION) all'interno del corpo di una funzione con valori di tabella incorporata, come nell'esempio.

Prendi in considerazione la possibilità di modificare il tuo processo per seguire la gerarchia solo una volta quando ricevi gli episodi e memorizzi l'output in una tabella relazionale. È possibile utilizzare un proc memorizzato per fare ciò in modo da non incorrere in questa limitazione.

Penso anche che potrebbe esserci un bug nel tuo codice: se il tuo CTE si unisce a personId e recluta su eventId, l'eventoId 101 presenterebbe due volte penso, come duplicato. Forse ho frainteso il tuo codice, fammi sapere cosa ne pensi.

HTH


questo non funziona poiché il parametro "OPTIONS" deve essere applicato a livello di istruzione e l'istruzione in questione è la chiamata alla funzione, ciò restituirà un'eccezione.
Guerra il

0

Mi sono ispirato a questo argomento .

Ecco cosa ho fatto per risolvere il problema.

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

Quindi invoco questa funzione in questo modo:

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

In questo modo, nessuna della mia logica CTE deve essere ripetuta e non pago nulla in più in termini di prestazioni. È una seccatura che debba essere fatto in questo modo, ma posso conviverci.


3
Non vedo come questo risolva un problema di ricorsione. L'invocazione della funzione non è ricorsiva.
ypercubeᵀᴹ

@ ypercubeᵀᴹ - il bit ricorsivo del CTE va dove ho i puntini di sospensione - la mia particolare logica ricorsiva non è realmente rilevante per il problema, ma si può presumere che il CTE sia, in effetti, ricorsivo. La whereclausola dopo i puntini di sospensione impedisce che si verifichino troppe ricorsioni utilizzando il parametro funzione come vincolo. Immagino che dovrebbe esserci una dichiarazione dopo la definizione CTE. Lo aggiungerò io.
carl.anderson,

3
Capisco molto bene che il CTE è ricorsivo. Il problema è che l'invocazione (chiamate di funzione) non è ricorsiva . Ad esempio, chiamate le funzioni con punti di partenza (righe) con EventID=1(e 101.201, ... 901). Ma la query originale (se eseguita con MAXRECURSION = 100000000) potrebbe non visitare mai la riga con EventID=101(e 201, .., 901). Quindi le due query (originale e la tua soluzione) possono restituire risultati diversi (nessuna riga con 101 nella prima, sì nella seconda)! Oppure può visitare il 101 ma prima del passaggio 100, quindi la tua soluzione includerebbe la riga due volte nei risultati (di nuovo diverso)
ypercubeᵀᴹ

2
A meno che ovviamente i dati non siano collegati a valori EventID sequenziali (1,2,, 3 ..., 99,100,101, ..). In tal caso, non è necessario un CTE ricorsivo.
ypercubeᵀᴹ

In che modo questo risolve il problema della profondità sconosciuta per qualcosa come ... ottenere un albero da un determinato percorso DMS come set di righe?
Guerra il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.