GanosBase TSDB は、PolarDB for PostgreSQL 用のプラグインとして実装された時系列データベースです。共有ストレージ、ワンライターマルチリーダー、バックアップおよび回復といった PolarDB for PostgreSQL クラスターのすべての機能を継承しています。さらに、Apache 2.0 ライセンスで提供されるオープンソースの時系列データベース TimescaleDB と完全互換であり、連続集約、時系列データ圧縮、統計分析などの高度な時系列データ機能を提供します。本トピックでは、時系列データベースの基本概念について説明し、GanosBase TSDB の有効化、スペックアップ、およびメンテナンス方法、ならびに時系列データベースの使用方法について説明します。
適用範囲
以下の PolarDB PostgreSQL Edition バージョンがサポートされています:
PostgreSQL 14(マイナーエンジンバージョン 2.0.14.13.26.0 以降)。
PostgreSQL 16(マイナーエンジンバージョン 2.0.16.9.8.0 以降)。
マイナーエンジンバージョン番号は、コンソールのこちらで確認できます。また、SHOW polardb_version; 文を実行しても確認可能です。ご利用のマイナーエンジンバージョンが要件を満たさない場合は、マイナーエンジンバージョンのスペックアップを行ってください。
用語
時系列データ: 時系列順に記録されたデータポイントの列です。各データポイントには数値とタイムスタンプが含まれます。時系列データは、変数が時間とともにどのように変化するかを示し、金融、気象モニタリング、センサネットワーク、Web トラフィック分析、疾病追跡など幅広い分野で利用されます。主な要素は以下のとおりです:
タイムスタンプ: 各データポイントの正確な時刻を示すマーカー。
観測値: 各タイムスタンプにおける測定または記録された値。
順序性: データポイントは時系列順に並べられます。この自然な順序性により、時系列分析が可能になります。
トレンドおよび季節性: 一般的なパターンには、長期的なトレンド、季節的な変動、周期的動作、ランダムノイズなどがあります。
メトリック: 時間とともに追跡される定量可能な測定値(例:温度、株価、ネットワークトラフィックなど)。メトリックは、動作パターンの把握、将来値の予測、異常の迅速な検出に役立ちます。
集約: 高頻度の時系列データを低頻度の要約に結合する処理です。たとえば、1 秒ごとの読み取り値を 1 分ごとの平均値に変換します。集約は、データ量を削減しつつ主要なトレンドを保持します。次元削減、トレンド分析、異常検出、予測モデリングをサポートします。
ダウンサンプリング: 時系列データのサンプリング周波数を低下させながら、その主な特徴やトレンドを保持する処理です。一般的な手法は以下のとおりです:
デシメーション: N 番目のデータポイントのみを保持します。たとえば、1 秒間に 10 サンプルを 1 秒間に 2 サンプルに減らす場合、5 つのポイントのうち最初の 1 つだけを保持します。シンプルですが、高周波数の詳細を失う可能性があります。
平均化: N 個の連続するポイントの平均値を新しいポイントとして計算します。データを滑らかにし、ノイズを低減しますが、急激な変化をぼかす可能性があります。
中央値: 平均値の代わりに中央値を使用します。外れ値が存在する場合にロバスト性が高まります。
最大値/最小値: 各グループ内の最高値または最低値を保持します。ピークまたは谷を捉えるのに有用です。
再サンプリング: 新しい時系列グリッド上にデータを補間した後、一様にサンプリングします。線形補間、ニアレストネイバー補間、キュービック補間などの手法があります。柔軟性が高く、形状をよく保持します。
モデルベースのダウンサンプリング: 統計的または機械学習モデル(ARIMA や LSTM など)を使用して、低いサンプリングレートでの値を予測します。よりスマートですが、計算コストが高くなります。
GanosBase TSDB と TimescaleDB の比較
TimescaleDB: PostgreSQL を基盤とするオープンソースの時系列データベースです。センサデータ、メトリック、金融データなどの時系列ワークロード向けに最適化されています。完全な PostgreSQL SQL サポートを維持しつつ、高速な書き込み、効率的なストレージ、複雑なクエリを実現します。
GanosBase TSDB は、オープンソースの時系列データベース TimescaleDB を基盤として開発された時系列エンジンです。PolarDB for PostgreSQL クラスター用のプラグインとして提供され、PolarDB の共有ストレージ、シングルライター・マルチリーダー、バックアップ、回復などのすべての機能を完全に継承します。
主な違い
両者の主な違いは機能セットにあります。TimescaleDB Apache 2 Edition は Apache 2.0 ライセンスでリリースされており、自由な利用およびサービス提供が許可されますが、コア機能のみが含まれます。
一方、GanosBase TSDB は TimescaleDB を完全にサポートし、連続集約、データ圧縮、ホットデータおよびコールドデータ向けの OSS レイヤードストレージなどの高度な機能を追加しています。
時系列データベースの有効化
PolarDB for PostgreSQL クラスターで時系列データベース機能を有効にするには、shared_preload_libraries パラメーターに timescaledb を追加します。このパラメーターはコンソールで変更できます。shared_preload_libraries パラメーターを変更する。
shared_preload_libraries パラメーターの変更によりクラスターが再起動します。変更前に業務への影響を十分に検討してください。
プラグインの作成
プラグインのアップグレード
ハイパーテーブル
ハイパーテーブルは、時系列データ向けに最適化された特殊なテーブルタイプです。標準テーブルに対するすべての操作をハイパーテーブルに対しても実行できます。
特徴
ハイパーテーブルは、自動的に時系列でデータをパーティション分割します。通常のテーブルと同じように操作できますが、時系列管理を容易にする追加機能を提供します。
ハイパーテーブルは通常のテーブルと共存します。時系列データをハイパーテーブルに格納することで、書き込みおよびクエリのパフォーマンスを向上させることができます。また、ハイパーテーブルに対して時系列関数も使用できます。
ハイパーテーブルは時系列データを時系列でパーティション分割します。データベースがバックグラウンドでパーティションの設定およびメンテナンスを自動的に処理します。
ハイパーテーブルの作成
以下の構文を使用して、標準テーブルをハイパーテーブルに変換します:
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 | いいえ | ハイパーテーブルが配置されるスキーマ。 |
associated_table_prefix | いいえ | チャンクテーブルのプレフィックス。チャンクは自動的に作成されます。 |
chunk_time_interval | いいえ | チャンクの時間間隔。デフォルトは 7 日です。 |
create_default_indexes | いいえ | タイムカラムに B-tree インデックスを作成するかどうか。オプション:
|
if_not_exists | いいえ | ハイパーテーブルが既に存在する場合にエラーを発生させるかどうか。オプション:
|
partitioning_func | いいえ | 空間パーティション分割を使用する場合のカスタム空間パーティション分割関数。 |
migrate_data | いいえ | ソーステーブルから既存のデータをハイパーテーブルに転送するかどうか。オプション:
|
chunk_target_size | いいえ | チャンクの目標サイズ(例: |
chunk_sizing_func | いいえ |
|
time_partitioning_func | いいえ | 時系列パーティション分割のためのパーティション関数を指定します。 |
ハイパーテーブルのパーティション分割
ハイパーテーブルを作成および使用すると、自動的に時系列でデータがパーティション分割されます。また、空間でもパーティション分割できます。
各ハイパーテーブルは、チャンクと呼ばれる子テーブルで構成されます。各チャンクは特定の時間範囲をカバーし、その範囲内のデータのみを格納します。ハイパーテーブルが空間でもパーティション分割されている場合、各チャンクは空間値のサブセットをカバーします。
ハイパーテーブル内の各チャンクは、特定の時間範囲のデータのみを格納します。まだチャンクがない時間範囲のデータを挿入すると、システムが自動的にそのデータを格納するためのチャンクを作成します。
デフォルトでは、データは 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);標準テーブルのレプリケーション IDENTITY を DEFAULT に設定します:
ALTER TABLE transaction_data replica IDENTITY DEFAULT;標準テーブルをハイパーテーブルに変換します:
SELECT create_hypertable('transaction_data', 'tm', chunk_time_interval => INTERVAL '1 day');説明テーブルにデータが含まれている場合は、
migrate_dataパラメーターを追加し、trueに設定してください。テーブルのデータ量が大きい場合、変換に長時間を要する可能性があります。(任意)ハイパーテーブルのパーティション間隔を変更します。
SELECT set_chunk_time_interval('transaction_data', chunk_time_interval => INTERVAL '2 day');
連続集約
連続集約は、自動化された事前計算メカニズムです。1 時間ごとの平均値など、あらかじめ定義された集約を定期的または継続的に更新し、複雑なクエリを事前計算結果の高速な読み取りに変換します。マテリアライズドビューと同様に、時系列データ向けに最適化されており、増分更新をサポートします。これにより、履歴データの再計算を回避し、大規模データセットに対するクエリの高速化を実現します。
メリット
クエリの高速化: 生データをスキャンする代わりに、事前計算結果を読み取ります。
リソース使用量の削減: 実時間の CPU およびメモリ負荷を低減します。
自動メンテナンス: 手動のトリガーなしで、新規および既存のデータに対する集約を更新します。
連続集約の作成
CREATE MATERIALIZED VIEW transaction_min_cagg
WITH (timescaledb.continuous) -- 連続集約として宣言
AS
SELECT id,
time_bucket(INTERVAL '1 min', tm) AS bucket, -- 1 分間隔で集約
AVG(price),
MAX(price),
MIN(price)
FROM transaction_data
GROUP BY id, bucket;連続集約のストレージ
結果は専用のマテリアライズドビューに格納されます。データは、基盤となるハイパーテーブルのパーティション分割に一致する、時系列に整列されたチャンクに格納されます。
ジョブのスケジューリング
連続集約は、データのリフレッシュを実行するスケジュールされたジョブに依存します。リフレッシュは自動的または手動でトリガーできます。
ジョブの作成
関数またはストアドプロシージャを自動的にスケジュールするジョブを作成します。
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
);パラメーターの説明:
パラメーター名 | 説明 |
proc | 実行する関数またはストアドプロシージャの名前または OID。 |
schedule_interval | ジョブ実行間の間隔。 |
config | ジョブ構成パラメーター。 |
initial_start | ジョブの開始時刻。デフォルトは現在時刻です。 |
scheduled | 自動実行するかどうか。デフォルトは |
check_config |
|
fixed_schedule | 固定間隔で実行するかどうか。デフォルトは |
timezone | タイムゾーン。デフォルトは NULL です。 |
例
ベースデータを準備します。実行するストアドプロシージャを作成します。
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 $$;ジョブを作成します。ジョブの
idを返します。SELECT add_job('user_defined_action','1 hour'); SELECT add_job('user_defined_action','1h', initial_start => '2024-03-11 00:00:00');
ジョブの変更
既存のジョブを更新します。
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
);パラメーターの説明:
これは主なパラメーターのみをリストしています。詳細については、「ジョブの作成パラメーター」をご参照ください。
パラメーター名 | 説明 |
job_id | 変更対象のタスクの ID。 |
max_runtime | ジョブの最大実行時間。デフォルトは NULL です。 |
max_retries | 失敗後の最大リトライ回数。デフォルトは NULL です。 |
retry_period | 失敗後のリトライ間隔。デフォルトは NULL です。 |
例
SELECT alter_job(1002, schedule_interval => INTERVAL '2 hours');ジョブの手動実行
既存のジョブを手動でトリガーします。
void run_job(job_id int);パラメーターの説明:
パラメーター名 | 説明 |
job_id | 実行対象のタスクの ID。 |
例
CALL run_job(1002);ジョブの削除
ジョブを削除します。
void delete_job(job_id int);パラメーターの説明:
パラメーター名 | 説明 |
job_id | 削除対象のジョブの |
例
SELECT delete_job(1002);連続集約のリフレッシュ
手動リフレッシュ
以下のストアドプロシージャを使用して、連続集約を手動でリフレッシュします。
refresh_continuous_aggregate(
cagg REGCLASS,
window_start "any",
window_end "any"
);パラメーターの説明:
パラメーター名 | 説明 |
cagg | リフレッシュ対象の連続集約の名前または OID。 |
window_start | リフレッシュウィンドウの開始時刻。タイムカラムの型と一致する必要があります。
|
window_end | リフレッシュウィンドウの終了時刻。タイムカラムの型と一致する必要があります。 最新のデータまでリフレッシュする場合は、NULL に設定します。 |
注意事項
リフレッシュウィンドウは、テーブル内のタイムバケットと正確に整列している必要があります。完全にカバーされたバケットのみがリフレッシュされ、部分的なバケットはスキップされます。
refresh_continuous_aggregateの複数回の呼び出しでウィンドウが重複する場合、新しいデータまたは変更されたデータを含むバケットのみが更新されます。refresh_continuous_aggregateはストアドプロシージャです。CALL を使用して呼び出してください。
例
CALL refresh_continuous_aggregate('transaction_min_cagg', '2024-03-11 00:00:00+08'::timestamptz, NULL);自動リフレッシュ
自動リフレッシュは、以下の 2 つの方法で設定できます。
add_continuous_aggregate_policy の使用
リアルタイムクエリ
連続集約をクエリする際、リアルタイムクエリが有効になっていない限り、完了した集約のみにアクセスできます。リアルタイムクエリを有効化すると、集約される前に新しく取り込まれたデータを読み取ることができます。
リアルタイムクエリの有効化
ALTER MATERIALIZED VIEW transaction_min_cagg SET (timescaledb.materialized_only = false);リアルタイムクエリの無効化
ALTER MATERIALIZED VIEW transaction_min_cagg SET (timescaledb.materialized_only = true);
ネスト集約
ネスト集約は、他の連続集約の上位に連続集約を構築するものです。たとえば、時間単位の集約から日単位の集約を作成したり、日単位の集約から月単位の集約を作成したりします。これにより、冗長性が削減され、パフォーマンスが向上します。
第 1 層目の集約(ここでは分単位)を作成します。
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 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);
時系列データ圧縮
時系列パーティションが既存データと判断された場合、時系列データ圧縮を有効化します。GanosBase TSDB は、テーブル全体または個別のパーティションの圧縮をサポートしています。圧縮により、ストレージ容量を 70 % 以上削減でき、ストレージコストを大幅に低減できます。
圧縮されたデータは読み取り専用です。
プラグインのアンインストール
DROP EXTENSION ganos_tsdb CASCADE;
DROP EXTENSION timescaledb CASCADE;