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需要一个double),所以我想知道在代码中首先实际计算DateTime,然后将结果作为参数传递给查询是否更具性能。我知道这将取决于统计数据,我还不能说这些值将如何分布。。。我在一个示例数据库上运行了这两个查询,在性能上没有真正的差异,但当数据集增加时,我认为这可能会改变。

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

EF为该查询提供的内容将很好地工作,即使它有点意外的语法。

为什么?

  1. WHERE timestampcolumn > DATEADD(minute, number, something_meaning_now)是一个可搜索的过滤项:它可以使用timestampcolumn上的索引
  2. CCD_ 5是一个非确定性函数。这意味着SQL Server知道它的返回值是基于它的输入值之外的一些东西

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

我在大规模生产中做过这种吨位的事情,而且效果很好。

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

  1. 使用SSMS
  2. 选择"显示实际查询计划">
  3. 运行查询
  4. 查看查询计划。如果你需要的话,它会显示一个推荐的索引

最新更新