我编写了这个相当简单的查询,其中根据名为 LastActivity 的 DateTimeOffset 列选择不到 5 分钟的记录。
我正在使用 EF,在检查实际查询时,我发现 EF 实际上转换了此条件:
LastActivity > DateTimeOffset.UtcNow.AddMinutes(-5);
使用 SQL 日期时间函数进行查询:[s].[LastActivity] > DATEADD(min, CAST(-5.0E0 AS int) ), CAST(SYSUTCDATETIME() AS datetimeoffset))
。
我的问题是:当没有参数(但使用 DATEADD)时,SQL 将始终使用相同的查询计划,或者它会以某种方式优化它,因为我们使用的是 SYSUTCDATETIME,我的假设是否正确?
最佳答案
EF 为该查询提供的内容将正常工作,即使它的语法有点意外。
为什么?
-
WHERE timestampcolumn > DATEADD(minute, number, something_meaning_now)
是 sargeable过滤项:它可以使用timestampcolumn
上的索引. -
SYSUTCDATETIME()
是一个非确定性函数。这意味着 SQL Server 知道它的返回值基于除输入值之外的其他值。
所以,发生的事情是这样的:SQL Server 在使用日期之前“在代码中”计算日期,就像您在代码中所做的那样。因为 SQL Server 知道每次使用查询时计算的日期都会改变(因为它是不确定的),所以它的缓存执行计划不会将该日期绑定(bind)到常量,因此查询缓存不会膨胀。如果您的过滤器是timestampcolumn < DATEADD(minute, number, '2021-01-23 12:34')
,它将被绑定(bind).
我已经在大规模生产中做过大量此类事情,并且工作正常。
您询问了有关扩大规模的问题。做到这一点的方法是将索引放在您的 s.LastActivity
上。柱子。但是,要弄清楚您需要哪些索引......
- 使用 SSMS
- 选择“显示实际查询计划”。
- 运行查询
- 查看查询计划。如果您需要的话,它会显示推荐的索引。
关于sql-server - SQL性能: does MSSQL optimise the use of date time functions or is it better to pass it as a parameter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66330408/