主キーに基づいて UPDATE 操作を実行する場合、または大規模なデータセットに対して範囲フィルター条件を含むクエリを実行する場合は、テーブルのイベントタイム列を設定できます。システムは、イベントタイム列に基づいてデータファイルをソートし、データファイルを結合します。これにより、重複ファイルが削減され、できるだけ多くのファイルが除外されます。このようにして、クエリの効率が向上します。イベントタイム列を適切に設定することで、データベースの処理効率、クエリ速度、および全体的なパフォーマンスを向上させることができます。このトピックでは、Hologres でテーブルのイベントタイム列を設定する方法について説明します。
概要
Hologres V0.9 では、segment_key プロパティの名前がデフォルトで event_time_column に変更されました。ただし、segment_key プロパティは Hologres V0.9 以前でも使用できます。
イベントタイム列は、次のシナリオに適用できます。
等価条件を含む、範囲フィルター条件を含むクエリ。
主キーに基づく UPDATE 操作。
テーブルを作成するときに、テーブルのイベントタイム列を指定する必要があります。イベントタイム列を設定するには、次の構文を使用します。
-- Hologres V2.1 以降でサポートされている構文
CREATE TABLE <table_name> (...) WITH (event_time_column = '[<columnName>[,...]]');
-- すべての Hologres バージョンでサポートされている構文
BEGIN;
CREATE TABLE <table_name> (...);
call set_table_property('<table_name>', 'event_time_column', '[<columnName> [,...]]');
COMMIT;次の表は、上記の構文のパラメーターを示しています。
パラメーター | 説明 |
table_name | イベントタイム列を設定するテーブルの名前。 |
columnName | イベントタイム列として設定する列の名前。 |
使用上の注意
タイムスタンプ列など、データが単調に増加または減少する列をイベントタイム列として設定することをお勧めします。 event_time_column プロパティは、ログ列やトラフィック列など、時間と強い相関関係のある列に適用できます。このプロパティを適切に設定することで、クエリのパフォーマンスを向上させることができます。複数のファイルがマージされた後、イベントタイム列のデータが順序付けられていない場合、各ファイルのデータには識別機能がなく、順序付けられていません。この場合、データフィルタリングの効果は低くなります。
テーブルにデータが単調に増加または減少する列が含まれていない場合は、
update_time列を追加し、イベントタイム列として使用できます。 UPSERT 操作を実行するたびに、現在の時刻が update_time 列に書き込まれます。イベントタイム列に基づくデータクエリは、左端一致の原則に従います。したがって、テーブルに複数のイベントタイム列を指定しないことをお勧めします。指定した場合、イベントタイム列に基づくデータクエリが一部のシナリオで高速化されない可能性があります。ほとんどの場合、テーブルに 1 つまたは 2 つのイベントタイム列を指定することをお勧めします。
制限事項
テーブルのイベントタイム列は、NOT NULL 制約を満たす必要があります。 Hologres V1.3.20 から V1.3.27 では、NULL 値を含む列をイベントタイム列として指定できます。 Hologres V1.3.28 以降では、NULL 値を含む列をイベントタイム列として指定することはできません。これは、イベントタイム列に NULL 値が含まれていると、データの精度に悪影響を与える可能性があるためです。ビジネス要件に基づいて NULL 値を含む列をイベントタイム列として指定する必要がある場合は、CREATE TABLE ステートメントの前に次の SET コマンドを追加できます。
set hg_experimental_enable_nullable_segment_key = true;SQL ステートメントを実行して、イベントタイム列に NULL 値が含まれているかどうかを確認できます。ステートメントの例:
WITH t_base AS ( SELECT * FROM hologres.hg_table_info WHERE collect_time::date = CURRENT_DATE ), t1 AS ( SELECT db_name, schema_name, table_name, jsonb_array_elements(table_meta::jsonb -> 'columns') cols FROM t_base ), t2 AS ( SELECT db_name, schema_name, table_name, cols ->> 'name' col_name FROM t1 WHERE cols -> 'nullable' = 'true'::jsonb ), t3 AS ( SELECT db_name, schema_name, table_name, regexp_replace(regexp_split_to_table(table_meta::jsonb ->> 'segment_key', ','), ':asc|:desc$', '') segment_key_col FROM t_base WHERE table_meta::jsonb -> 'segment_key' IS NOT NULL ) SELECT CURRENT_DATE, t3.db_name, t3.schema_name, t3.table_name, jsonb_build_object('nullable_segment_key_column', string_agg(t3.segment_key_col, ',')) as nullable_segment_key_column FROM t2, t3 WHERE t3.db_name = t2.db_name AND t3.schema_name = t2.schema_name AND t3.table_name = t2.table_name AND t2.col_name = t3.segment_key_col GROUP BY t3.db_name, t3.schema_name, t3.table_name;event_time_column プロパティは変更できません。プロパティを変更する場合は、別のテーブルを作成してください。
行指向テーブルの event_time_column プロパティは設定できません。
デフォルトでは、列指向テーブルの TIMESTAMP または TIMESTAMPTZ データ型の最初の非 NULL 列がイベントタイム列として使用されます。そのような列が存在しない場合、デフォルトでは DATE データ型の最初の非 NULL 列がイベントタイム列として使用されます。 Hologres V0.9 より前のバージョンでは、デフォルトでテーブルにイベントタイム列は指定されていません。
DECIMAL、NUMERIC、FLOAT、DOUBLE、ARRAY、JSON、JSONB、BIT、MONEY データ型、およびその他の複合データ型の列はサポートされていません。
仕組
次の図は、シャード内のデータの書き込み方法を示しています。
シャード内のデータは、最初にメモリテーブルに書き込まれます。最大の書き込み効率を実現するために、追加専用モードを使用してデータを書き込みます。メモリテーブルのサイズは制限されています。メモリテーブルがいっぱいになると、Hologres はメモリテーブル内のデータをファイルに非同期的にフラッシュします。
書き込み効率を最大化するために、データは追加専用モードでファイルに書き込まれ、ファイルの数は時間の経過とともに増加します。この場合、Hologres は定期的にファイルをマージします。 event_time_column プロパティが設定されている場合、Hologres はプロパティで指定された範囲に基づいてファイルをソートし、データの範囲が隣接するファイルを選択して、これらのファイルをマージします。これにより、ファイル間の重複が減り、クエリ中に不要なファイルが除外されます。この場合、クエリの効率が向上します。
ファイルは、イベントタイム列に基づいてソートされます。イベントタイム列に基づくデータクエリは、左端一致の原則に従います。列
a、b、cをイベントタイム列として指定した場合、列a、b、cのクエリ、または列a と bのクエリは、イベントタイム列にヒットします。列a と cをクエリする場合、列aのクエリのみがイベントタイム列にヒットします。列b と cをクエリする場合、クエリはイベントタイム列にヒットしません。
上記の内容は、次のシナリオでイベントタイム列を使用してデータクエリを高速化できることを示しています。
等価条件を含む、範囲フィルター条件を含むクエリ。
クエリ対象の列がイベントタイム列として指定されている場合、Hologres はデータのスキャン時に、範囲フィルター条件に基づいてファイル内の列の統計 (最小/最大) を比較して、必要なファイルをフィルタリングします。これにより、クエリプロセスが高速化されます。
主キーに基づく UPDATE 操作。
Hologres では、
UPDATE操作は、DELETE操作とINSERT操作の組み合わせに相当します。テーブルに主キーを設定した後、UPDATE ステートメントまたは INSERT ON CONFLICT ステートメントを実行すると、Hologres は主キーに基づいて、ターゲットテーブルに指定したイベントタイム列の値を見つけます。次に、Hologres はイベントタイム列に基づいて、既存のデータが存在するファイルを見つけます。最後に、Hologres は既存のデータを見つけて、データを DELETE としてマークします。 UPDATE ステートメントと INSERT ON CONFLICT ステートメントの詳細については、「UPDATE」または「INSERT ON CONFLICT(UPSERT)」をご参照ください。適切なイベントタイム列は、既存のデータが存在するファイルをすばやく見つけるのに役立ちます。これにより、書き込みパフォーマンスが向上します。次のシナリオでは、データクエリ中に多数のファイルをスキャンする必要があります。(1) 列指向テーブルにイベントタイム列が指定されていない。 (2) 設定したイベントタイム列が適切でない。 (3) 設定したイベントタイム列が時間と強い相関関係がなく、順序付けられていないデータが含まれている。この場合、多数の I/O 操作が実行され、CPU 負荷が高くなります。その結果、書き込みパフォーマンスとインスタンスの負荷に悪影響が及びます。
例
テーブルを作成するときに、列をイベントタイム列として設定します。
Hologres V2.1 以降でサポートされている構文:
CREATE TABLE tbl_segment_test ( a int NOT NULL, b timestamptz NOT NULL ) WITH ( event_time_column = 'b' ); INSERT INTO tbl_segment_test values (1,'2022-09-05 10:23:54+08'), (2,'2022-09-05 10:24:54+08'), (3,'2022-09-05 10:25:54+08'), (4,'2022-09-05 10:26:54+08'); EXPLAIN SELECT * FROM tbl_segment_test WHERE b > '2022-09-05 10:24:54+08';すべての Hologres バージョンでサポートされている構文:
BEGIN; CREATE TABLE tbl_segment_test ( a int NOT NULL, b timestamptz NOT NULL ); CALL set_table_property('tbl_segment_test', 'event_time_column', 'b'); COMMIT; INSERT INTO tbl_segment_test VALUES (1,'2022-09-05 10:23:54+08'), (2,'2022-09-05 10:24:54+08'), (3,'2022-09-05 10:25:54+08'), (4,'2022-09-05 10:26:54+08'); EXPLAIN SELECT * FROM tbl_segment_test WHERE b > '2022-09-05 10:24:54+08';
EXPLAIN ステートメントを実行することで、実行プランをクエリできます。実行プランに
Segment Filterが含まれている場合、クエリはイベントタイム列にヒットします。
テーブルを作成するときに、複数の列をイベントタイム列として設定します。
Hologres V2.1 以降でサポートされている構文:
CREATE TABLE tbl_segment_test_2 ( a int NOT NULL, b timestamptz NOT NULL ) WITH ( event_time_column = 'a,b' ); INSERT INTO tbl_segment_test_2 VALUES (1,'2022-09-05 10:23:54+08'), (2,'2022-09-05 10:24:54+08'), (3,'2022-09-05 10:25:54+08'), (4,'2022-09-05 10:26:54+08') ; -- クエリはイベントタイム列にヒットしません。 SELECT * FROM tbl_segment_test_2 WHERE b > '2022-09-05 10:24:54+08'; -- クエリはイベントタイム列にヒットします。 SELECT * FROM tbl_segment_test_2 WHERE a = 3 and b > '2022-09-05 10:24:54+08'; SELECT * FROM tbl_segment_test_2 WHERE a > 3 and b < '2022-09-05 10:26:54+08'; SELECT * FROM tbl_segment_test_2 WHERE a > 3 and b > '2022-09-05 10:24:54+08';すべての Hologres バージョンでサポートされている構文:
BEGIN; CREATE TABLE tbl_segment_test_2 ( a int NOT NULL, b timestamptz NOT NULL ); CALL set_table_property('tbl_segment_test_2', 'event_time_column', 'a,b'); COMMIT; INSERT INTO tbl_segment_test_2 VALUES (1,'2022-09-05 10:23:54+08'), (2,'2022-09-05 10:24:54+08'), (3,'2022-09-05 10:25:54+08'), (4,'2022-09-05 10:26:54+08') ; -- クエリはイベントタイム列にヒットしません。 SELECT * FROM tbl_segment_test_2 WHERE b > '2022-09-05 10:24:54+08'; -- クエリはイベントタイム列にヒットします。 SELECT * FROM tbl_segment_test_2 WHERE a = 3 and b > '2022-09-05 10:24:54+08'; SELECT * FROM tbl_segment_test_2 WHERE a > 3 and b < '2022-09-05 10:26:54+08'; SELECT * FROM tbl_segment_test_2 WHERE a > 3 and b > '2022-09-05 10:24:54+08';
関連情報
ビジネスクエリシナリオに基づいてテーブルプロパティを設定する方法の詳細については、「シナリオ固有のテーブル作成とチューニングのガイド」をご参照ください。
Hologres 内部テーブルの DDL ステートメントの詳細については、以下のトピックをご参照ください。