Parsivex raises this finding for tables on provisioned billing only. Tables already on on-demand are never flagged: they bill per request, so there is no reserved headroom to waste.
What triggers this finding
A DynamoDB table on provisioned billing with monthly cost of at least $5, where consumed read or write capacity is below 15% of what is provisioned (including global secondary indexes).
Typical fix
Rightsize provisioned RCU/WCU to roughly 2× observed peak usage, or switch to on-demand billing when utilization is very low and monthly provisioned cost is under ~$50.
Example savings
Depends on over-provisioning — often $10–$100+/month on tables with unused headroom.
See also: Severity and savings estimates for how Parsivex calculates figures on your report.
How provisioned capacity is billed
Provisioned mode reserves throughput by the hour whether or not you use it. Parsivex prices that reservation at the us-east-1 on-demand rates — $0.00013 per RCU-hour and $0.00065 per WCU-hour — across 730 hours a month. Write capacity is five times the price of read capacity, so a table over-provisioned on writes wastes money five times faster than the same mistake on reads.
Global secondary indexes carry their own provisioned capacity and are billed separately from the base table. Parsivex sums the table and every GSI before deciding, which is why a table showing modest capacity in the console can appear here with a much larger monthly figure: three indexes at the same capacity as the base table cost four times the base table.
Two thresholds gate the finding. Tables costing less than $5 a month are skipped entirely, and the table is only flagged when the higher of read and write utilization is under 15% of what is provisioned. Below 5% utilization, and under $50 a month, Parsivex recommends switching to on-demand instead of rightsizing and estimates savings at 70% of the current spend. Above that, it recommends new capacity values at roughly twice the observed peak consumption.
Checking capacity and consumption yourself
Provisioned capacity, including every index, comes from one call:
aws dynamodb describe-table --table-name orders \
--query 'Table.{Mode:BillingModeSummary.BillingMode,RCU:ProvisionedThroughput.ReadCapacityUnits,WCU:ProvisionedThroughput.WriteCapacityUnits,Indexes:GlobalSecondaryIndexes[].{Name:IndexName,RCU:ProvisionedThroughput.ReadCapacityUnits,WCU:ProvisionedThroughput.WriteCapacityUnits}}'
Consumption is a CloudWatch sum, and the arithmetic matters:
aws cloudwatch get-metric-statistics --namespace AWS/DynamoDB \
--metric-name ConsumedWriteCapacityUnits \
--dimensions Name=TableName,Value=orders \
--start-time 2026-07-12T00:00:00Z --end-time 2026-08-11T00:00:00Z \
--period 86400 --statistics Sum Maximum
ConsumedWriteCapacityUnits is reported as a total, not a rate. Divide each daily Sum by 86,400 to get the average units per second that the utilization percentage is built from. Run the same query for ConsumedReadCapacityUnits, and add ThrottledRequests to the list — a table that is both under-utilized on average and occasionally throttled is bursty, not over-provisioned.
Cases where low utilization is correct
The daily granularity is the honest limitation here. Parsivex reads 30 days of daily datapoints, so its "peak" is the busiest day's average rate, not the busiest minute. A table that sits idle for 23 hours and saturates its capacity during a nightly batch window reports single-digit utilization while genuinely needing every unit it has. The 2× headroom factor exists to absorb some of that, but a sharply spiky table needs more than 2×, and you are the only one who knows the shape of the load.
Three other situations produce a correct finding with the wrong conclusion:
- Application auto scaling is already managing the table. DynamoDB auto scaling holds utilization near its target — typically 70% — but drops to
MinCapacityovernight and stays there. The waste is a floor set too high, and the fix is loweringMinCapacity, not the table's current capacity. - You own DynamoDB reserved capacity. Reserved capacity is paid for regardless. Cutting provisioned units below what you have already reserved saves nothing and wastes the reservation.
- The headroom is deliberate. Launches, migrations, and replays are all reasons to hold capacity ahead of demand for a few weeks.
Cost and risk of a capacity change
Reducing capacity has no downtime and no data risk — it is a control-plane update that applies within seconds. The exposure is throttling: if consumption exceeds the new ceiling, DynamoDB returns ProvisionedThroughputExceededException, which the AWS SDKs retry with backoff. Well-behaved applications degrade into latency; less careful ones surface errors to users. Put a CloudWatch alarm on ThrottledRequests before the change, not after.
Rollback is an increase, and increases apply immediately. Decreases are the constrained direction: AWS limits how many times a table's capacity can be reduced in a single day, so plan one considered step rather than a series of experiments.
Switching billing mode is the larger commitment. A table can change between provisioned and on-demand only once every 24 hours, so a mode switch cannot be undone the same afternoon if traffic surprises you. Move a non-critical table first, watch a full weekly cycle including the batch peaks, and then apply the pattern to the rest.