【问题标题】:How Does Dateadd Impact the Performance of a SQL Query?Dateadd 如何影响 SQL 查询的性能?
【发布时间】:2011-01-07 09:40:12
【问题描述】:

例如,我加入一个数字表以在子查询中的两个日期之间执行一些操作,如下所示:

select n
      ,(select avg(col1)
          from table1
         where timestamp between dateadd(minute, 15*n, @ArbitraryDate) 
                             and dateadd(minute, 15*(n+1), @ArbitraryDate))
  from numbers
 where n < 1200

如果我比使用 dateadd 函数从连接的 varchars 构造日期,查询的性能会更好吗?

【问题讨论】:

  • n 是 table1 中的 int(或 smallint,等等)字段?
  • @Patrick Karcher,n 是 [number] 表中的一个 int。
  • 也许你需要向我们展示table1的结构

标签: sql sql-server performance tsql


【解决方案1】:

很可能不会有任何区别。 我会运行这个:

SET STATISTICS IO ON;
SET STATISTICS TIME ON;

后跟查询的两种变体,以便您查看和比较实际执行成本。

【讨论】:

    【解决方案2】:

    使用 DATEADD 以日期时间格式保存数据最有可能更快

    检查这个问题:Most efficient way in SQL Server to get date from date+time?

    接受的答案(不是我!)通过字符串转换演示了 DATEADD。很多年前我见过另一个显示相同的

    【讨论】:

    • 这正是我所希望的答案类型。为您找到它 +1,为伟大的基准 +1 给 Tomas。谢谢!
    【解决方案3】:

    您为什么要从使用相关子查询开始?这会比 dateadd 慢得多。它们就像游标一样,逐行工作。 这样的事情会奏效吗?

     select n.n , avgcol1   
        from numbers n 
        left outer join  
            (
            select avg(col1) as avgcol1, n
            from table1 
            where timestamp between dateadd(minute, 15*n, @ArbitraryDate)  
               and dateadd(minute, 15*(n+1), @ArbitraryDate)
            Group by n
            ) t
         on n.n = t.n
        where n < 1200 
    

    【讨论】:

    • 这是个好主意。问题是 table1 没有被枚举(或必须是可枚举的)。
    • 我把内连接换成了左外连接,这样这个查询就和原来的一样了。
    • 一般来说,相关子查询逐行工作是完全错误的。我们可以比较执行计划并亲自查看。
    • Alex 直接引用在线书籍:“在包含相关子查询(也称为重复子查询)的查询中,子查询的值取决于外部查询。这意味着子查询是重复执行,对于外部查询可能选择的每一行执行一次。"
    • @HLGEM 和@AlexKuznetsov,我仍然认为这不会起作用,除非 table1 是可枚举的。 table1 需要一个要加入的 n 列。
    【解决方案4】:

    只要您的谓词计算不包括对您正在查询的表的列的引用,您的方法就应该无关紧要(为了清楚起见)。

    不过,如果您要在计算中包含来自 Table1 的内容,我会注意表扫描或覆盖索引扫描,因为它可能不再是 sargable

    无论如何,请检查(或发布!)execution plan 以确认。

    【讨论】:

      【解决方案5】:

      注意中间和日期,看看How Does Between Work With Dates In SQL Server?

      我曾经将查询优化为从 24 小时到 36 秒。只是不要在列上使用日期函数或转换,请参见此处:Only In A Database Can You Get 1000% + Improvement By Changing A Few Lines Of Code

      要查看哪个查询执行得更好,同时执行两个查询并查看执行计划,您还可以使用统计 io 和统计时间来获取读取次数和执行查询所用的时间

      【讨论】:

      • 感谢关于“之间”的提醒。我知道我会得到一些重叠。
      • BETWEEN 运算符将您的范围视为closed range,而标准做法是使用半开范围。例如,[a, b) 表示a &lt;= x &lt; b,因此将诸如“2019 年”之类的内容写为[2019, 2020) 并将其转换为 SQL 为@x &gt;= '2019-01-01' AND @x &lt; '2020-01-01' 非常方便,而不必忍受data-type specific epsilons 做@ 987654330@,避免包括2020-01-01 00:00
      【解决方案6】:

      我不会使用连接 varchars。

      DateAdd 将比字符串连接和转换为 DATETIME 性能更好。

      与往常一样,最好的办法是分析这 2 个选项,并确定最佳结果,因为没有指定 DB。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多