Изменить системное значение по умолчанию для maxrecursion

12

Как изменить общесистемное значение по умолчанию MAXRECURSION?

По умолчанию это 100, но мне нужно увеличить его до 1000.

Я не могу использовать подсказки запроса, так как я использую программу, которая принимает мой запрос и выполняет его для меня, и я, к сожалению, не могу обойти это ограничение.

Тем не менее, у меня есть права администратора на экземпляре сервера. Я копался в аспектах сервера, но не вижу там ничего, связанного с параметрами запроса или рекурсией. Я предполагаю, что где-то должно быть место, где я могу обновить общесистемные настройки по умолчанию.

Есть идеи?

carl.anderson
источник
3
Я просто хотел убедиться, что вы понимаете, что ограничение в 100 было только для представлений и функций, и что вы можете использовать хранимую процедуру и переопределять там локально? Есть ли особая необходимость в использовании функции? Поскольку рекурсия довольно неэффективна, я бы также предложил обходить иерархию только один раз и сохранять результаты в таблице. Затем вы можете создать функцию, которая ссылается на эту таблицу. Как вы думаете?
wBob

Ответы:

10

Если ваши запросы имеют общую форму, вы можете добавить необходимую подсказку maxrecursion, используя одно или несколько указаний плана.

Там может быть ловкость, чтобы получить их правильно. Если вы добавите конкретные детали запроса в свой вопрос, мы сможем решить эту проблему для вас. Как правило, вы отслеживаете SQL- запрос , фактически попадающий на сервер, или получаете параметризованную форму, используя встроенную процедуру sys.sp_get_query_template , а затем создаете руководство плана TEMPLATE и / или OBJECT / SQL.

См. Документацию для получения дополнительной информации:

Руководства по планированию должны будут проходить повторную проверку всякий раз, когда изменяется код приложения, а также когда исправляется или обновляется SQL Server. Это должно быть просто частью вашего обычного цикла тестирования.

Обратите внимание, что проверка руководства плана с использованием sys.fn_validate_plan_guide может некорректно сообщать об ошибке, если инструкция направляет временную таблицу. Смотрите этот вопрос:

Проверка руководства плана с помощью fn_validate_plan_guide дает ложные срабатывания

Классы « Руководство по плану» и « Руководство по плану» Классы « Неудачный профилировщик» и «Расширенные события» также можно использовать для мониторинга приложений «Руководство по плану».

Connect был удален до того, как было реализовано предложение по улучшению продукта: допустимые предельные значения MAXRECURSION, отличные от 100, для представлений и пользовательских функций Стивом Кассом . Если вы хотите обсудить это с Microsoft сейчас, ознакомьтесь с параметрами справки и отзывами по SQL Server .

Пол Уайт 9
источник
Это расстраивает и не отвечает на вопрос, вместо этого хоронит нас в кроличьей норе документации. EF Core (типичный ORM) генерирует запросы для вас, даже если вы дадите ему необработанный SQL-оператор, который обернет его в родительский выбор, у любого, кто использует EF Core, есть эта проблема. Ваше решение - «планируйте свои запросы».
Война
@War Это лучший ответ, который я могу дать на этот конкретный вопрос с подробной информацией. Единственный известный мне способ добавления подсказки о максимальной рекурсии - через SQL Server, называемый «Руководство по планированию», который не имеет ничего общего с «планированием ваших запросов». Если у вас есть конкретный вопрос, задайте его отдельно с минимальным воспроизводимым примером .
Пол Уайт 9
9

Если вам абсолютно необходимо использовать функцию (как вы подразумеваете, это ограничение вашего ETL-инструмента), вы можете указать ее OPTIONкак часть табличной функции с несколькими утверждениями, например что-то вроде этого:

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

Это также сработало для меня, когда обернулось в представление, как вы предлагаете ваши инструменты ETL. Нет никакого способа изменить это в масштабе всей системы, но поскольку рекурсия может быть неэффективной, это, вероятно, хорошая вещь. Вы не можете указать подсказку запроса (используя OPTION) в теле встроенной табличной функции, как в вашем примере.

Подумайте о том, чтобы изменить свой процесс, чтобы обходить иерархию только один раз, когда вы получаете свои эпизоды и сохраняете выходные данные в реляционной таблице. Вы можете использовать хранимый процесс, чтобы не делать этого ограничения.

Я также думаю, что в вашем коде может быть ошибка: если ваш CTE включается в personId и рекурсивно в eventId, eventId 101 будет представлен дважды, я думаю, как дубликат. Возможно, я неправильно истолковал ваш код, дайте мне знать, что вы думаете.

НТН

wBob
источник
это не работает, так как параметр «OPTIONS» должен применяться на уровне оператора, а рассматриваемый оператор является вызовом функции, это возвратит исключение.
Война
0

Я черпал вдохновение из этой темы .

Вот что я сделал, чтобы решить проблему.

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

Затем я вызываю эту функцию следующим образом:

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

Таким образом, ни одна из моих логик CTE не должна повторяться, и я ничего не плачу с точки зрения производительности. Это неприятно, что это должно быть сделано таким образом, но я могу жить с этим.

carl.anderson
источник
3
Я не понимаю, как это решает проблему рекурсии. Вызов функции не является рекурсивным.
ypercubeᵀᴹ
@ ypercubeᵀᴹ - рекурсивный бит CTE идет туда, где у меня есть многоточие - моя конкретная рекурсивная логика на самом деле не имеет отношения к проблеме, но вы можете предположить, что CTE на самом деле рекурсивный. Предложение whereпосле многоточия предотвращает слишком много рекурсий, используя параметр функции в качестве ограничения. Я думаю, что после определения CTE должно быть заявление . Я добавлю это.
carl.anderson
3
Я очень хорошо понимаю, что CTE является рекурсивным. Проблема в том, что вызов (вызов функции) не является рекурсивным . Например, вы вызываете функции с начальными точками (строками) с помощью EventID=1(и 101,201, ... 901). Но исходный запрос (если он выполняется с MAXRECURSION = 100000000) может никогда не посетить строку с EventID=101(и 201, .., 901). Таким образом, два запроса (исходный и ваше решение) могут возвращать разные результаты (нет строки с 101 в первом, да во 2)! Или он может посетить 101, но до шага 100, поэтому ваше решение будет включать строку в результаты дважды (опять же иначе)
ypercubeᵀᴹ
2
Если, конечно, данные не связаны через последовательные значения EventID (1,2, 3 ..., 99,100,101, ..). В этом случае вам вообще не понадобится рекурсивный CTE.
ypercubeᵀᴹ
Как это решает неизвестную проблему глубины для чего-то вроде ... получения дерева по заданному пути DMS в качестве набора строк?
Война