Docs Menu
Docs Home
/
MongoDBマニュアル
/

時系列コレクションのベストプラクティス

項目一覧

  • 圧縮のベストプラクティス
  • ドキュメントから空のオブジェクトと配列を含むフィールドを省略
  • 数値データを小数点以下の桁に丸めます
  • 挿入のベストプラクティス
  • ドキュメントのバッチ書込み (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]
}

数値データをアプリケーションに必要な精度に四捨五入します。数値データを四捨五入して小数点の桁数を減らすと、圧縮率が向上します。

時系列コレクションの挿入パフォーマンスを最適化するには、以下の操作を実行します。

複数のドキュメントを挿入する場合

  • ネットワーク ラウンドトリップを回避するには、複数の insertOne() ステートメントではなく、単一の insertMany() ステートメントを使用します。

  • 可能であれば、同じバッチに同一の metaField 値を含むデータを挿入します。

  • orderedパラメータをfalseに設定します。

たとえば、sensor Asensor 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 を使用してコレクションをシャードすると、時系列コレクションのシャードキーとして十分な濃度が得られます。

注意

MongoDB 8.0 以降、時系列コレクションで timeField をシャードキーとして使用することは非推奨です。

時系列コレクションのクエリを最適化するには、次のアクションを実行します。

metaField の選択は、アプリケーションのクエリの最適化に最も大きな影響を与えます。

  • metaField の一部として、ほとんどまたはまったく変更されないフィールドを選択します。

  • 可能であれば、metaField の一部として、フィルター式に一般的な識別子またはその他の安定値を選択します。

  • metaField の一部としてフィルタリングに使用されていないフィールドを選択することは避けてください。 代わりに、それらのフィールドを測定値として使用してください。

詳細については、「metaField の考慮事項」を参照してください。

時系列コレクションを作成すると、MongoDB は受信した時系列データをバケットにグループ化します。 粒度を正確に設定することで、データの取り込み率に基づいてデータがバケット化される頻度を制御します。

MongoDB 6.3 以降では、カスタム バケット パラメーターbucketMaxSpanSecondsbucketRoundingSecondsを使用してバケット境界を指定し、時系列データのバケット化方法をより正確に制御できます。

同じデータソースからの受信測定値間の時間範囲に最も一致するようにgranularityまたはカスタム バケット パラメーターを設定することでパフォーマンスを向上できます。 たとえば、数百万のセンサーから気象データを記録しているものの、各センサーからのデータは 5 分に 1 回のみ記録する場合は、 granularity"minutes"に設定するか、カスタム バケット パラメータを300 (秒)に設定できます。

この場合、 granularityhoursに設定すると、最大 1 か月量のデータ取り込みイベントが単一のバケットにグループ化され、トラバース時間が長くなり、クエリが遅くなります。 これをsecondsに設定すると、ポーリング間隔ごとに複数のバケットが使用されます。その多くには 1 つのドキュメントのみが含まれる場合があります。

次の表は、特定のgranularity値を使用する場合に 1 バケットのデータに含まれる最大時間間隔を示しています。

granularity
granularity バケット制限
seconds
1 時間
minutes
24 時間
hours
30 日間

Tip

以下も参照してください。

クエリのパフォーマンスを向上させるには、一般的なクエリ パターンをサポートするために1 つ以上のセカンダリ インデックスtimeFieldmetaFieldに作成します。 バージョン 6.3 以降では、MongoDB はtimeFieldmetaFieldにセカンダリ インデックスを自動的に作成します。

  • フィルタリングと等価性のために metaField インデックスを使用する。

  • 範囲クエリには timeField やその他のインデックス付きフィールドを使用する。

  • 一般的なインデックス戦略は、時系列コレクションにも適用される。詳細については、「インデックス戦略」を参照。

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
}
] )

sensorIdtypeのスカラー サブフィールドに対する次のクエリは、クエリ条件に一致する最初のドキュメントを返します。

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
}

時系列コレクションは一意のデータ構造であるため、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"}}])

これは、次のように機能します。

  1. meta.projectmeta.type複合インデックスを作成し、集計をサポートする。

  2. $match ステージが meta.project = 10 のドキュメントにフィルターをかける。

  3. $group ステージでは、meta.type をグループキーとして使用して、一意の値ごとに 1 つのドキュメントを出力する。

戻る

セカンダリインデックスの追加