我需要编写一个查询,按照从一年到一小时的时间段对大量记录进行分组。
我最初的方法是在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字段上的索引;是否有任何想法?
感谢。
答案 0 :(得分:9)
与任何与绩效相关的衡量
检查第二种方法的查询计划将提前告诉您任何明显的问题(当您不需要时可以进行全表扫描),但没有替代测量。在SQL性能测试中,应使用适当大小的测试数据进行测量。
由于这是一个复杂的案例,您不是简单地比较两种不同的方式来执行单个查询,而是将单个查询方法与迭代方法进行比较,您的环境方面可能在实际性能中起主要作用。
特别是
答案 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形式的自然整数密钥,它具有相对高性能且人类可读。
另一种选择可能是索引视图,其中每个日期部分都有单独的表达式。
或计算列。
但必须对性能进行测试并检查执行计划......