本トピックでは、時系列テーブルのインデックスメカニズムについて説明し、効率的なクエリを作成するためのベストプラクティスを紹介します。
背景情報
時系列データのデータモデルの詳細については、「時系列テーブルの設計」をご参照ください。データは時系列によって編成されます。時系列テーブルでは、TAG とマークされたすべての列 (タグ列) にインデックスが作成されます。これらの列は、各データポイントが属する時系列を指定し、データソースを示します。
次の図は、時系列テーブル内で同じ時系列に属するデータの例を示しています。詳細については、「時系列テーブルの設計」をご参照ください。
タグ列の値が変更されると、データは異なる時系列に属することになります。通常、時系列は時系列データを生成する特定のデータソースを識別します。
LindormTSDB は、各タグ列に対して転置インデックスを作成します。このインデックスは、列名と値をキーとして使用し、そのキーと値のペアを含むすべての時系列にインデックスを付けます。これにより、システムは特定のタグに一致する時系列のセットを迅速に見つけることができます。データが書き込まれると、次の図に示すように、時系列テーブルの転置インデックスが進化します。
タイムスタンプ列に対して、LindormTSDB は自動的にブロックレンジインデックス (BRIN) を作成し、大量の時系列データの中から必要なデータ範囲を迅速に見つけます。ただし、LindormTSDB はフィールド列にはインデックスを作成しません。
推奨事項
LindormTSDB のインデックスメカニズムに基づき、時系列テーブルをクエリする際には、次の点を考慮してください。
クエリには、タグ列の等価フィルターと時間範囲フィルターを含めてください。フィールド列のみでフィルターするクエリは避けてください。
クエリに複数のタグ列のフィルターが含まれ、それらがマップする時系列セットに包含関係がある場合は、最も選択性の高いタグフィルターのみを保持してください。例えば、サンプルデータでは、id 列は city 列よりも選択性が高くなっています。
広い時間範囲をカバーするクエリは、大量のデータをスキャンする可能性があり、クエリパフォーマンスが低下します。パフォーマンスを向上させるには、フィルターで時間範囲を絞り込んでください。
クエリ例
以下の例の結果を再現するには、SQL スクリプトをダウンロードし、それを使用してサンプルデータをロードしてください。
時間範囲内の生データのクエリ
次の文を使用して、2019-04-18 10:00:00 から 2019-04-18 10:30:00 までに Yuhang 地区のデバイスから報告されたすべての SO2 メトリックをクエリします。
SELECT id, so2 FROM aqm WHERE district='yuhang' AND time >= '2019-04-18 10:00:00' AND time < '2019-04-18 10:30:00';次の結果が返されます。
+---------+------+
| id | so2 |
+---------+------+
| HY00003 | 10 |
| HY00003 | 10.3 |
| HY00003 | 10.3 |
| HY00003 | 10.1 |
| HY00003 | 10.1 |
| HY00003 | 10.1 |
| HY00003 | 10.1 |
| HY00003 | 10.1 |
| HY00003 | 10.3 |
| HY00003 | 10.2 |
| HY00001 | 10 |
| HY00001 | 10.5 |
| HY00001 | 10 |
| HY00001 | 10.3 |
+---------+------+
14 rows in set (444 ms)タグ列の値のクエリ
多数の同様のデバイスから単一の時系列データテーブルにデータを取り込んだ後、それらのデバイスの特定のタグの値をクエリする必要がある場合があります。例えば、次の SQL ステートメントを使用して、aqm 時系列データテーブルにデータを送信するすべての空気品質モニタリングデバイスのデバイス id をクエリできます。
SELECT DISTINCT(id) FROM aqm;次の結果が返されます。
lindorm> SELECT DISTINCT(id) FROM aqm;
+----------+
| |
+----------+
| HY00001 |
| HY00002 |
| HY00003 |
| HY00004 |
+----------+
4 rows in set (61 ms)タグ列のクエリは、ストレージエンジンレベルでデフォルトでタグインデックスを使用するため、全表スキャンによるパフォーマンスの問題を回避できます。ただし、タグのカーディナリティが高い (一意の値の数が多い) 場合、インデックス付きのクエリでも遅くなる可能性があります。
ダウンサンプリングクエリ
2019-04-18 10:00:00 から 2019-04-18 10:30:00 までの間に Yuhang 地区のデバイスから報告された PM2.5 と SO2 の平均メトリックを 5 分の粒度でクエリします。
SELECT id, time, avg(pm2_5) AS avg_pm2_5, avg(so2) AS avg_so2 FROM aqm WHERE district='yuhang' AND time >= '2019-04-18 10:00:00' AND time < '2019-04-18 10:30:00' SAMPLE BY 5m;次の結果が返されます。
+----------+-----------------------------+------------+---------+
| id | time | avg_pm2_5 | avg_so2 |
+----------+-----------------------------+------------+---------+
| HY00003 | 2019-04-18T10:00:00+08:00 | 31.26 | 10.16 |
| HY00003 | 2019-04-18T10:05:00+08:00 | 31.24 | 10.16 |
| HY00001 | 2019-04-18T10:00:00+08:00 | 31.175 | 10.2 |
+----------+-----------------------------+------------+---------+
3 rows in set (170 ms)ダウンサンプリングは、各時系列で実行される時間ベースの集約です。ダウンサンプリングクエリの詳細については、「ダウンサンプリングクエリ」をご参照ください。
デバイス間の集計データのクエリ
2019-04-18 10:00:00 から 2019-04-18 10:30:00 までの間に Yuhang 地区のデバイスから得られた PM2.5 と SO2 メトリックの 5 分間の最大平均値を計算します。
SELECT max(avg_pm2_5) AS max_avg_pm25, max(avg_so2) AS max_avg_so2 FROM (SELECT district, id, time, avg(pm2_5) AS avg_pm2_5, avg(so2) AS avg_so2 FROM aqm WHERE district='yuhang' AND time >= '2019-04-18 10:00:00' AND time < '2019-04-18 10:30:00' SAMPLE BY 5m) GROUP BY district;次の結果が返されます。
+--------------+------------+
| max_avg_pm25 | max_avg_so2 |
+--------------+------------+
| 31.26 | 10.2 |
+--------------+------------+
1 rows in set (103 ms)