SQL组按年,月,周,日,小时SQL与程序性能

时间:2009-01-27 10:36:36

标签: sql sql-server performance

我需要编写一个查询,按照从一年到一小时的时间段对大量记录进行分组。

我最初的方法是在C#中以程序方式决定句点,迭代每个句点并运行SQL以获取该时段的数据,并在我去的时候构建数据集。

SELECT Sum(someValues)
FROM table1
WHERE deliveryDate BETWEEN @fromDate AND @ toDate

我后来发现我可以使用Year(),Month()Day()和datepart(周,日期)和datepart(hh,date)对记录进行分组。

SELECT Sum(someValues)
FROM table1
GROUP BY Year(deliveryDate), Month(deliveryDate), Day(deliveryDate)

我担心的是,在一组时间内使用datepart会导致比在一段时间内多次运行查询更糟糕的性能,因为无法有效地使用datetime字段上的索引;是否有任何想法?

感谢。

7 个答案:

答案 0 :(得分:9)

与任何与绩效相关的衡量

检查第二种方法的查询计划将提前告诉您任何明显的问题(当您不需要时可以进行全表扫描),但没有替代测量。在SQL性能测试中,应使用适当大小的测试数据进行测量。

由于这是一个复杂的案例,您不是简单地比较两种不同的方式来执行单个查询,而是将单个查询方法与迭代方法进行比较,您的环境方面可能在实际性能中起主要作用。

特别是

  1. 应用程序与数据库之间的“距离”,因为与一个大查询方法相比,每次调用的延迟都将浪费时间
  2. 您是否正在使用预准备语句(在每个查询中对数据库引擎进行额外的解析工作)
  3. 范围查询本身的构造是否成本高昂(受2的影响很大)

答案 1 :(得分:6)

如果您将公式放入比较的字段部分,可以进行表格扫描

索引是在字段上,而不是在datepart(字段)上,所以必须计算所有字段 - 所以我认为你的预感是正确的。

答案 2 :(得分:5)

你可以做类似的事情:

SELECT Sum(someValues)
FROM 
(
    SELECT *, Year(deliveryDate) as Y, Month(deliveryDate) as M, Day(deliveryDate) as D
    FROM table1
    WHERE deliveryDate BETWEEN @fromDate AND @ toDate
) t
GROUP BY Y, M, D

答案 3 :(得分:5)

如果你能够容忍加入另一张表的表现,我有一个看似奇怪的建议,但效果很好。

创建一个表格,我将其称为ALMANAC,其中包含工作日,月份,年份等列。您甚至可以为日期的公司特定功能添加列,例如日期是否为公司假日。您可能希望添加开始和结束时间戳,如下所述。

虽然你可能每天都有一排,但是当我这样做的时候,我发现每班一排很方便,一天有三班。即使按照这个速度,十年的时间也只有10,000多行。

当您编写SQL来填充此表时,您可以使用所有面向日期的内置函数来简化工作。当您进行查询时,可以使用日期列作为连接条件,或者您可能需要两个时间戳来提供范围以捕获范围内的时间戳。其余部分就像使用任何其他类型的数据一样简单。

答案 4 :(得分:2)

我一直在寻找用于报告目的的类似解决方案,并且遇到了一篇名为Group by Month (and other time periods)的文章。它显示了按日期时间字段分组的各种方式,无论好坏。绝对值得一看。

答案 5 :(得分:1)

我认为你应该对它进行基准测试以获得可靠的结果,但是,恕我直言和我的第一个想法是让DB处理它(你的第二种方法)会比你在客户端代码中做得快得多。 使用您的第一种方法,您可以多次往返数据库,我认为这将更加昂贵。 :)

答案 6 :(得分:1)

您可能希望查看维度方法(这与Walter Mitty建议的相似),其中每一行都有一个日期和/或时间维度的外键。这允许通过连接到该表进行非常灵活的求和,其中这些部分是预先计算的。在这些情况下,密钥通常是YYYYMMDD和HHMMSS形式的自然整数密钥,它具有相对高性能且人类可读。

另一种选择可能是索引视图,其中每个日期部分都有单独的表达式。

或计算列。

但必须对性能进行测试并检查执行计划......