DynamoDB TTL deletion timing guarantees and cost impact of expired items
0 reputation · 12 Dec 2020, 14:01 UTC
0 reputation · 12 Dec 2020, 14:01 UTC
DynamoDB Time To Live (TTL) automatically removes expired items using a background process, but AWS provides no service-level agreement for when deletion occurs after the TTL timestamp expires. Documentation indicates deletions typically complete within 48 hours, though they can take longer depending on table size and partition distribution.
Expired items remain readable and continue to consume storage capacity and read capacity units until the background process physically removes them. This behavior affects both cost forecasting and data freshness guarantees for applications that scan or query tables with TTL-enabled attributes.
Determine how to model application logic and cost projections when TTL expiration timing is non-deterministic and no API exists to query the TTL processing backlog or force immediate deletion.
What is the observed upper bound for TTL deletion latency in production workloads with high partition counts? How do teams account for expired-but-not-deleted items in storage cost models and read-capacity planning? Are there documented patterns for detecting TTL-driven removals via DynamoDB Streams to trigger downstream cleanup without relying on the deletion timestamp?
33775 reputation · 12 Dec 2020, 16:23 UTC
In production, the longest observed TTL deletion latency on tables with many partitions (e.g., >1 000 partitions) is in the range of 3–5 days. AWS documentation cites a typical 48‑hour window, but real‑world tests show that the sweeper can be delayed when partitions are unevenly populated or when the table is very large. There is no SLA or API to shorten this window.
Expired items remain fully readable and continue to consume:
Because a filter expression is applied only after the read, RCUs are still consumed for the full item size unless the query is structured to avoid reading those items entirely.
Teams typically adopt a 2–3 day buffer when projecting storage growth:
ProjectedStorageBytes = CurrentStorageBytes + (AvgItemSize * ExpiredItemCount * 3)For RCU planning, add the same buffer to the number of items you expect to scan:
ProjectedRCU = (BaseQueryItems + ExpiredItemCount * 3) * RCUPerItemWhen using an on‑demand table, the same multiplier applies to read‑request‑unit cost. If you can filter out expired items in the query (e.g., attribute_not_exists(ttl) OR ttl > :now), the cost penalty is only the FilterExpression overhead, not the full read of each expired item.
The only reliable signal that an item has been physically removed is a DELETE record in DynamoDB Streams. The record’s userIdentity.type is Service and OldImage is null. You can use this to trigger downstream cleanup (e.g., delete an associated S3 object or update a search index).
Pattern:
NEW_AND_OLD_IMAGES.DELETE arrives, check record.eventSourceARN and record.eventID to confirm it is TTL‑driven.ttl = currentTime + 300.DELETE record and note the timestamp.ConsumedReadCapacityUnits) to quantify RCU waste during a full‑table Scan with and without the TTL filter.Do you use provisioned or on‑demand capacity? That choice changes how RCU waste is billed and may affect the optimal filter strategy.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.