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

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

項目一覧

  • 挿入の最適化
  • ドキュメントのバッチ書込み (write)
  • ドキュメントでの一貫したフィールド順序の使用
  • クライアント数の増加
  • 圧縮の最適化
  • ドキュメントから空のオブジェクトと配列を含むフィールドを省略
  • 数値データを小数点以下の桁に丸めます
  • クエリ パフォーマンスの最適化
  • 適切なバケット粒度の設定
  • セカンダリ インデックスの作成
  • サブフィールドのクエリ メタフィールド
  • Distinct() の代わりに $group を使用する

このページでは、時系列コレクションのパフォーマンスとデータ使用量を向上させるためのベストプラクティスについて説明します。

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

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

たとえば、 sensor Asensor Bの 2 つのセンサーがある場合、1 つのセンサーからの複数の測定値を含むバッチには、測定 1 件ごとに 1 回の挿入ではなく、1 回の挿入に対してコストが発生します。

次の操作では 6 つのドキュメントが挿入されますが、ドキュメントはセンサーの順序付けされているため、挿入コストは 2 回の挿入コスト(バッチあたり 1 回)のみになります。 パフォーマンスを向上させるために、 orderedパラメータはfalseに設定されています。

db.temperatures.insertMany( [
{
"metadata": {
"sensor": "sensorA"
},
"timestamp": ISODate("2021-05-18T00:00:00.000Z"),
"temperature": 10
},
{
"metadata": {
"sensor": "sensorA"
},
"timestamp": ISODate("2021-05-19T00:00:00.000Z"),
"temperature": 12
},
{
"metadata": {
"sensor": "sensorA"
},
"timestamp": ISODate("2021-05-20T00:00:00.000Z"),
"temperature": 13
},
{
"metadata": {
"sensor": "sensorB"
},
"timestamp": ISODate("2021-05-18T00:00:00.000Z"),
"temperature": 20
},
{
"metadata": {
"sensor": "sensorB"
},
"timestamp": ISODate("2021-05-19T00:00:00.000Z"),
"temperature": 25
},
{
"metadata": {
"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
}

コレクションにデータを書き込むクライアントの数を増やすと、パフォーマンスが向上します。

時系列コレクションのデータ圧縮を最適化するには、次のアクションを実行します。

圧縮を最適化するために、データに空のオブジェクトまたは配列が含まれている場合は、ドキュメントから空のフィールドを省略します。

例えば、次のドキュメントについて考えてみます。

{
"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 フィールドと空の配列を持つフィールドとの間で、コンプレッサーのスキーマが変更されます。 スキーマの変更により、シーケンス内の 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]
}

数値データをアプリケーションに必要な精度に丸めます。 数値データを小数点以下桁を丸めると、圧縮率が向上します。

時系列コレクションを作成すると、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にセカンダリ インデックスを自動的に作成します。

MongoDB は時系列コレクションの 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 つのドキュメントを出力する。

戻る

時系列コレクションのシャード