データベース

DynamoDB TTLとは|設定方法・自動削除の仕組みと期限切れ項目の扱いを実装目線で解説

DynamoDBのTTL(Time to Live)は、項目ごとに有効期限を持たせ、期限が過ぎた項目をDynamoDBが自動で削除する機能です。ログやセッション、一時トークンのように「一定期間で不要になるデータ」を、追加の書き込みコストなしに片付けられます。ただし「期限が来た瞬間に消える」わけではなく、実際の削除には遅延があり、消えるまでの項目は通常どおり読み取れてしまう——この挙動を知らないと、課金や整合性の設計を誤ります。この記事では、TTL属性の指定単位から設定手順、削除タイミングの正確な仕様、期限切れ項目の扱い、Streamsを使った後処理までを実装目線で整理します。

まとめ:DynamoDB TTLの要点

  • 正体:項目にUNIX epoch秒の有効期限属性を持たせると、期限後にDynamoDBが自動削除する。バッチ処理を自前で書く必要がない。
  • 属性の型:数値(Number)型でUNIX epoch時刻の「秒」。ミリ秒や文字列、ISO 8601形式は無視される。
  • 削除タイミング:期限が来た瞬間ではなく、公式表記で「有効期限後、通常数日以内(typically within a few days)」。2日程度で消えることも多いが保証値ではない。
  • 削除までの項目:期限切れでも実削除前は読み取り・クエリ・スキャンに出てくる。除外したいならFilterExpressionを併用する。
  • コスト:削除が発生したリージョンでのTTL削除は書き込みキャパシティ(WCU)を消費しない。グローバルテーブルのレプリカへの複製削除は課金対象。
  • 後処理:TTL削除はDynamoDB Streamsに「サービスによる削除」として流れ、userIdentity.principalIddynamodb.amazonaws.com。これでアーカイブ用Lambdaを回せる。

DynamoDB TTLとは(自動削除の仕組みと通常の削除との違い)

TTLは、テーブルの1つの属性を「有効期限」として指定し、その値が現在時刻を過ぎた項目をDynamoDBがバックグラウンドで削除する仕組みです。有効期限の判定に使う属性名はテーブルごとに1つだけ指定でき、名前は任意(expireAtttlなど)に決められます。

通常のDeleteItemとの違いは、削除の実行主体と課金です。TTLによる削除はアプリケーションからの明示的なリクエストではなくDynamoDB側のプロセスが行い、削除が起きたリージョンでは書き込みキャパシティを消費しません。大量の期限切れデータを自前のスキャン+削除ループで消すとRCU/WCUを消費しますが、TTLに任せればその処理コストを避けられます。DynamoDBの基礎的な特徴や料金体系はAWS DynamoDBとは?特徴・使い方・料金・RDSとの違いで解説しています。

TTL属性の型・単位・有効期限の計算方法

TTL属性で最もつまずくのが「単位」です。DynamoDBが認識するのは数値(Number)型で表したUNIX epoch時刻の「秒」だけです。ミリ秒(13桁)で入れると数万年後の時刻と解釈され永久に削除されず、文字列やISO 8601形式(2026-01-01T00:00:00Z)は数値でないため無視されます。

有効期限は「現在のepoch秒 + 保持したい秒数」で計算します。たとえば30日後に失効させるなら、現在時刻に60*60*24*30秒を足します。Python(boto3のresource)での例です。

指定 値の例 DynamoDBの解釈
Number・秒(正しい) 1767225600 該当時刻を過ぎたら削除対象
Number・ミリ秒(誤り) 1767225600000 遠い未来と解釈され削除されない
String(誤り) “1767225600” 数値型でないため無視
import time

# 現在時刻から30日後を有効期限にする(UNIX epoch秒)
expire_at = int(time.time()) + 60 * 60 * 24 * 30

# table = dynamodb.Table("Sessions")  # boto3 resource。intは自動でNumber型になる
table.put_item(Item={
    "SessionId": "abc123",
    "expireAt": expire_at,  # UNIX epoch「秒」で保存する
})

期限を延長したい場合は、この属性の値を更新し直すだけで有効期限を先送りできます。逆に属性を削除すればその項目はTTLの対象外に戻ります。

