Cambiar el valor predeterminado del sistema para maxrecursion

12

¿Cómo cambio el valor predeterminado de todo el sistema de MAXRECURSION?

Por defecto es 100, pero necesito aumentarlo a algo así como 1000.

No puedo usar sugerencias de consulta ya que estoy usando un programa que toma mi consulta y la ejecuta por mí y desafortunadamente no puedo evitar esta limitación.

Sin embargo, tengo derechos de administrador en la instancia del servidor. He hurgado en las facetas del servidor, pero no veo nada relacionado con las opciones de consulta o la recursividad. Supongo que tiene que haber un lugar en algún lugar donde pueda actualizar el valor predeterminado de todo el sistema.

¿Algunas ideas?

carl.anderson
fuente
3
Solo quería comprobar que entendía que el límite de 100 solo estaba en vistas y funciones y que podía usar un procedimiento almacenado y anular localmente allí. ¿Hay alguna necesidad particular de usar una función? Como la recursividad es bastante ineficiente, también sugeriría recorrer la jerarquía solo una vez y almacenar el resultado en una tabla. Luego puede crear una función que se refiera a esa tabla. ¿Qué piensas?
wBob

Respuestas:

10

Si sus consultas tienen una forma común, es posible que pueda agregar la sugerencia de recursión máxima requerida utilizando una o más guías de plan.

Puede haber una habilidad especial para acertar. Si agrega detalles específicos de la consulta a su pregunta, podríamos resolverlo por usted. Por lo general, debe rastrear el SQL que realmente está llegando al servidor, u obtener un formulario parametrizado utilizando el procedimiento incorporado sys.sp_get_query_template , y luego crear una guía de plan TEMPLATE y / u OBJECT / SQL.

Consulte la documentación para obtener más información:

Las guías de plan deberán revalidarse cada vez que cambie el código de la aplicación y cuando se parche o actualice SQL Server. Esto debería ser parte de su ciclo de prueba normal.

Tenga en cuenta que la validación de la guía del plan utilizando sys.fn_validate_plan_guide puede informar incorrectamente un error si la instrucción guiada hace referencia a una tabla temporal. Ver esta pregunta:

La validación de la guía del plan con fn_validate_plan_guide da falsos positivos

Las clases Planificador exitoso y Planificador exitoso de la guía del plan y Eventos extendidos también se pueden usar para monitorear las aplicaciones de la guía del plan.

Connect se retiró antes de la sugerencia de mejora del producto Permitir valores límite MAXRECURSION distintos de 100 para vistas y UDF de Steve Kass se implementó. Si desea abordarlo ahora con Microsoft, consulte las opciones en la ayuda y comentarios de SQL Server .

Paul White 9
fuente
Esto es frustrante y no responde la pregunta, sino que nos entierra en una madriguera de documentación. EF Core (un ORM típico) genera consultas para usted, incluso si le da una declaración SQL sin procesar, envuelve que en una selección primaria, cualquiera que use EF Core tiene este problema. Su solución es "planificar sus consultas".
Guerra
@War Es la mejor respuesta que puedo dar a esta pregunta en particular con los detalles proporcionados. La única forma en que sé agregar una sugerencia de recursividad máxima es a través de una cosa de SQL Server llamada Plan Guide, que no tiene nada que ver con "planificar sus consultas". Si tiene una pregunta específica, hágalo por separado con un ejemplo mínimo reproducible .
Paul White 9
9

Si tiene que usar absolutamente una función (una limitación de su herramienta ETL como usted lo implica), puede especificar OPTIONcomo parte de una función con valores de tabla de varias instrucciones, por ejemplo, algo como esto:

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

Esto también funcionó para mí cuando se envolvió en una vista, como sugiere que sus herramientas ETL lo hacen. No hay forma de alterar este sistema, pero como la recursión puede ser ineficiente, probablemente sea algo bueno. No puede especificar una sugerencia de consulta (usando OPTION) dentro del cuerpo de una función con valores de tabla en línea, como en su ejemplo.

Considere modificar su proceso para recorrer la jerarquía solo una vez cuando reciba sus Episodios y almacene la salida en una tabla relacional. Puede usar un proceso almacenado para hacer esto, de modo que no se encuentre con esta limitación.

También creo que puede haber un error en su código: si su CTE se une a personId y se repite en eventId, el eventId 101 se presentaría dos veces, creo, como un duplicado. Posiblemente he malinterpretado su código, hágame saber lo que piensa.

HTH

wBob
fuente
esto no funciona ya que el parámetro "OPCIONES" debe aplicarse a nivel de instrucción y la instrucción en cuestión es la llamada a la función, esto devolverá una excepción.
Guerra
0

Me inspiré en este tema .

Esto es lo que he hecho para resolver el 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

Luego invoco esta función así:

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 esta manera, nada de mi lógica CTE tiene que repetirse y no pago nada extra en términos de rendimiento. Es una molestia que tenga que hacerse de esta manera, pero puedo vivir con eso.

carl.anderson
fuente
3
No veo cómo esto resuelve un problema de recurrencia. La invocación de la función no es recursiva.
ypercubeᵀᴹ 05 de
@ ypercubeᵀᴹ: la parte recursiva del CTE va donde tengo mis puntos suspensivos: mi lógica recursiva particular no es realmente relevante para el problema, pero puede suponer que el CTE es, de hecho, recursivo. La wherecláusula después de los puntos suspensivos evita que se produzcan demasiadas recursiones utilizando el parámetro de función como restricción. Sin embargo, supongo que debería haber una declaración después de la definición de CTE. Agregaré eso.
carl.anderson
3
Entiendo muy bien que el CTE es recursivo. El problema es que la invocación (llamadas a funciones) no son recursivas . Por ejemplo, llama a las funciones con puntos de inicio (filas) con EventID=1(y 101,201, ... 901). Pero la consulta original (si se ejecuta con MAXRECURSION = 100000000) puede que nunca visite la fila con EventID=101(y 201, .., 901). Por lo tanto, las dos consultas (original y su solución) pueden devolver resultados diferentes (sin fila con 101 en la primera, sí en la segunda). O puede visitar el 101 pero antes del paso 100, por lo que su solución incluiría la fila dos veces en los resultados (nuevamente diferente)
ypercubeᵀᴹ
2
A menos que, por supuesto, los datos estén conectados a través de valores de EventID secuenciales (1,2,, 3 ..., 99,100,101, ..). En ese caso, no necesitarías un CTE recursivo en absoluto.
ypercubeᵀᴹ
¿Cómo resuelve esto el problema de profundidad desconocido para algo como ... obtener un árbol de una ruta DMS dada como un conjunto de filas?
Guerra