Yar*_*lav 5 optimization t-sql sql-server-2008-r2
我正在尝试优化几个在其中一个WHERE
子句上都使用类似模式的查询:
AND (DATEADD(DAY
, ISNULL(a.[due_days], 30) + 30
, [dbo].[CalcDate]([type], date1, date2, date3, date4, NULL))
) < GETDATE()
Run Code Online (Sandbox Code Playgroud)
CalcDate
基于type
字段值的udf进行一些比较并返回一个日期。然后将天数添加到该日期并与当前日期进行比较。为了能够使用现有的索引,due_days
我想转换操作以将所有转换应用到GETDATE()
,假设我想sargable
在可能的情况下实现它。另外,如果有一些关于可以做些什么来更好地改进 udf 的使用的建议。
ype*_*eᵀᴹ 11
进行这种转变并不难。一步步:
DATEADD(DAY
, ISNULL(a.[due_days], 30) + 30
, [dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
) < GETDATE()
Run Code Online (Sandbox Code Playgroud)
方法:
[dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
+ (ISNULL(a.[due_days], 30) + 30) DAYS
< GETDATE()
Run Code Online (Sandbox Code Playgroud)
那么我们必须将其ISNULL()
分为两种情况:
[dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
+ (a.[due_days] + 30) DAYS
< GETDATE()
OR
a.[due_days] IS NULL
AND
[dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
+ (30 + 30) DAYS
< GETDATE()
Run Code Online (Sandbox Code Playgroud)
可以写成:
(a.[due_days] + 30) DAYS
< GETDATE() - [dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
OR
a.[due_days] IS NULL
AND
(30 + 30) DAYS
< GETDATE() - [dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
Run Code Online (Sandbox Code Playgroud)
所以我们可以使用DATEDIFF()
:
(a.[due_days] + 30)
< DATEDIFF( day
, [dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
, GETDATE()
)
OR
a.[due_days] IS NULL
AND
(30 + 30)
< DATEDIFF( day
, [dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
, GETDATE()
)
Run Code Online (Sandbox Code Playgroud)
最后:
a.[due_days]
< DATEDIFF( day
, [dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
, GETDATE()
) - 30
OR
a.[due_days] IS NULL
AND
30
< DATEDIFF( day
, [dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
, GETDATE()
) - 30
Run Code Online (Sandbox Code Playgroud)
更正,注意时间部分:
a.[due_days]
< DATEDIFF( day
, [dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
, GETDATE()
) - 30
- CASE WHEN DATEADD( day
, DATEDIFF( day
, [dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
, GETDATE()
)
, [dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
) > GETDATE()
THEN 1 ELSE 0
END
OR
a.[due_days] IS NULL
AND
30
< DATEDIFF( day
, [dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
, GETDATE()
) - 30
- CASE WHEN DATEADD( day
, DATEDIFF( day
, [dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
, GETDATE()
)
, [dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
) > GETDATE()
THEN 1 ELSE 0
END
Run Code Online (Sandbox Code Playgroud)
您可以使用以下方法简化它CROSS APPLY
:
CROSS APPLY
( SELECT gdt = GETDATE(),
calc = [dbo].[CalcDate]([type], date1, date2, date3, date4, NULL)
) AS c
CROSS APPLY
( SELECT diff = x.diff - CASE WHEN DATEADD( day, x.diff, c.calc ) > c.gdt
THEN 1 ELSE 0
END
FROM
( SELECT diff = DATEDIFF( day, c.calc, c.gdt) - 30
) AS x
) AS y
----
WHERE ( a.[due_days] < y.diff
OR a.[due_days] IS NULL AND 30 < y.diff
)
Run Code Online (Sandbox Code Playgroud)