我需要编写一个查询,按年度到小时的时间段对大量记录进行分组.
我最初的方法是在C#中以程序方式决定周期,迭代每个周期并运行SQL以获取该周期的数据,随时构建数据集.
SELECT Sum(someValues) FROM table1 WHERE deliveryDate BETWEEN @fromDate AND @ toDate
我后来发现我可以使用Year(),Month()Day()和datepart(week,date)和datepart(hh,date)对记录进行分组.
SELECT Sum(someValues) FROM table1 GROUP BY Year(deliveryDate), Month(deliveryDate), Day(deliveryDate)
我担心的是,由于无法有效地使用datetime字段上的索引,因此在group by中使用datepart会导致比在一段时间内多次运行查询更糟糕的性能; 有关这是否属实的任何想法?
谢谢.
与任何与绩效相关的措施一样
检查第二种方法的查询计划将提前告诉您任何明显的问题(当您不需要时可以进行全表扫描),但无法替代测量.在SQL性能测试中,应使用适当大小的测试数据进行测量.
由于这是一个复杂的案例,您不是简单地比较两种不同的方式来执行单个查询,而是将单个查询方法与迭代方法进行比较,您的环境方面可能在实际性能中起主要作用.
特别
应用程序和数据库之间的"距离",因为与一个大查询方法相比,每个调用的延迟将浪费时间
是否使用预准备语句(在每个查询上导致数据库引擎的额外解析工作)
范围查询本身的构造是否代价高昂(受2的影响很大)
如果将公式放入比较的字段部分,则会进行表扫描.
索引在字段上,而不是在datepart(字段)上,因此必须计算所有字段 - 所以我认为你的预感是正确的.
你可以做类似的事情:
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
如果你能够容忍加入另一张桌子的表现,我有一个看似奇怪的建议,但效果很好.
创建一个我称之为ALMANAC的表,其中包含工作日,月,年等列.您甚至可以为日期的公司特定功能添加列,例如日期是否为公司假日.您可能希望添加开始和结束时间戳,如下所述.
虽然你可能每天都有一排,但是当我这样做的时候,我觉得每班一排很方便,一天有三班.即使按照这个速度,十年的时间也只有一万多排.
当您编写SQL来填充此表时,您可以使用所有面向日期的内置函数来简化工作.当您进行查询时,可以使用日期列作为连接条件,或者您可能需要两个时间戳来提供范围以捕获范围内的时间戳.其余部分与使用任何其他类型的数据一样简单.