CROSS APPLY Стиль против производительности
Должен ли я использовать отдельный CROSS APPLY для каждого псевдонима или определить несколько выражений в одном CROSS APPLY, где это возможно?
Я рефакторинг многих очень сложных запросов SQL (часто четыре или пять страниц с дюжиной JOIN), которые генерируются в коде. Часто они вложены в пять или шесть запросов, так как некоторые части используются повторно в разных ситуациях. Типичная причина вложения запросов заключается в том, что один запрос извлекает некоторые значения, выполняет вычисления и присваивает псевдоним этому значению. Затем включающий запрос выполняет дальнейшие вычисления с использованием значения с псевдонимом и т. Д. Это необходимо, поскольку на выражение с псевдонимом можно ссылаться только во внешнем запросе, а не в другом месте в запросе, который его определяет. (Альтернатива, которая также присутствует в коде, состоит в том, чтобы повторять одно и то же длинное подвыражение дюжину раз по всему запросу.)
Чтобы упростить этот спагетти-SQL, я начал сворачивать эти телескопические запросы, используя CROSS APPLY. Используя CROSS APPLY, я могу назначить псевдоним и использовать его в другом месте того же запроса. Обратите внимание, что ни одно из моих предложений CROSS APPLY не вводит новые таблицы с помощью подвыборов или вызовов UDF.
Сначала я поместил много выражений в один и тот же CROSS APPLY. Тем не менее, мой код должен быть модульным. В разных ситуациях потребуются разные поля, так как пользователи могут выбирать поля для фильтров, и мы генерируем аналогичную статистику для разных столбцов, поэтому создаем много похожих запросов, которые лишь немного отличаются друг от друга. Поскольку некоторые поля основаны на других, а некоторые зависят от определенных JOIN, определенных ранее в запросе, я не могу поместить все в один и тот же CROSS APPLY. Следовательно, количество CROSS APPLY может варьироваться.
Кроме того, некоторые поля, извлеченные из, затеняются новыми псевдонимами и переопределяются (как правило, для удаления значений NULL, значений по умолчанию и т. Д.). Таким образом, когда на определенное поле CROSS APPLY ссылаются в другом месте, псевдоним таблицы CROSS APPLY необходимо будет указать для убрать двусмысленность
В результате мне нужен логичный способ назвать мои CROSS APPLY, и я забочусь о производительности. Если количество ПРИЛОЖЕНИЙ CROSS изменяется, то, если ПРИЛОЖЕНИЯ CROSS нумеруются простым счетчиком (например, computed1, computed2 и т. Д.), То данное поле может видеть изменение ссылки на его имя с computed3. [ИМЯ ПОЛЯ] на computed4.[FIELD NAME], которая имеет волновой эффект в остальной части запроса, который может быть собран при вызовах различных процедур C#. Это проблема обслуживания.
Альтернатива, которую я рассматриваю, состоит в том, чтобы поместить каждое вычисленное выражение в отдельный CROSS APPLY, а имя CROSS APPLY будет получено из псевдонима для выражения. Например:
Используя один CROSS APPLY:
CROSS APPLY (
SELECT
[TIV_BLDG] = (CASE [COVERAGE] WHEN 'TIV_BLDG' THEN VALUEAMT ELSE 0 END)
, [TIV_OSTR] = (CASE [COVERAGE] WHEN 'TIV_OSTR' THEN VALUEAMT ELSE 0 END)
, [TIV_CONT] = (CASE [COVERAGE] WHEN 'TIV_CONT' THEN VALUEAMT ELSE 0 END)
, [TIV_TIME] = (CASE [COVERAGE] WHEN 'TIV_TIME' THEN VALUEAMT ELSE 0 END)
) computed2
Используя четыре CROSS APPLYs:
CROSS APPLY (SELECT [TIV_BLDG] = (CASE [COVERAGE] WHEN 'TIV_BLDG' THEN VALUEAMT ELSE 0 END)) AS [TIV_BLDG_COMP]
CROSS APPLY (SELECT [TIV_OSTR] = (CASE [COVERAGE] WHEN 'TIV_OSTR' THEN VALUEAMT ELSE 0 END)) AS [TIV_OSTR_COMP]
CROSS APPLY (SELECT [TIV_CONT] = (CASE [COVERAGE] WHEN 'TIV_CONT' THEN VALUEAMT ELSE 0 END)) AS [TIV_CONT_COMP]
CROSS APPLY (SELECT [TIV_TIME] = (CASE [COVERAGE] WHEN 'TIV_TIME' THEN VALUEAMT ELSE 0 END)) AS [TIV_TIME_COMP]
Если я использую этот подход с несколькими CROSS APPLY, я могу легко сгенерировать имена, которые не изменятся, если я добавлю новые применяет или удалит их, и я могу предсказать в коде, который ссылается на поля, какой будет псевдоним таблицы. Тем не менее, это означает, что гораздо больше утверждений CROSS APPLY. Каковы последствия производительности? Есть ли лучший способ сделать это, используя CROSS APPLY или какую-либо другую функцию SQL Server? (Мне не нужно, чтобы это было кросс-базой данных, поэтому функции только для Microsoft в порядке.)
1 ответ
Если есть недостаток в производительности, он должен быть на стадии компиляции выполнения запроса. Поскольку планы выполнения кэшируются в секунду, когда выполняется запрос времени, производительности не будет.
SQL Server может видеть через CROSS APPLY и преобразовывать их в простые, сложенные "вычислительные скаляры".
Другой потенциальной проблемой может быть размер запроса. Не уверен, есть ли какие-либо уместные ограничения с точки зрения количества AST-узлов или объединений или около того (я предполагаю, что CROSS APPLY считается соединением, когда дело доходит до внутренних ограничений).
Помимо этих проблем, я думаю, что CROSS APPLYs - очень хорошее и быстрое решение.