情况如下:
我有一个带有 datetime 参数的表值函数,例如 tdf(p_date),它过滤大约 200 万行,选择列 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())
执行计划结束:Stream Aggregate Cost 13% <--- Clustered Index Scan Cost 86%
查询 2 - 不太好
SELECT * FROM [dbo].[tdf] (dbo.EndOfDay(getdate()))
执行计划结束:Stream Aggregate Cost 4% <--- Filter Cost 12% <--- Clustered Index Scan Cost 86%