Вот ситуация:
У меня есть функция табличного значения с параметром datetime, чтобы, скажем, tdf (p_date),
он фильтрует около двух миллионов строк, выбирая строки с датой столбца, меньшей p_date, и вычисляет некоторые агрегированные значения для других столбцов.
Это прекрасно работает, но если p_date является пользовательской функцией скалярного значения (возвращающей конец дня в моем случае), план выполнения изменяется, и запрос выполняется с 1 до 1 минуты.
Таблица подтверждения концепции - 1K продуктов, 2M строк:
CREATE TABLE [dbo].[POC](
[Date] [datetime] NOT NULL,
[idProduct] [int] NOT NULL,
[Quantity] [int] NOT NULL
) ON [PRIMARY]
Функция встроенного табличного значения:
CREATE FUNCTION tdf (@p_date datetime)
RETURNS TABLE
AS
RETURN
(
SELECT idProduct, SUM(Quantity) AS TotalQuantity,
max(Date) as LastDate
FROM POC
WHERE (Date < @p_date)
GROUP BY idProduct
)
Функция скалярного значения:
CREATE FUNCTION [dbo].[EndOfDay] (@date datetime)
RETURNS datetime
AS
BEGIN
DECLARE @res datetime
SET @res=dateadd(second, -1,
dateadd(day, 1,
dateadd(ms, -datepart(ms, @date),
dateadd(ss, -datepart(ss, @date),
dateadd(mi,- datepart(mi,@date),
dateadd(hh, -datepart(hh, @date), @date))))))
RETURN @res
END
Запрос 1 - Отлично работает
SELECT * FROM [dbo].[tdf] (getdate())
Конец плана выполнения:
Совокупная стоимость потока 13% <--- Стоимость сканирования кластерного индекса 86% </p>
Запрос 2 - Не так здорово
SELECT * FROM [dbo].[tdf] (dbo.EndOfDay(getdate()))
Конец плана выполнения:
Совокупная стоимость потока 4% <--- Стоимость фильтра 12% <--- Стоимость сканирования кластерного индекса 86% </p>