Чи є спосіб запобігти скалярним АДС в обчислюваних колонках не гальмувати паралелізм?


29

Багато було написано про небезпеку скалярних UDF в SQL Server. Випадковий пошук призведе до повернення результатів.

Однак є місця, де скалярний АДС - єдиний варіант.

Як приклад: при роботі з XML: XQuery не може використовуватися як обчислене визначення стовпця. Один із варіантів, задокументований Microsoft, - використовувати Scalar UDF, щоб інкапсулювати XQuery у скалярний UDF, а потім використовувати його в обчисленому стовпчику.

Це має різні наслідки та деякі обходи.

  • Виконує рядок за рядком, коли таблиця запитується
  • Примушує всі запити до таблиці виконуватись послідовно

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

Чи відомий спосіб це зробити?

Відповіді:


31

Так, якщо ви:

  • запущений SQL Server 2014 або новішої версії; і
  • вміють запускати запит із прапором 176 активності; і
  • обчислена колонка PERSISTED

В Зокрема, за Принаймні , такі версії потрібні :

  • Сукупне оновлення 2 для SQL Server 2016 SP1
  • Сукупне оновлення 4 для RTM SQL Server 2016
  • Сукупне оновлення 6 для SQL Server 2014 SP2

АЛЕ, щоб уникнути помилок (посилання на 2014 та 2016 та 2017 роки ), введені в цих виправленнях, замість цього застосуйте:

Прапор трасування є ефективним як –Tваріант запуску , як у глобальному, так і в межах сеансу DBCC TRACEON, а також за запитом OPTION (QUERYTRACEON)або керівництвом плану.

Прапор трасування 176 запобігає збереженню обчисленого розширення стовпців.

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

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

Прапор трасування 176 допомагає в цьому, якщо стовпець зберігається, не завантажуючи визначення (оскільки розширення пропускається). Таким чином, скалярна визначена користувачем функція ніколи не присутня в дереві запитів компіляції, тому паралелізм не вимикається.

Основним недоліком прапора 176 сліду (окрім того, що він є лише злегка задокументованим), є те, що він також запобігає відповідності вираження запиту до збережених обчислюваних стовпців: Якщо запит містить вираз, що відповідає персистуючому обчислюваному стовпцю, прапор 176 сліду запобігає заміні виразу на посилання на обчислену колонку.

Докладніші відомості див. У моїй статті SQLPerformance.com " Правильно збережені обчислювані стовпці" .

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


10

Окрім відмінного Так №1 @ Павла , насправді є Так №2, який:

  • працює так само, як і SQL Server 2005,
  • не вимагає встановлення прапора сліду,
  • зовсім НЕ вимагає, щоб обчислюваний стовпець бути PERSISTED, і
  • (через те, що не потрібно прапор трас 176), не перешкоджає збігу вираження запиту до збережених обчислених стовпців

Єдині недоліки (наскільки я можу сказати):

  • не працює на базі даних SQL Azure (принаймні, поки що, хоча це працює на Amazon RDS SQL Server, а також на SQL Server в Linux), і
  • знаходиться трохи поза зоною комфорту багатьох DBA

І цей варіант такий: SQLCLR

Це вірно. Один класний аспект скалярних UDF SQLCLR полягає в тому, що якщо вони не роблять жодного доступу до даних (ні користувачеві, ні системі), вони не забороняють паралелізм. І це не лише теорія чи маркетинг. Поки я не маю часу (на даний момент) зробити повністю детальне оформлення, я перевірив і довів це.

Я скористався початковою установкою з наступного допису в блозі (сподіваємось, ОП не вважає це ненадійним джерелом 🙃):

Джинси поганої ідеї: кілька підказок

І виконували наступні тести:

  1. Позначає початковий запит так, як це ─⇾ Паралелізм (як очікувалося)
  2. Додано непостійний обчислений стовпець, визначений як ([c2] * [c3])─⇾ Паралелізм (як очікувалося)
  3. Вилучив цей обчислений стовпчик і додав непостійний обчислюваний стовпець, на який посилається скалярний UDF T-SQL (створений з SCHEMABINDING), визначений як RETURN (@First * @Second);─⇾ НЕ Паралелізм (як очікувалося)
  4. Вилучено обчислений стовпчик T-SQL UDF та додано неперсинований обчислюваний стовпчик, на який посилається скалярний UDF SQLCLR (спробував і те, IsDeterministic = trueі інше = false), визначений як return SqlInt32.Multiply(First, Second);─⇾ Паралелізм (woo hoo !!)

Отже, хоча SQLCLR працює не для всіх, він, безумовно, має свої переваги для тих людей / ситуацій / середовищ, які добре підходять. І, як це стосується цього конкретного питання - прикладу, що стосується використання XQuery - це певна робота для цього (і, залежно від того, що конкретно робиться, це може бути навіть трохи швидше 😎).

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