Производительность SELECT * во встроенной табличной функции - PullRequest
0 голосов
/ 01 марта 2019

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


uf_GetCustomersByCity_A

В этом примере я создаю ITVF, который выполняет SELECT *,возвращение отфильтрованного CustomerView.

CREATE FUNCTION [dbo].[uf_GetCustomersByCity_A] (@idCity INT)
RETURNS TABLE
AS RETURN

    SELECT CustView.*
      FROM [dbo].[CustomerView] CustView
     WHERE CustView.idCity = @idCity

GO

uf_GetCustomersByCity_B

CREATE FUNCTION [dbo].[uf_GetCustomersByCity_B] (@idCity INT)
RETURNS TABLE
AS RETURN

    SELECT CustView.idCustomer
         , CustView.cFullName
         , CustView.cCityName
         , CustView.fBalance
      FROM [dbo].[CustomerView] CustView
     WHERE CustView.idCity = @idCity

GO

Мой вопрос заключается в том, является ли это действительным наблюдением, или это просто сторонаэффект отладки в течение многих часов (при условии, что SQL Server оптимизируется с использованием).Было очень полезно предлагать в представлении все, что нужно, вместо указания каждого столбца специально в ITVF.

Любительские тесты

Так что оба работают довольно хорошо, с выходом ~500 000 строк в течение 4-5 секунд (примечание: существуют сложные предложения, дающие долгое время выполнения, и эти примеры вряд ли иллюстрируют цель здесь).В представлении есть что-то вроде 70 или 80 столбцов, многие из которых отформатированы или обрабатываются внутри строки.

-- Around 500k rows in ~3-4 seconds:

SELECT idCustomer, cCityName
FROM [dbo].[uf_GetCustomersByCity_A](93)

-- Around 500k rows, again ~3-4 seconds:

SELECT idCustomer, cCityName
FROM [dbo].[uf_GetCustomersByCity_B](93)

Такая же производительность в блоке разработчика, но в настоящее время его никто не использует.Предположим, что cFullName - это объединение cGivenName и cFamilyName, тогда как cCityName возвращается в точности как сохранено.Добавление cCityName к запросу имеет значительно меньшее влияние, чем cFullName, что заставляет меня поверить, что это не время доставки в SSMS, которое я замечаю.

-- Around 500k rows, ~6 seconds:

SELECT idCustomer, cFullName
FROM [dbo].[uf_GetCustomersByCity_A](93)

-- Around 500k rows, ~6 seconds:

SELECT idCustomer, cFullName
FROM [dbo].[uf_GetCustomersByCity_B](93)

Я думаю, что если SELECT * имеет значение в рамках ITVF, тогда он будет тратить кучу времени на определение значений для столбцов, которые он не использует.Из быстрых тестов, которые я разработал, я не вижу особой разницы, когда оборачиваю весь вид с помощью SELECT *, вместо того, чтобы указывать столбцы по одному, восстанавливая структуру представления по существу.Моя догадка действительна здесь?

1 Ответ

0 голосов
/ 01 марта 2019

i in iTVF - для inlined - как вы знаете.Это означает, что движок будет пытаться найти лучший план выполнения , как если бы оператор был записан в запрос непосредственно .

С этой точки зрения не должно быть никакой разницы, используете ли вы

SELECT * FROM YourView WHERE idCity=@idCity

или

SELECT * FROM YourITVF(@idCity)

Движок должен быть достаточно умным, чтобы обрабатывать только необходимые столбцы, но - в целом - лучше использовать список исправленийколонн.(См. Ссылку в комментарии @ a_horse_with_no_name.)

Подсказка : Когда вы оборачиваете представление (как вам нужно) с помощью SELECT * FROM ..., вы должны помнить, что вам нужно перекомпилироватьэто iTVF, если вы измените свое мнение.

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

Если ваше представление было построено на вложенных представлениях, а эти вложенные представления были построены из вложенных вложенных представлений, других iTVF и т. д., это приведет к переходу на вспомогательное представление.-оптимальные планы.

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

Короче говоря:

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