注意
ストレージ コストを節約するためにドキュメントを削除している場合、MongoDB Atlas の Online Archive の使用がおすすめです。Atlas Online Archive は、アクセス頻度の低いデータを完全自己管理型の S3 バケットに自動的にアーカイブするコスト効果の高いデータ階層化ツールです。
"Time-to-Live"(TTL)インデックスは、 MongoDB が一定時間の経過後または特定のクロック時間にコレクションからドキュメントを自動的に排除するために使用できる特殊な単一フィールド インデックスです。一定時間のみデータベースに保持する必要があるタイプのデータには有効期限を設定すると便利です。たとえば、マシンで生成されたイベントデータ、ログ、セッション情報はこうしたデータに該当します。
MongoDB Atlas でホストされている配置向けに UI で TTL インデックスを作成および管理できます。
TTL インデックスの作成
警告
TTL インデックスを作成すると、一度に削除する対象ドキュメントの数が非常に多くなる場合があります。こうした大きなワークロードは、サーバーでパフォーマンスの問題が生じる原因になることがあります。こうした問題を回避するには、営業時間外にインデックスを作成するか、対象となるドキュメントをバッチ単位で削除してからその後に作成されるドキュメントのインデックスを作成します。
TTL インデックスを作成するには、createIndex() を使用します。Date 型または Date 型の値を含む配列のインデックス フィールドを指定します。expireAfterSeconds オプションを使って TTL 値を秒単位で指定します。
TTLインデックスの expireAfterSeconds 値は、0 から 2147483647 の範囲内(両端を含む)である必要があります。
たとえば、eventlog コレクションの lastModifiedDate フィールドで TTL 値 3600 秒を使用して TTL インデックスを作成するには、mongosh で次の操作を使用します。
db.eventlog.createIndex( { "lastModifiedDate": 1 }, { expireAfterSeconds: 3600 } )
時系列コレクションに TTL インデックスを作成する
重要
MongoDB 7.0 以降では、時系列コレクションで部分的な TTL インデックスを作成できます。時系列コレクションを作成するときに、指定された時間後にドキュメントを削除する任意のフィールド expireAfterSeconds を含めることができます。
たとえば、次の気象データ時系列コレクションを作成し、expireAfterSeconds フィールドを設定して、24 時間後にドキュメントを削除するようにします。
db.createCollection( "weather24h", { timeseries: { timeField: "timestamp", metaField: "sensor", granularity: "hours" }, expireAfterSeconds: 86400 } )
また、partialFilterExpression フィールドを使用してコレクションに TTL インデックスを作成することもできます。これらのインデックスは、コレクションの timeField をキー フィールドとして使用します。また、次の項目も指定してください。
ドキュメントのサブセットに対して明示的な有効期限を設定する
expireAfterSecondsフィールド。コレクションを作成する際にexpireAfterSecondsフィールドを設定していても、partialFilterExpressionフィールドを使用することで、一致するドキュメントのサブセットに対して異なる、より短い有効期限を設定できます。metaField上の部分フィルター式。partial filter expressionは、expireAfterSecondsフィールドで定義された時間に有効期限切れとなるドキュメントのセットを定義します。
次の TTL インデックスは、「ensor」フィールドが「MDB_NYC」に設定されている「weather24h」コレクション内のドキュメントに一致しており、1 時間後にそれらを削除し、コレクションの作成時に設定したデフォルトの 24 時間を上書きします。
db.weather24h.createIndex( { "timestamp": 1 }, { expireAfterSeconds: 3600, partialFilterExpression: { "sensor": { $eq: "MDB_NYC" } } } )
重要
コレクションの expireAfterSeconds 値が部分的な TTL インデックスの expireAfterSeconds より小さい場合、コレクションは短い方の時間経過後にドキュメントを削除するため、TTL インデックスは効果がありません。
TTL 以外の単一フィールド インデックスの TTL インデックスへの変換
MongoDB 5.1 以降では、既存の単一フィールド インデックスに expireAfterSeconds オプションを追加できます。TTL 以外の単一フィールド インデックスを TTL インデックスに変更するには、collMod データベースコマンドを使用します。
db.runCommand({ "collMod": <collName>, "index": { "keyPattern": <keyPattern>, "expireAfterSeconds": <number> } })
次の例では、パターン { "lastModifiedDate": 1 } を含む TTL 以外の単一フィールド インデックスを TTL インデックスに変換しています。
db.runCommand({ "collMod": "tickets", "index": { "keyPattern": { "lastModifiedDate": 1 }, "expireAfterSeconds": 100 } })
TTL インデックスの expireAfterSeconds 値の変更
TTL インデックスの expireAfterSeconds 値を変更するには、collMod データベースコマンドを使用します。
db.runCommand({ "collMod": <collName>, "index": { "keyPattern": <keyPattern>, "expireAfterSeconds": <number> } })
次の例では、パターン { "lastModifiedDate": 1 } を含むインデックスの expireAfterSeconds の値を tickets コレクションで変更しています。
db.runCommand({ "collMod": "tickets", "index": { "keyPattern": { "lastModifiedDate": 1 }, "expireAfterSeconds": 100 } })
重要
TTL インデックスのexpireAfterSecondsパラメータを更新する前に、次の点を考慮してください。
パラメータを変更しても、インデックスの完全な再構築は さ
expireAfterSecondsれません 。triggerただし、expireAfterSecondsの値を減らすと、多くのドキュメントが即座に削除の対象となる可能性があり、削除操作が増加してパフォーマンスの問題が発生する可能性があります。TTL インデックスを更新する前に、ドキュメントを小さなバッチで手動で削除することをお勧めします。 これにより、クラスターへの影響を制御することができます。
多くのドキュメントを削除すると、ストレージ ファイルが断片化され、パフォーマンスにさらに影響が生じます。 スペースを再利用し、ストレージを最適化するには、コレクションに対して圧縮コマンドを実行するか、最初の同期を実行する必要がある場合があります。
動作
データの有効期限
TTL インデックスは、インデックス フィールド値から指定された秒数が経過するとドキュメントが期限切れになります。 有効期限のしきい値は、インデックス フィールドの値に、指定された秒数を加えた値になります。
フィールドが配列で、インデックスに複数の日付値がある場合、MongoDB は配列内の最も低い日付値(最も近い日付値)を使用して有効期限のしきい値を計算します。
時系列コレクションの場合、TTL インデックスは、その中のすべてのドキュメントの有効期限が切れると、バケット データの削除も行います。これは、バケットのタイムスタンプの上限に expireAfterSeconds 値を加えた値に等しくなります。たとえば、バケットに 2023-03-27T18:29:59Z までのデータが含まれ、expireAfterSeconds が 300 の場合、TTL インデックスは 2023-03-27T18:34:59Z の後にバケットを期限切れにします。
ドキュメント内のインデックス付きフィールドに 1 つ以上の日付値が含まれていない場合、ドキュメントは有効期限切れになりません。
インデックス フィールドが含まれていないドキュメントは、有効期限切れになりません。
削除操作
mongod のバックグラウンド スレッドは、インデックスの値を読み取り、コレクションから期限切れのドキュメントを削除します。
TTL スレッドによって実行される進行中の削除操作は、 db.currentOp()の出力に表示されます。 TTL スレッドがドキュメントを削除すると、 metrics.ttl.deletedDocumentsサーバー ステータス メトリクスが増加します。
MongoDB 6.1 以降、次の機能を使用できます。
MongoDB は効率を向上するために、複数のドキュメントの削除をバッチ処理する場合があります。
explainコマンドの結果には、バッチ処理されたドキュメント削除のための新しいBATCHED_DELETEステージが含まれています。
削除プロセス
TTL バックグラウンド削除プロセスは、各 TTL インデックスで期限切れのドキュメントをチェックします。 TTL インデックスごとに、次のいずれかの条件が満たされるまで、バックグラウンド プロセスはドキュメントを削除します。
プロセスは、現在のインデックスから50000ドキュメントを削除します。
プロセスでは、現在のインデックスからドキュメントを削除するのに 1 秒かかります。
期限切れのドキュメントはすべて、現在のインデックスから削除されます。
その後、プロセスは次のインデックスに移動します。 プロセスが各 TTL インデックスを 1 回通過すると、現在のサブパスは完了し、新しいサブパスが残りの期限切れドキュメントのチェックを開始します。 TTL モニターがすべての TTL インデックスから可能なすべての候補ドキュメントを削除すると、パスは完了します。
重要
TTL 削除プロセスはシングルスレッドのバックグラウンド タスクです。つまり、TTL 削除は同時に行われず、ワークロードが重い場合や期限切れのドキュメントを大量に処理する際には、時間がかかることがあります。
さらに、 プロセスは現在の削除ループを60秒ごとに停止して、1 回の大きな削除に時間がかかりすぎるのを防ぎます。 このような状況が発生すると、現在のサブパスは終了し、新しいサブパスが開始されます。
パスとサブパスはそれぞれmetrics.ttl.passesとmetrics.ttl.subPassesサーバー ステータス メトリクスで追跡されます。
削除操作のタイミング
MongoDB は、プライマリでインデックスの構築が完了するとすぐに、期限切れのドキュメントまたは時系列バケットの削除を開始します。インデックス構築プロセスの詳細については、「入力されたコレクションでのインデックス構築」を参照してください。
TTL インデックスは、有効期限が切れたデータがその期限直後に削除されることを保証するものではありません。ドキュメントの有効期限が切れてから MongoDB がデータベースからドキュメントを削除するまでの間にタイムラグが生じる可能性があります。
期限切れのドキュメントを削除するバックグラウンド タスクは、60 秒ごとに実行されるため、ドキュメントの有効期限が切れてからバックグラウンド タスクが実行されるまでの間に、ドキュメントがコレクションに残ることがあります。MongoDB は、インデックスの完了から 0~60 秒後にドキュメントの削除を開始します。
削除操作の間隔は mongod インスタンスのワークロードによって異なるため、バックグラウンド タスクの実行間隔が 60 秒を超えると、有効期限切れのデータがしばらく残る可能性があります。
TTL タスクが開始する削除操作は他の削除操作と同様に、フォアグラウンドで実行されます。
レプリカセット
TTL バックグラウンド スレッドはレプリカセット ノードで、ノードがプライマリ状態にある場合にのみドキュメントを削除します。TTL バックラウンド スレッドは、ノードがセカンダリ状態にある場合はアイドルになります。セカンダリ ノードはプライマリでの削除操作をレプリケートします。
クエリのサポート
TTL インデックスは、TTL 以外のインデックスと同様にクエリをサポートします。
スタンドアロンモードでの mongod
mongod がスタンドアロンモードで実行され、system.local.replset コレクションにデータが含まれている場合、TTL モニターは停止します。レプリカセットのノードをレプリカセットから取り出してスタンドアロンとして実行する場合、TTL モニターは無効になります。
TTL とスキーマ検証
TTL インデックスはスキーマ検証を必要としませんが、検証を使用することで、存在および日付フィールドの形式を標準化することにより、一貫した動作を確保し、有効期限の管理に役立ちます。
例として、スキーマ検証を使用して lastModifiedDate フィールドの存在を強制し、その値が有効な日付形式に従っていることを確認できます。
db.createCollection( "eventlog", { validator: { $jsonSchema: { bsonType: "object", required: [ "lastModifiedDate" ], properties: { lastModifiedDate: { bsonType: "date", description: "Must be a valid date." } } } } } )
このスキーマ検証ルールは、以下を保証します。
eventlogコレクション内のすべてのドキュメントにはlastModifiedDateフィールドが含まれています。lastModifiedDateフィールドには有効な日付値が含まれています。
Tip
制限事項
TTL インデックスは単一フィールドのインデックスです。複合インデックスは TTL をサポートしておらず、
expireAfterSecondsオプションを無視します。_idフィールドは TTL インデックスをサポートしていません。MongoDB7.0 以降では、 時系列コレクション の に 部分的な TTL インデックス
metaFieldを作成できます。MongoDB の以前のバージョンでは、時系列コレクションのtimeFieldの TTL インデックスのみを作成できます。既存のインデックスの
expireAfterSecondsの値を変更するために、createIndex()は使用できません。 代わりに、collModデータベースコマンドを使用します。 詳しくは、「 TTL インデックスのexpireAfterSeconds値の変更 」を参照してください。TTL 以外の単一フィールド インデックスがフィールドにすでにある場合、同じフィールドに TTL インデックスを作成できません。キー仕様が同じで、オプションのみが異なるインデックスは作成できないためです。 TTL 以外の単一フィールド インデックスを TTL インデックスに変更するには、
collModデータベースコマンドを使用します。