Присоединение к TVF, который создает временную таблицу, намного быстрее, чем прямое предложение.Почему это? - PullRequest
0 голосов
/ 12 октября 2018

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

Проведя небольшое исследование и исследования, мы обнаружили, что производительность была большойвыгоды от использования объединенных многострочных TVF в качестве предложений.Следующий пример может быть запущен для любой БД, предпочтительно с длинной историей обновлений объекта.Первый запрос, как мы думали, будет лучшим дизайном, но второй - гораздо лучше (обычно в 20 раз быстрее). На самом деле это была стоимость запроса, а не скорость

create function udf_ObjectsModifiedBetweenDates
(
    @DateFrom datetime,
    @Dateto datetime
)
returns @t table(object_id int primary key)
as
begin
insert into @t
(
    object_id
)
select object_id
from sys.objects 
where modify_date between @DateFrom and @Dateto
return
end

GO

declare @datefrom datetime = '2017-05-01' --Please adjust these dates to get good sample
declare @dateto datetime = '2018-08-02'

--slow
select object_id, parent_object_id, is_ms_shipped
from sys.objects
where modify_date between @datefrom and @dateto option (recompile)

--fast
select o.object_id, o.parent_object_id, o.is_ms_shipped
from sys.objects o
inner join udf_ObjectsModifiedBetweenDates(@datefrom, @dateto) ombd on o.object_id = ombd.object_id option (recompile)

Функция и запрос аналогичны тому, с которым мы работали в нашей системе, но здесь мы заменили системную таблицу напользовательская таблица.Мы пробовали то же самое на других пользовательских столах, снова получая огромную выгоду от MTVF.Планы выполнения показывают, что на TVF выполняется сканирование кластерного индекса по более быстрому запросу.Может кто-нибудь объяснить, что происходит, и если это жизнеспособный метод для повышения производительности запросов?

enter image description here

1 Ответ

0 голосов
/ 12 октября 2018

Кажется, вы неверно истолковали «Стоимость запроса (относительно пакета)» для «Стоимость запроса (сколько времени потребуется для выполнения запроса)» в плане выполнения.Стоимость запроса может очень мало зависеть от того, насколько он эффективен или быстр.

Я выполнил этот запрос (изменив даты), выполнив следующие действия:

SET STATISTICS IO ON;
SET STATISTICS TIME ON;

Для запроса, который вы пометили как «медленный» (без UDF), результат был:

The "slow" one

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 8 ms, elapsed time = 8 ms.

(19305 rows affected)
Table 'sysschobjs'. Scan count 1, logical reads 379, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 62 ms,  elapsed time = 61 ms.

А для запроса, который вы пометили «быстрый» (UDF), было получено:

The "fast" one

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 7 ms.

(19305 rows affected)
Table 'sysschobjs'. Scan count 0, logical reads 38610, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#B1BBD6DD'. Scan count 1, logical reads 34, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 266 ms,  elapsed time = 329 ms.

Как видно из этой статистики, версия без UDF была безусловно победителем.Время выполнения для не-UDF было более чем в 5 раз быстрее, однако ввод-вывод для запроса UDF был безумным (более чем в 1000 раз больше операций чтения).

При всей честности, многострочные функции табличных значенийболее чем часто убийцы производительности.Из трех типов функций (встроенное табличное значение, скалярное значение и многострочное табличное значение) они, вероятно, являются самыми медленными, тогда как встроенные намного чаще бывают быстрее.На слуху, я слышал, что скалярные функции «лучше» в SQL Server 2019, однако я не проверял себя и не видел никаких реальных доказательств;только в разговоре.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...