Quick start
Ganos TSDB is a time-series database plug-in built on PolarDB for PostgreSQL as an extension. It inherits all capabilities of a PolarDB for PostgreSQL cluster, including shared storage, one primary node with multiple read-only nodes, and backup and recovery. In addition, it is fully compatible with the open-source TimescaleDB Apache 2.0 edition and provides advanced time-series features such as continuous aggregation, time-series compression, and statistical analysis. This topic describes the basic concepts of the time-series database and the basic usage of Ganos TSDB, including how to enable and upgrade it, as well as how to use the time-series database.
Scope of application
-
Supported PolarDB for PostgreSQL versions:
-
PostgreSQL 14 (minor engine version 2.0.14.13.26.0 or later).
-
PostgreSQL 16 (minor engine version 2.0.16.9.8.0 or later).
-
-
Serverless clusters are not supported. Use a Subscription or Pay-as-you-go cluster instead.
You can view the minor engine version in the console or by running the SHOW polardb_version; statement. If the minor engine version does not meet the requirements, upgrade the minor engine version。
Basic concepts
-
Time series data: A sequence of data points recorded in chronological order. Each data point contains not only a numeric value but also an associated timestamp, reflecting the trend or pattern of a variable over time. Time series data is widely used in various fields, such as financial transactions, meteorological observations, sensor monitoring, website traffic analysis, and epidemic studies. Key elements of time series data include:
-
Timestamp: Each data point has a clear time marker indicating when the data was collected.
-
Observed value: The data value measured or recorded at each time point.
-
Sequential order: Data points are arranged in chronological order, reflecting the natural temporal relationship between data points and giving time series data its time-series characteristics.
-
Trends and periodicity: Time series data analysis often focuses on long-term trends, seasonal fluctuations, cyclical changes, and random variations in the data.
-
-
Metrics: Monitoring indicators for time series data, such as temperature, stock prices, and network traffic — any quantifiable measurement. Metrics help understand behavior patterns of time series data, predict future trends, and detect and respond to anomalies in a timely manner.
-
Aggregation: The process of consolidating higher-frequency data into lower-frequency data in time series analysis. In simple terms, data is merged or summarized along the time dimension to reduce granularity while retaining key trends or features. This approach is useful for data reduction, trend analysis, anomaly detection, and predictive model building.
-
Downsampling: A common operation in time series data processing that reduces the sampling frequency of time series data — that is, reduces the number of data points while attempting to retain the key features or trends of the original data. Common downsampling methods include:
-
Decimation: The most direct method, simply taking every Nth data point. For example, if the original sequence is sampled 10 times per second, you can keep only the first of every 5 points, achieving a sampling rate of 2 times per second. This method is simple but may lose high-frequency information.
-
Averaging: Before downsampling, consecutive data points are averaged. For example, the average of 5 consecutive points becomes a single new data point. This method helps smooth data and reduce noise, but may obscure rapid changes.
-
Median: Similar to averaging, but uses the median of consecutive data points instead of the mean. This is more robust when processing time series that contain outliers.
-
Max/Min: Selects the maximum or minimum value from consecutive data points as the new data point, suitable for scenarios where peak or valley values must be preserved.
-
Resampling: Adjusts data to new time points through interpolation or other methods, then performs uniform sampling on the new timeline. Common resampling methods include linear interpolation, nearest neighbor interpolation, and cubic interpolation. Resampling methods are more flexible and can adjust to any sampling frequency while preserving the data distribution as much as possible.
-
Model-based downsampling: Uses statistical or machine learning models to predict data points at lower sampling rates, such as using ARIMA or LSTM models to predict values at each new time point, and then uses these predicted values as the downsampled data. This method enables more intelligent downsampling but has higher computational costs.
-
Ganos TSDB vs. TimescaleDB
-
TimescaleDB: An open-source time-series database built on PostgreSQL, optimized for handling time-series data such as sensor data, monitoring metrics, and financial data. Its design goal is to provide efficient storage, fast writes, and complex query capabilities for time-series data while retaining full PostgreSQL SQL functionality.
-
Ganos TSDB: A time-series engine developed on top of the open-source TimescaleDB, running on PolarDB for PostgreSQL clusters as a plug-in. It fully inherits all PolarDB capabilities such as shared storage, one primary node with multiple read-only nodes, and backup and recovery.
Differences
The two differ primarily in the features they provide. TimescaleDB Apache 2 Edition is the version of TimescaleDB released under the Apache 2.0 license. The Apache 2.0 open-source license allows anyone to use the code and provide it as a service, but only basic features are included.
In contrast, Ganos TSDB is fully compatible with TimescaleDB and additionally provides advanced features such as time-series Continuous aggregates, data compression, and OSS tiered storage for hot and cold data.
Enable the time-series database
To enable the time-series database capability in a PolarDB for PostgreSQL cluster, add timescaledb to the shared_preload_libraries parameter. You can modify the shared_preload_libraries parameter in the console.
Modifying the shared_preload_libraries parameter restarts the cluster. Plan your maintenance window before making this change.
Create the plug-in
Upgrade the plug-in
Hypertables
A hypertable is a special type of table provided by the time-series database that can easily handle time-series data. All operations that can be performed on regular tables can also be performed on hypertables.
Features
-
Hypertables automatically partition data by time. You interact with hypertables the same way as regular tables, but hypertables also have additional features that make it easier to manage time-series data.
-
In the time-series database, hypertables coexist with regular tables. Use hypertables to store time-series data to improve write and query performance, and to support sequence functions on hypertables.
-
With hypertables, the time-series database can partition time-series data based on time parameters. In the background, the database automatically sets up and maintains hypertable partitions.
Create a hypertable
The syntax for converting a regular table to a hypertable is as follows:
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
);
The following table describes the parameters.
|
Parameter |
Required |
Description |
|
table_name |
Yes |
The name or OID of the table to be converted to a hypertable. The hypertable keeps the same name after conversion. |
|
time_column_name |
Yes |
The name of the time column in the source table. The following data types are supported:
|
|
partitioning_column_name |
No |
The partitioning column name. By default, the table is partitioned by the time column. |
|
number_partitions |
No |
The number of partitions. |
|
associated_schema_name |
No |
The schema where the hypertable resides. |
|
associated_table_prefix |
No |
Since a hypertable consists of a series of chunk tables that are automatically created internally, you can specify the prefix for chunk tables here. |
|
chunk_time_interval |
No |
The time interval for hypertable chunks. Default is 7 days. |
|
create_default_indexes |
No |
Whether to create a B-tree index on the time column of the hypertable. Valid values:
|
|
if_not_exists |
Whether to report an error if the hypertable already exists. Valid values: |
Whether to report an error if the hypertable already exists. Valid values:
|
|
partitioning_func |
No |
If spatial partitioning is used, you can specify a custom spatial partitioning function. |
|
migrate_data |
No |
Whether to migrate existing data from the source table to the hypertable. Valid values:
|
|
chunk_target_size |
No |
The target size for chunks (example: |
|
chunk_sizing_func |
No |
Used with |
|
time_partitioning_func |
No |
The partitioning function for time-based partitioning. |
Hypertable partitioning
-
When you create and use a hypertable, it automatically partitions data by time. Data can also be partitioned by space.
-
Each hypertable consists of child tables called chunks. Each chunk is assigned a time range and contains only data within that range. If the hypertable is also partitioned by space, each chunk is also assigned a subset of space values.
-
Each chunk of a hypertable stores data only within a specific time range. When data is inserted for a time range that does not yet have a chunk, a chunk is automatically created to store it.
By default, the chunk time interval is 7 days. You can use the following SQL statement to change the partition time interval.
SELECT set_chunk_time_interval(
'table_name',
chunk_time_interval,
'dimension_name'
);
The following table describes the parameters.
|
Parameter |
Description |
|
table_name |
The name of the hypertable. |
|
chunk_time_interval |
The chunk time interval for the hypertable. |
|
dimension_name |
Optional. The partitioning (dimension) strategy. Default is NULL. |
Example
The following example uses transaction data to create a time-series hypertable:
-
Create a regular table:
CREATE TABLE transaction_data( tm TIMESTAMPTZ NOT NULL, id INT NOT NULL, price double precision); -
Set the replica identity of the regular table to DEFAULT mode:
ALTER TABLE transaction_data replica IDENTITY DEFAULT; -
Convert the regular table to a hypertable:
SELECT create_hypertable('transaction_data', 'tm', chunk_time_interval => INTERVAL '1 day');NoteIf the table already contains data, add the
migrate_dataparameter and set it totruewhen converting to a hypertable. However, if the table contains a large amount of data, the conversion may take a long time. -
(Optional) Change the hypertable partition interval.
SELECT set_chunk_time_interval('transaction_data', chunk_time_interval => INTERVAL '2 day');
Continuous aggregates
Continuous aggregates are an automated precomputation mechanism that periodically or in real time precompute predefined aggregation results such as hourly averages, converting complex queries into fast reads of precomputed results. They are similar to materialized views but optimized for time-series data, supporting incremental updates and avoiding repeated computation of historical data to accelerate queries on very large datasets.
Benefits
-
Query acceleration: Query precomputed results directly to avoid full table scans of raw data.
-
Resource savings: Reduce CPU and memory consumption for real-time computation.
-
Automated maintenance: Automatically handle aggregation updates for new and old data without manual triggering.
Create a continuous aggregate
CREATE MATERIALIZED VIEW transaction_min_cagg
WITH (timescaledb.continuous) -- Declare as a continuous aggregate
AS
SELECT id,
time_bucket(INTERVAL '1 min', tm) AS bucket, -- Aggregate by 1-minute intervals
AVG(price),
MAX(price),
MIN(price)
FROM transaction_data
GROUP BY id, bucket;
Continuous aggregate data storage
Continuous aggregate results are stored in independent materialized views. Data is stored in time-based chunks that are aligned with the underlying hypertable partitions.
Job scheduling
Continuous aggregates use job scheduling to write and refresh data. The job scheduling feature enables automatic or manual refresh of aggregation results.
Create a job
Create a job that can automate the scheduling of a function or stored procedure.
integer add_job(
proc REGPROC,
schedule_interval INTERVAL,
config JSONB DEFAULT NULL,
initial_start TIMESTAMPTZ DEFAULT NULL,
scheduled BOOL DEFAULT true,
check_config REGPROC DEFAULT NULL,
fixed_schedule BOOL DEFAULT TRUE,
timezone TEXT DEFAULT NULL
);
The following table describes the parameters.
|
Parameter |
Description |
|
proc |
The name or OID of the function or stored procedure to execute. |
|
schedule_interval |
The interval between job executions. |
|
config |
Job configuration parameters. |
|
initial_start |
The start time for the job. Default is the current time. |
|
scheduled |
Whether to run automatically. Default is |
|
check_config |
A function to validate whether the |
|
fixed_schedule |
Whether to run the job at fixed time intervals. Default is |
|
timezone |
The time zone. Default is NULL. |
Example
-
Prepare the base data. Create the stored procedure to be executed.
CREATE OR REPLACE PROCEDURE user_defined_action(job_id int, config jsonb) LANGUAGE PLPGSQL AS $$ BEGIN RAISE NOTICE 'Executing action % with config %', job_id, config; END $$; -
Create a job. The function returns the job
id.SELECT add_job('user_defined_action','1 hour'); SELECT add_job('user_defined_action','1h', initial_start => '2024-03-11 00:00:00');
Modify a job
Modify a job that has already been created.
void alter_job( job_id INTEGER,
schedule_interval INTERVAL = NULL,
max_runtime INTERVAL = NULL,
max_retries INTEGER = NULL,
retry_period INTERVAL = NULL,
scheduled BOOL = NULL,
config JSONB = NULL,
next_start TIMESTAMPTZ = NULL,
if_exists BOOL = FALSE,
check_config REGPROC = NULL,
fixed_schedule BOOL = NULL,
initial_start TIMESTAMPTZ = NULL,
timezone TEXT DEFAULT NULL
);
The following table describes some of the parameters.
This section describes only some parameters. For the full parameter list, see Create a job parameters.
|
Parameter |
Description |
|
job_id |
The |
|
max_runtime |
The maximum runtime for the job. Default is NULL. |
|
max_retries |
The maximum number of retries after job failure. Default is NULL. |
|
retry_period |
The retry interval after job failure. Default is NULL. |
Example
SELECT alter_job(1002, schedule_interval => INTERVAL '2 hours');
Run a job manually
Manually run a job that already exists.
void run_job(job_id int);
The following table describes the parameters.
|
Parameter |
Description |
|
job_id |
The |
Example
CALL run_job(1002);
Delete a job
Delete a job.
void delete_job(job_id int);
The following table describes the parameters.
|
Parameter |
Description |
|
job_id |
The |
Example
SELECT delete_job(1002);
Refresh continuous aggregates
Refresh manually
The stored procedure for manually refreshing a continuous aggregate.
refresh_continuous_aggregate(
cagg REGCLASS,
window_start "any",
window_end "any"
);
The following table describes the parameters.
|
Parameter |
Description |
|
cagg |
The name or OID of the continuous aggregate to refresh. |
|
window_start |
The start time of the refresh window. The type must match the continuous aggregate time column.
|
|
window_end |
The end time of the refresh window. The type must match the continuous aggregate time column. If the refresh end time is unclear, set it to NULL to refresh up to the latest data in the table. |
Usage notes
-
The refresh window time must match the data time in the table. When refreshing a continuous aggregate, only data in fully matching time windows is refreshed. Aggregation cannot be computed for incomplete time periods.
-
If multiple calls to
refresh_continuous_aggregatehave overlapping time windows, only time periods with new or modified data are aggregated. Time periods without data modifications are not processed. -
refresh_continuous_aggregateis a stored procedure function and must be called using CALL.
Example
CALL refresh_continuous_aggregate('transaction_min_cagg', '2024-03-11 00:00:00+08'::timestamptz, NULL);
Refresh automatically
The following two methods are available for automatic refresh of continuous aggregates.
Use the add_continuous_aggregate_policy function
Real-time queries
When querying continuous aggregates, if real-time query is not enabled, only data with completed aggregations is accessible. You can enable real-time query to access newly ingested data that has not yet been aggregated.
-
Enable real-time query
ALTER MATERIALIZED VIEW transaction_min_cagg SET (timescaledb.materialized_only = false); -
Disable real-time query
ALTER MATERIALIZED VIEW transaction_min_cagg SET (timescaledb.materialized_only = true);
Nested aggregates
Nested aggregates refer to creating continuous aggregates on top of materialized views generated by other continuous aggregates. For example, you can create hourly aggregates on top of per-minute aggregates, and monthly aggregates on top of daily aggregates. This reduces data redundancy and improves aggregation performance.
-
Create the first-level aggregate. In this example, a per-minute aggregate is created.
CREATE MATERIALIZED VIEW transaction_min_cagg WITH (timescaledb.continuous) AS SELECT id, time_bucket(INTERVAL '1 min', tm) AS bucket, AVG(price) as avg, MAX(price) as max, MIN(price) as min FROM transaction_data GROUP BY id, bucket; -
Create a nested aggregate. Create an hourly aggregate on top of the per-minute aggregate.
CREATE MATERIALIZED VIEW transaction_one_hour_mview WITH (timescaledb.continuous) AS SELECT id, time_bucket(INTERVAL '1 hour', bucket) AS bucket, AVG(avg) as avg, MAX(max) as max, MIN(min) as min FROM transaction_min_cagg GROUP BY id, time_bucket(INTERVAL '1 hour', bucket);
Time-series compression
-
When a time-series partition is identified as historical data, you can enable the data compression feature provided by the time-series database. Ganos TSDB supports compressing entire tables or specific partitions. Compression can reduce data storage space by more than 70%, significantly lowering storage costs.
-
Compressed data is read-only.
Uninstall the plug-in
DROP EXTENSION ganos_tsdb CASCADE;
DROP EXTENSION timescaledb CASCADE;