Alterar o padrão geral do sistema para maxrecursion

12

Como altero o valor padrão de todo o sistema MAXRECURSION?

Por padrão, é 100, mas preciso aumentá-lo para algo como 1000.

Não consigo usar dicas de consulta, pois estou usando um programa que pega minha consulta e a executa para mim e, infelizmente, não consigo contornar essa limitação.

No entanto, eu tenho direitos de administrador na instância do servidor. Eu dei uma olhada nas facetas do servidor, mas não vejo nada relacionado a opções de consulta ou recursão. Suponho que deve haver um lugar em algum lugar onde eu possa atualizar o padrão de todo o sistema.

Alguma ideia?

carl.anderson
fonte
3
Eu só queria verificar se você entendeu que o limite de 100 era apenas em visualizações e funções e que você poderia usar um procedimento armazenado e substituir localmente lá? Existe alguma necessidade específica de usar uma função? Como a recursão é bastante ineficiente, eu também sugeria caminhar pela hierarquia apenas uma vez e armazenar a saída em uma tabela. Você pode criar uma função que se refere a essa tabela. O que você acha?
WBob 05/04

Respostas:

10

Se suas consultas tiverem um formato comum, você poderá adicionar a dica de maxrecursão necessária usando um ou mais guias de plano.

Pode haver um jeito de acertar. Se você adicionar detalhes específicos da consulta à sua pergunta, poderemos resolver isso para você. Normalmente, você rastreia o SQL que realmente está atingindo o servidor ou obtém um formulário parametrizado usando o procedimento interno sys.sp_get_query_template e cria um guia de plano TEMPLATE e / ou OBJECT / SQL.

Consulte a documentação para obter mais informações:

Os guias de plano precisarão ser revalidados sempre que o código do aplicativo for alterado e quando o SQL Server for corrigido ou atualizado. Isso deve fazer parte do seu ciclo de testes normal.

Observe que a validação do guia de plano usando sys.fn_validate_plan_guide pode relatar incorretamente uma falha se a instrução guiada fizer referência a uma tabela temporária. Veja esta pergunta:

A validação do guia de plano com fn_validate_plan_guide fornece falsos positivos

As classes Guia de plano bem - sucedido e Guia de plano sem êxito e Eventos estendidos também podem ser usadas para monitorar aplicativos de guia de plano.

O Connect foi retirado antes da sugestão de melhoria do produto Permitir que valores-limite de MAXRECURSION diferentes de 100 para visualizações e UDFs de Steve Kass fossem implementados. Se você deseja fazer parte da Microsoft agora, consulte as opções na ajuda e nos comentários do SQL Server .

Paul White 9
fonte
Isso é frustrante e não responde à pergunta, mas nos enterra em uma toca de documentação. O EF Core (um ORM típico) gera consultas para você, mesmo que você forneça uma instrução SQL bruta que envolva que em uma seleção pai, qualquer pessoa que use o EF Core tenha esse problema. Sua solução é "planejar suas consultas".
Guerra
@ War É a melhor resposta que posso dar a esta pergunta em particular com os detalhes fornecidos. A única maneira que conheço de adicionar uma dica de recursão máxima é através de uma coisa do SQL Server chamada Guia de Plano, que nada tem a ver com "planejar suas consultas". Se você tiver uma pergunta específica, pergunte-a separadamente com um exemplo mínimo reproduzível .
Paul White 9
9

Se você precisar absolutamente usar uma função (uma limitação da sua ferramenta ETL, como você sugere), poderá especificar OPTIONcomo parte de uma função com valor de tabela com várias instruções, por exemplo, algo como isto:

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

Isso também funcionou para mim quando envolvido em uma exibição, como você sugere suas ferramentas ETL. Não há como alterar isso em todo o sistema, mas como a recursão pode ser ineficiente, isso provavelmente é uma coisa boa. Você não pode especificar uma dica de consulta (usando OPTION) no corpo de uma função embutida com valor de tabela, como no seu exemplo.

Considere alterar seu processo para percorrer a hierarquia apenas uma vez ao receber seus episódios e armazenar a saída em uma tabela relacional. Você pode usar um procedimento armazenado para fazer isso, para não entrar nessa limitação.

Eu também acho que pode haver um erro no seu código: se o seu CTE se unir a personId e se repetir em eventId, o eventId 101 apresentaria duas vezes, como uma duplicata. Possivelmente, eu interpretei mal o seu código, deixe-me saber o que você pensa.

HTH

wBob
fonte
isso não funciona, pois o parâmetro "OPTIONS" deve ser aplicado no nível da instrução e a instrução em questão é a chamada para a função; isso retornará uma exceção.
Guerra
0

Eu me inspirei neste tópico .

Aqui está o que eu fiz para resolver o 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

Então eu invoco esta função assim:

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

Dessa forma, nenhuma das minhas lógicas CTE precisa ser repetida e eu não pago nada a mais em termos de desempenho. É um incômodo que isso tenha que ser feito dessa maneira, mas eu posso viver com isso.

carl.anderson
fonte
3
Não vejo como isso resolve um problema de recursão. A invocação da função não é recursiva.
precisa saber é o seguinte
@ ypercubeᵀᴹ - o bit recursivo do CTE vai para onde tenho minhas reticências - minha lógica recursiva específica não é realmente relevante para o problema, mas você pode supor que o CTE é, de fato, recursivo. A wherecláusula após as reticências impede que ocorram muitas recursões usando o parâmetro de função como restrição. Acho que deveria haver uma declaração após a definição da CTE. Vou acrescentar isso.
Carl.anderson
3
Entendo muito bem que o CTE é recursivo. O problema é que a chamada (chamadas de função) não é recursiva . Por exemplo, você chama as funções com pontos de partida (linhas) com EventID=1(e 101,201, ... 901). Mas a consulta original (se executada com MAXRECURSION = 100000000) pode nunca visitar a linha com EventID=101(e 201, .., 901). Portanto, as duas consultas (original e sua solução) podem retornar resultados diferentes (nenhuma linha com 101 na primeira, sim na segunda)! Ou pode visitar o 101, mas antes do passo 100, então sua solução incluiria a linha duas vezes nos resultados (novamente diferente)
ypercubeᵀᴹ
2
A menos que os dados estejam conectados através de valores EventID seqüenciais (1,2,, 3 ..., 99,100,101, ..). Nesse caso, você não precisaria de uma CTE recursiva.
usar o seguinte comando
Como isso resolve o problema de profundidade desconhecido para algo como ... obter uma árvore de um determinado caminho do DMS como um conjunto de linhas?
Guerra