首页 > 解决方案 > SQL 性能:MSSQL 是否优化了日期时间函数的使用,还是将其作为参数传递更好

问题描述

我编写了这个相当简单的查询,在该查询中,我根据名为 LastActivity 的 DateTimeOffset 列选择了不到 5 分钟的记录。

我正在使用 EF,在检查实际查询时,我看到 EF 实际上将此条件转换 LastActivity > DateTimeOffset.UtcNow.AddMinutes(-5);为使用 SQL 日期时间函数的查询:[s].[LastActivity] > DATEADD(minute, CAST(-5.0E0 AS int), CAST(SYSUTCDATETIME() AS datetimeoffset)).

如您所见,它进行了一些不必要的强制转换(例如 .AddMinutes 需要双精度),所以我想知道首先在代码中实际计算 DateTime 然后将结果作为参数传递给查询是否会更高效。我知道这将取决于统计数据,我还不能真正说出这些值将如何分布......我已经在示例数据库上运行了两个查询,性能没有真正的差异,但是当数据集增加时我认为这可能会改变。

我的问题是:我是否正确假设当没有参数时(但使用 DATEADD),SQL 将始终使用相同的查询计划,或者它会以某种方式优化它,因为我们使用的是 SYSUTCDATETIME?

标签: sql-serverentity-frameworkdatetimeentity-framework-corequery-optimization

解决方案


EF 为该查询提供的内容可以正常工作,即使它的语法有点出人意料。

为什么?

  1. WHERE timestampcolumn > DATEADD(minute, number, something_meaning_now)是一个sargeable过滤术语:它可以在timestampcolumn.
  2. SYSUTCDATETIME()是一个非确定性函数。这意味着 SQL Server 知道它的返回值是基于它的输入值之外的东西。

所以,这就是正在发生的事情:SQL Server 在使用它之前“在代码中”计算日期,就像您在代码中所做的那样。因为 SQL Server 知道每次使用查询时计算的日期都会改变(因为它是不确定的),所以它的缓存执行计划不会将该日期绑定到一个常量,因此查询缓存不会膨胀。如果您的过滤器是timestampcolumn < DATEADD(minute, number, '2021-01-23 12:34').

我已经在大规模生产中完成了这种事情的吨位并且它工作正常。

你问的是扩大规模。这样做的方法是在您的s.LastActivity列上放置一个索引。但是,要弄清楚你需要什么索引......

  1. 使用 SSMS
  2. 选择显示实际查询计划。
  3. 运行查询
  4. 查看查询计划。如果您需要,它将显示推荐的索引。

推荐阅读