DynamoDBでTTLを有効化・設定する方法

TTLはテーブル単位で有効化し、どの属性を有効期限として使うかを指定します。有効化操作と、各項目への期限属性の書き込みは別物である点に注意してください(有効化しただけでは何も消えず、項目に期限属性を入れて初めて対象になる)。

マネジメントコンソールで有効化する

対象テーブルの「追加設定」からTime to Liveを開き、有効期限として使う属性名(例:expireAt)を入力して有効化します。有効化直後は既存項目に期限属性が無いため削除は発生せず、以降に書き込んだ項目から順次対象になります。

AWS CLIで有効化する

update-time-to-liveで有効化します。属性名は既存項目の書き込みと一致させる必要があります。

aws dynamodb update-time-to-live \
  --table-name Sessions \
  --time-to-live-specification "Enabled=true, AttributeName=expireAt"

CloudFormation/Serverless FrameworkでIaC管理する

テーブル定義にTTL指定を含めておけば、環境差異なく有効化できます。CloudFormation(およびそれを内包するServerless Framework)ではTimeToLiveSpecificationを記述します。

Resources:
  SessionsTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: Sessions
      TimeToLiveSpecification:
        AttributeName: expireAt
        Enabled: true

期限切れから実削除までの挙動(削除タイミングと未削除項目の扱い)

TTLの設計で最も誤解が多いのが「いつ消えるか」です。有効期限イコール削除時刻ではありません。

実削除は「数日以内」——48時間は保証値ではない

公式ガイドは「有効期限が切れた項目は、その後通常数日以内(typically within a few days)にシステムによって削除される場合がある」と記述しています。実際には2日程度で消えることも多いものの、これは保証された値ではありません(AWSの一部ページには「2日以内」という記述も残りますが、上位ガイドは数日以内へ更新されています)。テーブルのトラフィックやサイズで前後するため、「期限=即時削除」や「厳密に48時間で消える」を前提にした設計は避けてください。厳密な失効が必要な要件では、後述のとおり読み取り側で除外する必要があります。

期限切れだが未削除の項目を読み取りから除外する

実削除までのあいだ、期限切れ項目はGetItemQueryScanの結果に通常どおり返ってきます。アプリケーションで「期限切れは無いもの」として扱いたい場合は、クエリに現在時刻との比較を入れて除外します。

# from boto3.dynamodb.conditions import Key, Attr / table = dynamodb.Table("Sessions")
# 現在時刻より後に失効する項目だけ取得(期限切れを除外)
resp = table.query(
    KeyConditionExpression=Key("UserId").eq("u001"),
    FilterExpression=Attr("expireAt").gt(int(time.time())),
)

なお期限切れの項目もまだ更新でき、更新すると期限属性を書き換えて削除対象から外すことも可能です。意図せず生き返らせないよう、更新時は条件式(ConditionExpression)で期限切れかどうかを確認する運用が安全です。

StreamsとLambdaによるTTL削除の後処理(アーカイブ・監査)

「消す前に別ストレージへ退避したい」「削除を監査ログに残したい」という要件では、DynamoDB Streamsと組み合わせます。TTLによる削除もStreamsにレコードとして流れますが、通常のユーザー削除と区別できる署名を持ちます。

  • eventNameREMOVE
  • userIdentity.typeService
  • userIdentity.principalIddynamodb.amazonaws.com

Lambdaのイベントソースマッピングにフィルターを設定すれば、TTL削除だけを対象にLambdaを起動でき、通常の書き込みや手動削除では起動しないため呼び出し回数とコストを抑えられます。

{
  "userIdentity": {
    "type": ["Service"],
    "principalId": ["dynamodb.amazonaws.com"]
  }
}

この署名を使い、期限切れ項目のS3アーカイブや通知を自動化するのが定番パターンです。グローバルテーブルの場合、このuserIdentityが付くのは削除が実行された元リージョンだけで、他リージョンへ複製された削除レコードには付かない点に注意してください(後処理を1回だけ動かしたいときに重要)。

グローバルテーブルでのTTLの挙動と課金

