解锁 SQL Server 2022的时间序列数据功能
SQL Server2022在处理时间序列数据时,SQL Server 提供了一些优化和功能,比如 DATE_BUCKET 函数、窗口函数(如 FIRST_VALUE 和 LAST_VALUE)以及其他时间日期函数,以便更高效地处理时间序列数据。
GENERATE_SERIES函数
SQL Server 2022 引入了一个新的函数 GENERATE_SERIES,它用于生成一个整数序列。
这个函数非常有用,可以在查询中生成一系列连续的数值,而无需创建临时表或循环。
使用场景包括快速生成一系列数据用于测试或填充表或者结合日期函数生成一系列日期值。
示例
生成的结果集将包含 20 行,每行显示从 '2019-02-28 13:45:23' 开始,按分钟递增的时间。
对于每一个 s.value,DATEADD 函数将基准日期时间增加相应的分钟数。
DATE_BUCKET函数
SQL Server 2022 引入了一个新的函数 DATE_BUCKET,用于将日期时间值按指定的时间间隔分组(即分桶)。
这个函数在时间序列分析、数据聚合和分段分析等场景中非常有用。
使用 DATE_BUCKET 函数时,指定的时间间隔单位(如 YEAR、QUARTER、MONTH、WEEK 等)以及起始日期(origin)决定了日期时间值被分配到哪个存储桶。这种方式有助于理解时间间隔的计算是如何基于起始日期来进行的。
示例
更多实际场景示例
按自定义起始日期分组
假设我们有一系列事件时间 EventTime,希望从'2023-01-01'日期开始,每周进行分组统计事件数量。
按自定义时间间隔分组
假设我们有一个传感器数据表 SensorReadings
如果是传统方法需要使用公用表表达式CTE才能完成这个需求
WITH TimeIntervals AS (...)公共表表达式(CTE)用于计算每条记录的 BucketStartTime。
DATEDIFF(MINUTE, '2000-01-01', ReadingTime) / 10 计算 ReadingTime 到基准时间 '2000-01-01' 的分钟数,然后除以 10,得到当前时间点所在的 10 分钟区间的索引。
DATEADD(MINUTE, ..., '2000-01-01') 将该索引转换回具体的时间点,即区间的起始时间。
查询主部分:
选择 BucketStartTime 和相应区间内读数值的平均值。
使用 GROUP BY 按 BucketStartTime 分组,并计算每个分组的平均值。
ORDER BY 用于按照时间顺序排列结果。
FIRST_VALUE 和 LAST_VALUE 窗口函数
在 之前版本的SQL Server 中,FIRST_VALUE 和 LAST_VALUE 是窗口函数,用于在一个分区或窗口中返回第一个或最后一个值。
SQL Server 2022 引入了新的选项 IGNORE NULLS 和 RESPECT NULLS 来处理空值(NULL)的方式,从而增强了这些函数的功能。
基本语法
示例
假设我们有一个表 MachineTelemetry,包含以下数据:
默认行为(包含 NULL 值)
忽略 NULL 值
总结
实际上,对于时间序列我们一般使用专业的时间序列数据库,例如InfluxDB 。
它使用 TSM(Time-Structured Merge Tree)作为存储引擎称,这是 LSM 树的一种变体,专门优化用于时间序列数据的写入和查询性能。
另外,SQL Server 的时间序列功能是使用行存储引擎(Row Store)作为其存储引擎,这意味着数据是按行进行存储和处理的。
在大部分场景下面,如果性能不是要求非常高,其实SQL Server 存储时间序列数据性能是完全足够的,而且额外使用InfluxDB数据库需要维护多一个技术栈,对运维要求更加高。
特别是现在追求数据库一体化的趋势背景下,无论是时间序列数据,向量数据,地理数据,json数据都最好在一个数据库里全部满足,减轻运维负担,复用技术栈,减少重复建设成本是比较好的解决方案。
参考文章
https://sqlbits.com/sessions/event2024/Time_Series_with_SQL_Server_2022
https://www.microsoft.com/en-us/sql-server/blog/2023/01/12/working-with-time-series-data-in-sql-server-2022-and-azure-sql/
https://www.mssqltips.com/sqlservertip/6232/load-time-series-data-with-sql-server/