【问题标题】:SQL query Performance when using Datetime in where / On clause在 where / On 子句中使用 Datetime 时的 SQL 查询性能
【发布时间】:2016-08-03 14:55:44
【问题描述】:

我在表中有 5l 记录。需要查询...哪个是查询快,输入参数@RegistrationFrom DATE,@RegistrationTo DATE

方法一:

WHERE 
    CAST(Act.RegistrationOn AS DATE) BETWEEN CAST(@RegistrationFrom AS DATE) 
                                         AND CAST(@RegistrationTo AS DATE)

方法 #2 - 转换为日期时间:

DECLARE @From DATETIME, @Todate DATETIME;

SELECT @From = @RegistrationFrom;
SELECT @Todate = DATEADD(day, 1, @RegistrationTo);

WHERE 
    Act.RegistrationOn BETWEEN @From AND @Todate

方法#3:

在@From 和 @Todate 之间转换(VARCHAR,Act.RegistrationOn,101)

我得到比上面 1,2 更快的响应方法 3。 它是如何工作的?

【问题讨论】:

  • 你为什么不测试它?这是确定您的配置的唯一方法
  • 你为什么要casting as date方法1?
  • 我们从 UI 中传递 from & To date 作为过滤器
  • 这里要非常小心!您的 BETWEEN CAST(@RegistrationFrom AS DATE) AND CAST(@RegistrationTo AS DATE) 不会包含最后一天的条目,如果它们有时间部分的话!
  • 这个问题解决了吗?您需要进一步的帮助吗?请给我一个提示:如果您在最佳答案的投票柜台下方勾选接受检查,那就太好了。这将 1) 将此问题标记为已解决 2) 让追随者更容易找到最佳解决方案 3) 向回答者支付积分和 4) 向您支付积分。一旦您自己越过 15 点边界,您 - 另外 - 被要求对贡献进行投票。这是说谢谢的方式。编码快乐!

标签: sql sql-server


【解决方案1】:

我会将查询写成:

SELECT @Todate = DATEADD(day, 1, @RegistrationTo);
. . .
WHERE Act.RegistrationOn >= @From AND 
      Act.RegistrationOn < @Todate

您是使用变量还是对变量进行强制转换对性能没有影响或影响很小。更重要的考虑因素是索引的使用和可解释性(代码是否符合您的预期)。

Aaron Bertrand 有一个很好的 blog 说明为什么你不应该使用 BETWEEN 来约会。

至于第一个版本。 . .它实际上比你想象的更合理。通常,函数调用会阻止在列上使用索引。但是,SQL Server 将datetime 转换为date 时例外。所以,它仍然会使用索引。

也就是说,我还是会选择上面的版本。

【讨论】:

  • 参数好像都是DATETIME上交的。如果他们有时间部分,这将导致意外和错误的结果......
【解决方案2】:

试试这样:

WITH MyPrms AS
(
    SELECT CAST(@RegistrationFrom AS DATE) AS fromD
          ,CAST(@RegistrationTo AS DATE) + 1 AS toD
)
SELECT *
FROM MyPrms
CROSS JOIN Act
WHERE Act.Registration>=fromD AND Act.RegistrationOn<toD;

它是完全可内联的(在 VIEWS 中,函数...)和 sargable(优化器可以使用索引)

编辑只是为了清楚

通过将+1 添加到您的上限日期(之前被转换为永恒的DATE,上限是最后一天之后的午夜。通过使用&lt;,您将获取全天的所有数据。BETWEEN 包含可能导致意外错误的边框...

【讨论】:

    【解决方案3】:

    从性能的角度来看,这两个选项是等效的:

    方法 1

    WHERE Act.RegistrationOn AS DATE BETWEEN CAST(@RegistrationFrom AS DATE) AND CAST(@RegistrationTo AS DATE)
    

    方法 2

    WHERE RegistrationOn BETWEEN @From AND @Todate
    

    方法 1 中的每个强制转换只执行一次,而不是您可能预期的每一行。

    为了清楚起见,我会采用选项 2,甚至更好地将具有正确类型的参数发送到此查询。

    此外,RegistrationOn 列上的索引肯定会有所帮助。请注意,已从方法 1 中删除了 RegistrationOn 列上的 CAST,因为这会阻止 SQL Server 使用此索引。

    【讨论】:

    • 此 CAST(Act.RegistrationOn AS DATE) 将适用于每一行的内容是什么?
    • Act.RegistrationOn 的强制转换将阻止 sql server 使用任何可能包含此列的索引。但是,如果该列的类型为 datetime,则强制转换为 date 无论如何都是多余的。因为日期时间可以与日期进行比较。
    • Mihai,不知道,也许 OP 想要这种方式,但是使用 BETWEENCAST AS DATE 作为高边界,您将不会包含最后一天的数据,如果有时间...
    • @ZoharPeled,迄今为止日期时间的演员阵容实际上是可追溯的:dba.stackexchange.com/questions/34047/…...
    【解决方案4】:
    WHERE CONVERT(VARCHAR, Act.RegistrationOn,101)  BETWEEN @From AND @Todate
    

    【讨论】:

    • 虽然此代码可能有助于解决问题,但提供有关 why 和/或 如何 回答问题的额外上下文将显着改善其长期长期价值。请edit你的答案添加一些解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-14
    • 1970-01-01
    • 2014-06-11
    • 1970-01-01
    • 2011-12-03
    • 2019-03-14
    • 2014-07-17
    相关资源
    最近更新 更多