Ganos TSDB是在PolarDB PostgreSQL版基础上以插件的形式实现的时序数据库,它继承了PolarDB PostgreSQL版集群拥有的共享存储、一写多读、备份恢复等一切能力,除此之外它可完全兼容开源时序数据库TimescaleDB Apache 2.0版本,并提供连续聚合、时序压缩、统计分析等时序数据高级功能。本文介绍时序数据库的基本概念,以及Ganos TSDB的基本用法,包括启用与升级维护,同时介绍时序数据库的使用方法。
基本概念
时序数据(Time Series Data):指按照时间顺序记录的数据序列。这类数据的特点是数据点不仅包含数值信息,还关联了具体的时间戳,反映了某一变量随时间变化的趋势或模式。时序数据广泛应用于多个领域,如金融交易、气象观测、传感器监测、网站流量分析、疾病传播研究等。时序数据的关键要素包括:
时间戳:每个数据点都有一个明确的时间标记,表明数据的采集时间。
观测值:在各个时间点上测量或记录到的数据值。
顺序性:数据点按照时间的先后顺序排列,这种顺序反映了数据之间的自然时间关系,使得时序数据具有时间序列的特性。
趋势和周期性:时序数据分析中常关注数据中的长期趋势、季节性波动、周期性变化以及随机波动等特征。
度量(Metrics):时序数据监测指标,如温度、股价、网络流量等任何可以量化测量的数值,度量可以帮助理解时序数据的行为模式、预测未来趋势,并能及时发现并响应异常情况。
聚合(Aggregation):指在时间序列数据分析中,将较高频率的数据聚合到较低频率的过程,简单来说,就是将数据按时间维度进行合并或汇总,从而减少数据的粒度,但同时能保留数据的主要趋势或特征。这种处理方式对于数据降维、趋势分析、异常检测以及预测模型的构建都非常有用。
降采样(Downsampling):时序数据处理的一个常见操作,可以减少时间序列数据的采样频率,即降低数据点的数量,同时尝试保留原始数据的关键特征或趋势。时序降采样的几种常见方法:
直接抽样(Decimation):这是最直接的方法,简单地每隔N个点取一个数据点。例如,如果原序列每秒采样10次,您可以选择只保留每5个点中的第一个,从而实现每秒2次的采样率。这种方法简单但可能会丢失高频信息。
平均值法(Averaging):在降采样前,先对连续的数据点进行平均处理。例如,将连续的5个点取平均值作为新的一个数据点。这种方法有助于平滑数据,减少噪声,但可能会模糊快速变化的细节。
中值法(Median):与平均值法类似,但使用连续数据点的中值代替平均值,这在处理包含异常值的时间序列时更为稳健。
最大值/最小值法:选取连续数据点中的最大值或最小值作为新数据点,适用于需要保留峰值或谷值的场景。
重采样(Resampling):通过插值等方法调整数据到新的时间点上,然后在新的时间线上进行均匀采样。常见的重采样方法有线性插值、最近邻插值、立方插值等。重采样方法更加灵活,可以根据需求调整到任意的采样频率,同时尽可能保持原数据的形态。
模型预测降采样:利用统计模型或机器学习模型预测在较低采样率下的数据点,比如使用ARIMA、LSTM等模型预测每个新时间点的值,然后使用这些预测值作为降采样后的数据。这种方法可以更智能地降采样,但计算成本较高。
前提条件
支持的PolarDB PostgreSQL版的版本如下:
PostgreSQL 14(内核小版本14.13.26.0及以上)。
您可通过如下语句查看PolarDB PostgreSQL版的内核小版本号:
SELECT version();
使用说明
启用时序数据库
在PolarDB PostgreSQL版集群中启用时序数据库能力,需要将timescaledb
添加到shared_preload_libraries参数中。您可以通过控制台修改shared_preload_libraries参数,详细操作请参考设置集群参数。
修改shared_preload_libraries参数后集群将会重启,请在修改参数前做好业务安排,谨慎操作。
安装插件。
CREATE EXTENSION ganos_tsdb CASCADE;
说明如在安装插件时遇到
ERROR: Disable the injection of custom functions when creating extension: metadata_insert_trigger (21128)
类似错误,请联系我们开放相关权限后再执行安装插件语句。创建ganos_tsdb的同时会创建TimescaleDB插件。
为避免权限问题,建议您将扩展安装在PUBLIC模式下。
CREATE EXTENSION ganos_tsdb WITH SCHEMA PUBLIC CASCADE;
升级插件。对于已经安装了Ganos TSDB或者TimescaleDB插件的集群,可以通过以下命令升级:
--先升级timescaledb ALTER EXTENSION timescaledb UPDATE; --再升级ganos_tsdb,如果是首次安装ganos_tsdb,则直接执行创建命令 ALTER EXTENSION ganos_tsdb UPDATE;
时序超表
超表(Hypertable)是时序数据库提供的一种特殊功能的表,可轻松处理时间序列数据,使用常规表可以完成的所有操作都可以使用超表完成。
关于超表
超表是一种PolarDB PostgreSQL版数据表,可自动按时间对数据进行分区。与超表的交互方式与常规表相同,但超表还具有一些额外功能,可更轻松地管理时间序列数据。
在时序数据库中,超表与常规表并存。使用超表来存储时间序列数据,这可以提高数据写入和查询性能,并支持在超表上使用序列功能函数。
借助超表,时序数据库可以根据时间参数对时间序列数据进行分区,在后台,由数据库自动执行设置和维护超表分区的工作。
创建超表
将一张普通数据表转为超表的语法如下:
SELECT create_hypertable(
'table_name',
'time_column_name',
'partitioning_column_name',
number_partitions,
'associated_schema_name',
'associated_table_prefix',
chunk_time_interval,
create_default_indexes,
if_not_exists,
partitioning_func,
migrate_data,
chunk_target_size,
chunk_sizing_func,
time_partitioning_func
);
具体参数解释如下:
参数名称 | 是否必选 | 描述 |
table_name | 是 | 需要转为超表的数据表名称或OID,为了区分,以下称其为原表,转为超表后,名称与原表同名。 |
time_column_name | 是 | 原表中具有时序特征的时间字段名,支持如下数据类型:
|
partitioning_column_name | 否 | 分区字段名,默认按原表的时间字段分区。 |
number_partitions | 否 | 分区数量。 |
associated_schema_name | 否 | 指定超表所在的Schema。 |
associated_table_prefix | 否 | 由于超表由一系列的分块表组成,块表会在内部自动创建,这里可指定块表的前缀。 |
chunk_time_interval | 否 | 超表分块的时间间隔,默认按7 天分块。 |
create_default_indexes | 否 | 是否在超表的时间字段上创建btree索引,取值范围如下:
|
if_not_exists | 否 | 如果超表已经创建,是否报错,取值范围如下:
|
partitioning_func | 否 | 如果使用空间分区,可指定自定义的空间分区函数。 |
migrate_data | 否 | 如果原表中已经存在数据,是否将数据转移至超表,取值范围如下:
|
chunk_target_size | 否 | 指定块表的大小(示例: |
chunk_sizing_func | 否 | 与chunk_target_size配合使用,指定自定义的函数以统计块表的时间间隔,并应用在新的块表中。 |
time_partitioning_func | 否 | 指定用于时间分区的分区函数。 |
超表的分区
在创建和使用超表时,它会自动按时间对数据进行分区,也可以按空间对数据进行分区。
每个超表由称为块(chunk)的子表组成,每个块分配一个时间范围,并且仅包含该范围内的数据。如果超表也按空间分区,则每个块也会分配空间值的子集。
超表的每个块仅保存特定时间范围内的数据。当插入尚无块的时间范围内的数据时,会自动创建一个块来存储它。
默认情况下,按7天时间间隔进行分区块,也可以使用以下SQL语句修改分区时间间隔。
SELECT set_chunk_time_interval(
'table_name',
chunk_time_interval,
'dimension_name'
);
具体参数解释如下:
参数名称 | 描述 |
table_name | 超表名称。 |
chunk_time_interval | 超表分块时间间隔。 |
dimension_name | 可选参数,指定分区(维度)策略,默认为NULL。 |
示例
以交易数据为例,创建时序超表:
创建普通表:
CREATE TABLE transaction_data( tm TIMESTAMPTZ NOT NULL, id INT NOT NULL, price double precision);
设置普通表的复制标识,必须为DEFAULT模式:
ALTER TABLE transaction_data replica IDENTITY DEFAULT;
将普通表转换为超表:
SELECT create_hypertable('transaction_data', 'tm', chunk_time_interval => INTERVAL '1 day');
(可选)修改超表分区间隔:
SELECT set_chunk_time_interval('transaction_data', chunk_time_interval => INTERVAL '2 day');
连续聚合
连续聚合(continuous aggregates)旨在使超大数据集查询得更快。连续聚合使用物化视图在后台连续且增量地刷新查询,以便在运行查询时,只需要计算已更改的数据,而不是整个数据集。
创建连续聚合
CREATE MATERIALIZED VIEW transaction_five_minute_mview
WITH (timescaledb.continuous) AS
SELECT id,
time_bucket(INTERVAL '5 minute', tm) AS bucket,
AVG(price),
MAX(price),
MIN(price)
FROM transaction_data
GROUP BY id, bucket;
CREATE MATERIALIZED VIEW transaction_one_hour_mview
WITH (timescaledb.continuous) AS
SELECT id,
time_bucket(INTERVAL '1 hour', tm) AS bucket,
AVG(price),
MAX(price),
MIN(price)
FROM transaction_data
GROUP BY id, bucket;
设置连续聚合刷新策略
设置5分钟视图的更新频率为1秒:
SELECT add_continuous_aggregate_policy('transaction_five_minute_mview', start_offset => NULL, end_offset => INTERVAL '5 min', schedule_interval => INTERVAL '1 sec');
设置1小时视图的更新频率为1分钟:
SELECT add_continuous_aggregate_policy('transaction_one_hour_mview', start_offset => NULL, end_offset => INTERVAL '1 hour', schedule_interval => INTERVAL '1 min');
启停连续聚合刷新策略
设置刷新策略后,默认是关闭状态,需要手动将其设置为启用状态。当希望节约系统资源情况时也可以将刷新策略设置为关闭状态。
启用刷新策略:
---启用5分钟视图刷新策略 ALTER MATERIALIZED VIEW transaction_five_minute_mview set (timescaledb.materialized_only = false); ---启用1小时视图刷新策略 ALTER MATERIALIZED VIEW transaction_one_hour_mview set (timescaledb.materialized_only = false);
停用刷新策略:
---停用5分钟视图刷新策略 ALTER MATERIALIZED VIEW transaction_five_minute_mview set (timescaledb.materialized_only = true); ---停用1小时视图刷新策略 ALTER MATERIALIZED VIEW transaction_one_hour_mview set (timescaledb.materialized_only = true);
写入数据至超表
CREATE OR REPLACE FUNCTION make_trans_data(cnt int, tblname text)
RETURNS void
AS $$
DECLARE
sql text;
i int := 0;
BEGIN
FOR i IN 1..cnt
LOOP
-- 数据产生频率为1 min
sql = format('INSERT INTO %s(tm, id, price) VALUES(''2024-01-01 01:32:00''::TIMESTAMPTZ + ''%s min'', 1, 25+random()*5);', tblname, i);
execute sql;
END LOOP;
END;
$$
LANGUAGE 'plpgsql';
SELECT make_trans_data(100000, 'transaction_data');
查询连续聚合
查询5分钟聚合视图:
SELECT * FROM transaction_five_minute_mview WHERE id = 1 ORDER BY bucket;
返回结果如下:
id | bucket | avg | max | min ----------+------------------------+--------------------+--------------------+-------------------- 1 | 2024-01-01 01:00:00+08 | 27.71473106645959 | 29.382205152249785 | 25.57066817275004 1 | 2024-01-01 01:05:00+08 | 28.047595687281046 | 29.95373300432865 | 26.5804794171798 1 | 2024-01-01 01:10:00+08 | 26.886727134847632 | 29.618678419331452 | 25.542425053517448 1 | 2024-01-01 01:15:00+08 | 27.66459562393295 | 29.384819410390808 | 25.98123617659473 1 | 2024-01-01 01:20:00+08 | 27.51044547905668 | 28.96496200408036 | 26.400810183343637 1 | 2024-01-01 01:25:00+08 | 27.11575041786701 | 29.235194086952347 | 25.254402527742652 1 | 2024-01-01 01:30:00+08 | 27.235267548506148 | 29.588470070540076 | 25.02734910524511 1 | 2024-01-01 01:35:00+08 | 28.324461354574083 | 29.69822992893265 | 26.81138181844558 1 | 2024-01-01 01:40:00+08 | 29.025639648102718 | 29.90137161064922 | 28.17982996110466 1 | 2024-01-01 01:45:00+08 | 27.304264829013988 | 29.258375316444774 | 25.41408817930172 1 | 2024-01-01 01:50:00+08 | 27.79180238172512 | 29.681647002081526 | 25.61807962924787 1 | 2024-01-01 01:55:00+08 | 28.509148439180745 | 29.514106519007157 | 27.86880311664552 1 | 2024-01-01 02:00:00+08 | 27.102089460989 | 27.97529260208675 | 26.42301163169506
查询1小时聚合视图:
SELECT * FROM transaction_one_hour_mview WHERE id = 1 ORDER BY bucket;
返回结果如下:
id | bucket | avg | max | min ----------+------------------------+--------------------+--------------------+-------------------- 1 | 2024-01-01 01:00:00+08 | 27.76165113536066 | 29.95373300432865 | 25.02734910524511 1 | 2024-01-01 02:00:00+08 | 27.258612444571547 | 29.904677294604856 | 25.055769589204342 1 | 2024-01-01 03:00:00+08 | 27.23598692759433 | 29.96548968844543 | 25.005789123775894 1 | 2024-01-01 04:00:00+08 | 27.45210713073776 | 29.977740285026293 | 25.046434697239732 1 | 2024-01-01 05:00:00+08 | 27.46406508180239 | 29.991966017428577 | 25.002763662365037 1 | 2024-01-01 06:00:00+08 | 27.27656140300274 | 29.956770824017838 | 25.108233973093572 1 | 2024-01-01 07:00:00+08 | 27.4322210561795 | 29.987582889270037 | 25.06072539802812 1 | 2024-01-01 08:00:00+08 | 27.47425150068208 | 29.901690827507093 | 25.080841718110438 1 | 2024-01-01 09:00:00+08 | 27.62315772556615 | 29.950381936739365 | 25.00460435187133 1 | 2024-01-01 10:00:00+08 | 27.178210805657518 | 29.88265205362758 | 25.001676411976153 1 | 2024-01-01 11:00:00+08 | 27.494308291596898 | 29.96406889655635 | 25.284677425690667 1 | 2024-01-01 12:00:00+08 | 27.58228931469942 | 29.99257040124446 | 25.080872170315036
嵌套聚合
嵌套聚合是指在连续聚合生成的物化视图基础上再创建连续聚合,比如按小时聚合结果基础上创建按天聚合,按天聚合基础上创建按月聚合等,一方面减少了数据冗余,另一方面提升了聚合的性能。
时序压缩
当时序分区被判定为历史数据时,可以启用时序数据库提供的数据压缩功能,Ganos TSDB提供整表压缩以及指定分区压缩的功能,压缩后可降低数据存储空间,压缩率可达70%以上,大大减轻存储成本。
压缩后数据只能读不能写。
当前版本不支持时序压缩功能,如要启用时序压缩功能,请联系我们处理。
卸载插件
DROP EXTENSION ganos_tsdb CASCADE;
DROP EXTENSION timescaledb CASCADE;