Змініть системний стандарт за замовчуванням для макскурсії


12

Як змінити загальносистемне значення за замовчуванням MAXRECURSION?

За замовчуванням це 100, але мені потрібно збільшити його на щось на зразок 1000.

Я не можу використовувати підказки щодо запитів, оскільки я використовую програму, яка приймає мій запит і виконує його для мене, і я, на жаль, не можу обійти це обмеження.

Однак у мене є права адміністратора на екземплярі сервера. Я ткнув навколо граней сервера, але я не бачу нічого, що стосується параметрів запиту чи рекурсії. Я припускаю, що десь має бути місце, де я можу оновити системний дефолт.

Будь-які ідеї?


3
Я просто хотів перевірити, чи ти розумієш, що обмеження 100 є лише на представленнях та функціях, і що ти можеш використовувати збережену процедуру та переобирати локально там? Чи є якась особлива потреба у використанні функції? Оскільки рекурсія є досить неефективною, я б також запропонував пройти по ієрархії лише один раз і зберігати результати в таблиці. Потім можна створити функцію, яка посилалась на цю таблицю. Як ти гадаєш?
wBob

Відповіді:


10

Якщо ваші запити мають загальну форму, ви, можливо, зможете додати необхідний підказку щодо максимальної рекурсії за допомогою одного або декількох настанов плану.

Тут може бути хитрість, щоб їх правильно виправити. Якщо ви додасте конкретні деталі запиту до свого запитання, ми можемо це вирішити для вас. Як правило, ви могли б простежити, як SQL фактично потрапляє на сервер, або отримати параметризовану форму, використовуючи вбудовану процедуру sys.sp_get_query_template , а потім створити посібник з плану TEMPLATE та / або OBJECT / SQL.

Для отримання додаткової інформації дивіться документацію:

Посібники плану потрібно буде повторно перевірити, коли змінюється код програми та коли патч або оновлення SQL Server буде оновлено. Це просто має бути частиною вашого нормального циклу тестування.

Зауважте, що перевірка керівництва плану за допомогою sys.fn_validate_plan_guide може неправильно повідомити про помилку, якщо керований оператор посилається на тимчасову таблицю. Дивіться це запитання:

Перевірка керівництва плану за допомогою fn_validate_plan_guide дає помилкові позитиви

У Керівництві плану Успішне і Невдалий план Керівництво Profiler і розширені події класи також може бути використані для моніторингу плану напрямних додатків.

Connect було вимкнено, перш ніж було запропоновано пропозиції щодо вдосконалення продукту Дозволити максимальні значення MAXRECURSION, окрім 100 для переглядів та UDF, Стіва Касса . Якщо ви хочете взяти це з Microsoft зараз, перегляньте параметри довідки та відгуки на SQL Server .


Це засмучує і не дає відповіді на запитання, замість того, щоб поховати нас у кролячій лунці документації. 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 відображатиметься двічі, я думаю, як дублікат. Можливо, я неправильно трактував ваш код, дайте мені знати, що ви думаєте.

HTH


це не працює, оскільки параметр "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 не повинна повторюватися, і я не плачу нічого додаткового з точки зору продуктивності. Прикро, що це потрібно зробити так, але я можу з цим жити.


3
Я не бачу, як це вирішує проблему рекурсії. Викликання функції не є рекурсивним.
ypercubeᵀᴹ

@ ypercubeᵀᴹ - рекурсивний біт CTE йде там, де я маю еліпсис - моя особлива рекурсивна логіка насправді не стосується проблеми, але можна припустити, що CTE насправді є рекурсивним. whereТурнірне становище після крапки запобігає занадто багато рекурсії відбувалася за допомогою параметра функції в якості обмеження. Я думаю, що після визначення CTE має бути заява . Я додам це.
carl.anderson

3
Я дуже добре розумію, що CTE є рекурсивним. Проблема полягає в тому, що виклик (виклики функції) не є рекурсивним . Наприклад, ви викликаєте функції з початкових точок (рядків) за допомогою EventID=1(і 101,201, ... 901). Але оригінальний запит (якщо він виконується з MAXRECURSION = 100000000) може ніколи не відвідувати рядок з EventID=101(і 201, .., 901). Тож два запити (оригінал та ваше рішення) можуть повертати різні результати (жоден рядок із 101 у першому, так у другому)! Або він може відвідати 101, але перед кроком 100, тож ваше рішення включить рядок двічі в результати (знову ж таки різні)
ypercubeᵀᴹ

2
Якщо, звичайно, дані не підключені через послідовні значення EventID (1,2,, 3 ..., 99,100,101, ..). У такому випадку вам взагалі не знадобиться рекурсивний CTE.
ypercubeᵀᴹ

Як це вирішує невідому проблему глибини на щось на зразок ... отримання дерева із заданого шляху DMS у вигляді набору рядків?
Війна
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.