グローバルテーブルでは、あるリージョンで起きたTTL削除がすべてのレプリカへ複製されます。ここで課金の扱いが変わります。削除が発生した元リージョンのTTL削除はWCUを消費しませんが、レプリカへ複製される削除は書き込みキャパシティ(プロビジョンド)または書き込みユニット(オンデマンド)を消費し課金対象になります。大量削除を伴うテーブルでは、この複製コストを見積もりに含めてください。グローバルテーブル自体の複製の仕組みや料金はDynamoDB Global Tablesとは|複製の仕組み・強整合性・料金で詳しく扱っています。

TTLの主なユースケースと、TTLを避けるべき場面

TTLが向くのは、削除タイミングに数日の幅があっても支障がなく、削除自体が主目的のデータです。

  • セッション・認証トークン:ログイン状態や一時トークンを一定期間後に失効させる(実クエリでも「ttl session」で流入がある用途)。
  • キャッシュデータ:一時的な計算結果や画面キャッシュを保持期間経過で自動整理する。
  • イベントログ・監査ログ:法定・運用上の保持期間を過ぎたレコードを自動で片付ける。

一方で、次のケースではTTLは適しません。ここは割り切りが必要です。期限ちょうどに確実に消したい(数日の遅延が許容できない)要件、失効時刻を秒単位で厳密に守る必要がある要件では、TTLだけに頼るべきではありません。削除遅延中も項目は読めてしまうため、厳密性が要る場合は前述のFilterExpressionで読み取り側を締めるか、明示的なDeleteItemや別のスケジューラで補完します。TTLは「掃除を任せる仕組み」であって「正確なタイマー」ではない、と捉えるのが実務的です。

TTLで削除されない・効かないときのトラブルシューティング

「TTLを設定したのに消えない」という相談の大半は、次のいずれかです。上から順に確認します。

症状の原因 確認ポイント
属性名の不一致 TTL有効化時の属性名と、項目に書いた属性名が完全一致しているか
型・単位の誤り Number型か/ミリ秒でなく「秒」か(13桁はミリ秒の疑い)
期限が未来すぎる epoch値が想定より大きくないか(ミリ秒混入で遠い未来になっていないか)
まだ削除遅延の範囲内 期限直後は未削除が正常。数日は待つ。即時性が要るなら読み取り側で除外
TTL自体が無効 テーブル設定でTTLがEnabledになっているか

特に多いのがミリ秒混入です。多くの言語で「現在時刻」はミリ秒で返るため、そのまま入れると13桁になり削除されません。保存前に必ず秒(10桁)へ丸めてください。削除が遅いだけで設定は正しい、というケースも多いので、削除タイミングの仕様(数日以内)を踏まえて切り分けます。

よくある質問(FAQ)

DynamoDBのTTLとは何ですか?

項目ごとにUNIX epoch秒の有効期限を持たせ、期限を過ぎた項目をDynamoDBが自動削除する機能です。ログやセッションなど期限のあるデータを、自前のバッチや追加の書き込みコストなしに整理できます。

TTLの単位は秒ですか、ミリ秒ですか?

秒です。数値(Number)型のUNIX epoch時刻を「秒」で保存します。ミリ秒(13桁)で入れると遠い未来と解釈され削除されません。

DynamoDBのTTLは48時間で削除されますか?

48時間は保証値ではありません。現在の公式説明は「有効期限後、通常数日以内(a few days)に削除される場合がある」で、2日程度で消えることも多い一方、確実に48時間で消えるわけではありません。厳密な失効が必要なら読み取り時に期限切れを除外します。

期限切れだが未削除の項目は読み取れますか。課金されますか?

実削除までは通常どおり読み取り・クエリ・スキャンに返ります。ストレージ課金も削除されるまで発生します。読み取りで隠したい場合はFilterExpressionで除外してください。

TTL削除はDynamoDB Streamsに流れますか?

流れます。eventNameREMOVEuserIdentity.principalIddynamodb.amazonaws.com(type=Service)になり、この署名でTTL削除だけをLambdaで後処理できます。

関連記事

資料請求

RELATED POSTS 関連記事