時系列コレクションのベストプラクティス
項目一覧
- 圧縮のベストプラクティス
- ドキュメントから空のオブジェクトと配列を含むフィールドを省略
- 数値データを小数点以下の桁に丸めます
- 挿入のベストプラクティス
- ドキュメントのバッチ書込み (write)
- ドキュメントでの一貫したフィールド順序の使用
- クライアント数の増加
- シャーディングのベストプラクティス
metaField
をシャードキーとして使用する- クエリのベストプラクティス
- コレクションの作成時に戦略的な
metaField
を設定する - 適切なバケット粒度の設定
- セカンダリ インデックスの作成
- 追加インデックスのベストプラクティス
- サブフィールドでの
metaField
のクエリ - Distinct() の代わりに $group を使用する
このページでは、時系列コレクションのパフォーマンスとデータ使用量を向上させるためのベストプラクティスについて説明します。
圧縮のベストプラクティス
時系列コレクションのデータ圧縮を最適化するには、次のアクションを実行します。
ドキュメントから空のオブジェクトと配列を含むフィールドを省略
データに空のオブジェクト、配列、または文字列が含まれている場合は、圧縮を最適化するために、ドキュメントから空のフィールドを取り除きます。
例えば、次のドキュメントについて考えてみます。
{ timestamp: ISODate("2020-01-23T00:00:00.441Z"), coordinates: [1.0, 2.0] }, { timestamp: ISODate("2020-01-23T00:00:10.441Z"), coordinates: [] }, { timestamp: ISODate("2020-01-23T00:00:20.441Z"), coordinates: [3.0, 5.0] }
coordinates
値が入力されたフィールドと、配列が空の coordinates
フィールドは、コンプレッサーのスキーマが変更されます。スキーマの変更により、シーケンス内の 2 番目と 3 番目のドキュメントは非圧縮のままになります。
次のドキュメントに示すように、空の値を持つフィールドを取り除いて、圧縮を最適化します。
{ timestamp: ISODate("2020-01-23T00:00:00.441Z"), coordinates: [1.0, 2.0] }, { timestamp: ISODate("2020-01-23T00:00:10.441Z") }, { timestamp: ISODate("2020-01-23T00:00:20.441Z"), coordinates: [3.0, 5.0] }
数値データを小数点以下の桁に丸めます
数値データをアプリケーションに必要な精度に四捨五入します。数値データを四捨五入して小数点の桁数を減らすと、圧縮率が向上します。
挿入のベストプラクティス
時系列コレクションの挿入パフォーマンスを最適化するには、以下の操作を実行します。
ドキュメントのバッチ書込み (write)
複数のドキュメントを挿入する場合
ネットワーク ラウンドトリップを回避するには、複数の
insertOne()
ステートメントではなく、単一のinsertMany()
ステートメントを使用します。可能であれば、同じバッチに同一の
metaField
値を含むデータを挿入します。ordered
パラメータをfalse
に設定します。
たとえば、sensor A
と sensor B
の 2 つの metaField
値に対応する 2 つのセンサーがある場合、1 つのセンサーからの複数の測定値を含むバッチでは、測定ごとに 1 回の挿入ではなく、1 回の挿入のコストが発生します。
次の操作では 6 つのドキュメントが挿入されますが、ドキュメントはセンサー順に並べられるため、挿入コストは 2 回(metaField
値ごとに1回)しかかかりません。パフォーマンスを向上させるために、ordered
パラメータは false
に設定されています。
db.temperatures.insertMany( [ { metaField: { sensor: "sensorA" }, timestamp: ISODate("2021-05-18T00:00:00.000Z"), temperature: 10 }, { metaField: { sensor: "sensorA" }, timestamp: ISODate("2021-05-19T00:00:00.000Z"), temperature: 12 }, { metaField: { sensor: "sensorA" }, timestamp: ISODate("2021-05-20T00:00:00.000Z"), temperature: 13 }, { metaField: { sensor: "sensorB" }, timestamp: ISODate("2021-05-18T00:00:00.000Z"), temperature: 20 }, { metaField: { sensor: "sensorB" }, timestamp: ISODate("2021-05-19T00:00:00.000Z"), temperature: 25 }, { metadField: { sensor: "sensorB" }, timestamp: ISODate("2021-05-20T00:00:00.000Z"), temperature: 26 } ], { "ordered": false } )
ドキュメントでの一貫したフィールド順序の使用
ドキュメントで一貫したフィールド順序を使用すると、挿入パフォーマンスが向上します。
たとえば、フィールドの順序がすべて同じ次のドキュメントを挿入すると、最適な挿入パフォーマンスが得られます。
{ _id: ObjectId("6250a0ef02a1877734a9df57"), timestamp: ISODate("2020-01-23T00:00:00.441Z"), name: "sensor1", range: 1 }, { _id: ObjectId("6560a0ef02a1877734a9df66"), timestamp: ISODate("2020-01-23T01:00:00.441Z"), name: "sensor1", range: 5 }
対照的に、次のドキュメントはフィールドの順序が異なるため、最適な挿入パフォーマンスを得られません。
{ range: 1, _id: ObjectId("6250a0ef02a1877734a9df57"), name: "sensor1", timestamp: ISODate("2020-01-23T00:00:00.441Z") }, { _id: ObjectId("6560a0ef02a1877734a9df66"), name: "sensor1", timestamp: ISODate("2020-01-23T01:00:00.441Z"), range: 5 }
クライアント数の増加
コレクションにデータを書き込むクライアントの数を増やすと、パフォーマンスが向上します。
シャーディングのベストプラクティス
時系列コレクションのシャーディングを最適化するには、次のアクションを実行します。
metaField
をシャードキーとして使用する
metaField
を使用してコレクションをシャードすると、時系列コレクションのシャードキーとして十分な濃度が得られます。
注意
MongoDB 8.0 以降、時系列コレクションで timeField
をシャードキーとして使用することは非推奨です。
クエリのベストプラクティス
時系列コレクションのクエリを最適化するには、次のアクションを実行します。
コレクションの作成時に戦略的な metaField
を設定する
metaField
の選択は、アプリケーションのクエリの最適化に最も大きな影響を与えます。
metaField の一部として、ほとんどまたはまったく変更されないフィールドを選択します。
可能であれば、metaField の一部として、フィルター式に一般的な識別子またはその他の安定値を選択します。
metaField の一部としてフィルタリングに使用されていないフィールドを選択することは避けてください。 代わりに、それらのフィールドを測定値として使用してください。
詳細については、「metaField の考慮事項」を参照してください。
適切なバケット粒度の設定
時系列コレクションを作成すると、MongoDB は受信した時系列データをバケットにグループ化します。 粒度を正確に設定することで、データの取り込み率に基づいてデータがバケット化される頻度を制御します。
MongoDB 6.3 以降では、カスタム バケット パラメーターbucketMaxSpanSeconds
とbucketRoundingSeconds
を使用してバケット境界を指定し、時系列データのバケット化方法をより正確に制御できます。
同じデータソースからの受信測定値間の時間範囲に最も一致するようにgranularity
またはカスタム バケット パラメーターを設定することでパフォーマンスを向上できます。 たとえば、数百万のセンサーから気象データを記録しているものの、各センサーからのデータは 5 分に 1 回のみ記録する場合は、 granularity
を"minutes"
に設定するか、カスタム バケット パラメータを300
(秒)に設定できます。
この場合、 granularity
をhours
に設定すると、最大 1 か月量のデータ取り込みイベントが単一のバケットにグループ化され、トラバース時間が長くなり、クエリが遅くなります。 これをseconds
に設定すると、ポーリング間隔ごとに複数のバケットが使用されます。その多くには 1 つのドキュメントのみが含まれる場合があります。
次の表は、特定のgranularity
値を使用する場合に 1 バケットのデータに含まれる最大時間間隔を示しています。
granularity | granularity バケット制限 |
---|---|
seconds | 1 時間 |
minutes | 24 時間 |
hours | 30 日間 |
セカンダリ インデックスの作成
クエリのパフォーマンスを向上させるには、一般的なクエリ パターンをサポートするために1 つ以上のセカンダリ インデックスをtimeField
とmetaField
に作成します。 バージョン 6.3 以降では、MongoDB はtimeField
とmetaField
にセカンダリ インデックスを自動的に作成します。
追加インデックスのベストプラクティス
フィルタリングと等価性のために metaField インデックスを使用する。
範囲クエリには timeField やその他のインデックス付きフィールドを使用する。
一般的なインデックス戦略は、時系列コレクションにも適用される。詳細については、「インデックス戦略」を参照。
サブフィールドでの metaField
のクエリ
MongoDB は時系列コレクションの metaField
の順序を再配置します。これにより、サーバーはアプリケーションとは異なるフィールド順序でデータを保存する場合があります。metaField
がオブジェクトの場合、metaField
に対するクエリでは結果に一貫性がありません。これは、metaField
の順序がサーバーとアプリケーションによって異なる場合があるためです。時系列 metaField
でのクエリを最適化するには、metaField
全体ではなく、スカラーのサブフィールドで metaField
をクエリします。
次の例では、時系列コレクションを作成しています。
db.weather.insertMany( [ { metaField: { sensorId: 5578, type: "temperature" }, timestamp: ISODate( "2021-05-18T00:00:00.000Z" ), temp: 12 }, { metaField: { sensorId: 5578, type: "temperature" }, timestamp: ISODate( "2021-05-18T04:00:00.000Z" ), temp: 11 } ] )
sensorId
とtype
のスカラー サブフィールドに対する次のクエリは、クエリ条件に一致する最初のドキュメントを返します。
db.weather.findOne( { "metaField.sensorId": 5578, "metaField.type": "temperature" } )
出力例:
{ _id: ObjectId("6572371964eb5ad43054d572"), metaField: { sensorId: 5578, type: 'temperature' }, timestamp: ISODate( "2021-05-18T00:00:00.000Z" ), temp: 12 }
Distinct() の代わりに $group を使用する
時系列コレクションは一意のデータ構造であるため、MongoDB は個別の値に対して効率的にインデックスを作成できません。時系列コレクションで distinct
コマンドまたは db.collection.distinct()
ヘルパーメソッドを使用しないでください。代わりに、$group
集計を使用して、ドキュメントを個別の値でグループ化します。
たとえば、meta.project = 10
であるドキュメントに対して meta.type
の値を個別でクエリするには、次のようにします。
db.foo.distinct("meta.type", {"meta.project": 10})
次を使用します。
db.foo.createIndex({"meta.project":1, "meta.type":1}) db.foo.aggregate([{$match: {"meta.project": 10}}, {$group: {_id: "$meta.type"}}])
これは、次のように機能します。