快速入门

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

原表中具有时序特征的时间字段名,支持如下数据类型:

  • TIMESTAMP/TIMESTAMPTZ/DATE类型。

  • 被视为微秒的整数类型。

  • INTERVAL类型。

partitioning_column_name

分区字段名,默认按原表的时间字段分区。

number_partitions

分区数量。

associated_schema_name

指定超表所在的Schema。

associated_table_prefix

由于超表由一系列的分块表组成,块表会在内部自动创建,这里可指定块表的前缀。

chunk_time_interval

超表分块的时间间隔,默认按7 天分块。

create_default_indexes

是否在超表的时间字段上创建btree索引,取值范围如下:

  • true(默认):在超表的时间字段上创建btree索引。

  • false:不在超表的时间字段上创建btree索引。

if_not_exists

如果超表已经创建,是否报错,取值范围如下:

  • true:如果超表已经创建,则报错。

  • false(默认):如果超表已经创建,不报错。

partitioning_func

如果使用空间分区,可指定自定义的空间分区函数。

migrate_data

如果原表中已经存在数据,是否将数据转移至超表,取值范围如下:

  • true:如果原表中已经存在数据,将数据转移至超表。

  • false(默认):如果原表中已经存在数据,不将数据转移至超表

chunk_target_size

指定块表的大小(示例:'1000MB', 'estimate', or 'off')。

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。

示例

以交易数据为例,创建时序超表:

  1. 创建普通表:

    CREATE TABLE transaction_data(
       tm TIMESTAMPTZ NOT NULL,
       id INT NOT NULL,
       price double precision);
  2. 设置普通表的复制标识,必须为DEFAULT模式:

    ALTER TABLE transaction_data replica IDENTITY DEFAULT;
  3. 将普通表转换为超表:

    SELECT create_hypertable('transaction_data', 'tm', chunk_time_interval => INTERVAL '1 day');
  4. (可选)修改超表分区间隔:

    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;