Является ли поддержка Parallel Scalar UDF разумным запросом функции?

10

Достаточно хорошо задокументировано, что скалярные UDF создают общий последовательный план.

Запуск функций параллельно

Учитывая большое количество строк, приходящих в точку в конвейере, где нужно вычислить UDF, почему движок не может просто распределить их между процессорами? Если в UDF нет состояния, порядок не должен иметь значения.

Есть заявления о том, что UDF является черным ящиком, в котором должен использоваться курсор. Я вижу, что пользовательский курсор нельзя распараллелить в SP для случаев, когда между итерациями поддерживается какое-то состояние, но кажется, что в противном случае оно должно быть распараллелено.

Дополнительные баллы за объяснение того, почему двигатель заставляет весь план быть последовательным, а не только этап расчета UDF.

Является ли поддержка параллельной UDF разумной функцией для запроса?

crokusek
источник
1
Соответствующая реакция, как отмечается в принятом ответе на вашу ссылку, переписывает любые скалярные пользовательские функции в виде одноколоночных встроенных табличных функций . Они расширяются так же, как представление, и, таким образом, полностью оптимизируются. В этом свете ваш вопрос все еще заслуживает внимания?
Питер Гиркенс
1
Да на успех с обходным путем TVF. Я спросил, потому что кажется неправильным избегать использования такой естественной конструкции. Также кажется нецелесообразным ожидать, что новые разработчики SQL будут изучать внутреннюю структуру UDF.
crokusek
Уточняющий комментарий. Успех с ITVF, но не с мульти-оператором TVF.
crokusek

Ответы:

17

Достаточно хорошо задокументировано, что UDF определяют общий последовательный план.

Я не уверен, что все это хорошо задокументировано.

  • Скалярная функция T-SQL предотвращает параллелизм в любом месте плана.
  • Скалярная функция CLR может выполняться параллельно, если она не имеет доступа к базе данных.
  • Табличнозначная функция T-SQL с несколькими утверждениями вынуждает последовательную зону в плане, которая может использовать параллелизм в другом месте.
  • Встроенная табличная функция T-SQL расширяется как представление, поэтому не имеет прямого эффекта.

См. Форсирование плана параллельного выполнения и / или презентацию Крейга Фридмана о параллельном выполнении .

Есть заявления о том, что UDF должны быть в черном ящике с курсором.

Эти претензии не верны.

Дополнительные баллы за объяснение того, почему двигатель заставляет весь план быть последовательным, а не только этап расчета UDF.

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

В частности, скалярные функции T-SQL выполняются в отдельном контексте T-SQL, что значительно усложняет правильную работу, координацию и завершение работы (особенно в случае ошибки).

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

Является ли поддержка параллельной UDF разумной функцией для запроса?

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


Вы можете прочитать статью Microsoft:

... который описывает подход, который Microsoft использует для решения проблем производительности скалярных функций T-SQL в выпуске после SQL Server 2017.

Цель Froid - дать разработчикам возможность использовать абстракции пользовательских функций и процедур без ущерба для производительности. Фройд достигает этой цели, используя новую технику для автоматического преобразования императивных программ в эквивалентные алгебраические формы отношений, когда это возможно. Froid моделирует блоки императивного кода как реляционные выражения и систематически объединяет их в одно выражение с помощью оператора Apply, что позволяет оптимизатору запросов выбирать эффективные ориентированные на множество параллельные планы запросов.

(акцент мой)


Встроенные скалярные функции T-SQL теперь реализованы в SQL Server 2019 .

Пол Уайт 9
источник
11

Как справедливо упомянул Пол в своем ответе, нет фундаментальной причины, по которой скалярные UDF не могут быть выполнены с использованием параллелизма. Однако, помимо проблем с реализацией, есть еще одна причина, заставляющая их быть последовательными. Froid цитируемой Павел дает больше информации об этом.

Цитата из статьи (раздел 2.3):

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

Например, рассмотрим пользовательскую функцию, которая вызывает другие SQL-запросы, такие как те, что показаны на рисунке 1. Каждый такой запрос сам может использовать параллелизм, и поэтому оптимизатор не может знать, как разделить потоки между ними, если только он не изучит UDF и определяет степень параллелизма для каждого запроса внутри (который потенциально может измениться от одного вызова к другому). С помощью вложенных и рекурсивных пользовательских функций эта проблема становится еще более сложной для решения.

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

Обновление: Froid теперь доступен как функция предварительного просмотра SQL Server 2019. Эта функция называется «Скалярная подкладка UDF». Более подробная информация здесь: https://blogs.msdn.microsoft.com/sqlserverstorageengine/2018/11/07/introduction-scalar-udf-inlining/

[Раскрытие: я соавтор статьи Froid]

Картик
источник
Очень хорошо! Если я правильно понимаю, он собирается автоматически автоматически преобразовать UDF в ITVF. Мы сделали это для нескольких (w / Declares / If / else) и сделали хороший беспорядок. У нас даже была отладочная «колонка».
crokusek
1
На самом деле он не превращает UDF в ITVF, но ваша интуиция верна. Делать это вручную на уровне SQL-запросов действительно сложно для сложных пользовательских функций. Фройд делает это преобразование на дереве реляционной алгебры, что позволяет избежать беспорядка :)
Karthik
@Karthik, не могли бы вы взглянуть на dba.stackexchange.com/questions/202211/… . Мне бы очень хотелось узнать, как Froid будет работать в описанном случае
Роман Пекар
@Romman Я прокомментировал твой вопрос.
Картик
1
Спасибо, @Karthik, за работу, которую вы проделали над документом Froid, и за ваши (и группы) усилия по улучшению юзабилити скалярных UDF :-)
Соломон Руцки