DynamoDB provisioned capacity cost comes from read and write capacity units a table reserves and does not consume; the same pattern is called request units per second on Azure Cosmos DB, shards on Kinesis, baseline slots on BigQuery and cluster instances on Data Explorer. Provisioned capacity is billed by the ordered figure, used or not; the saving comes from the gap between ordered and consumed, closed by autoscaling, by a lower figure or by the move to the on-demand mode. The fix belongs to the team that runs the application on the table or stream, because only there is the peak load known.
Symptom
The bill shows capacity hours, not requests. On AWS these are lineItem/UsageType EUC1-ReadCapacityUnit-Hrs and EUC1-WriteCapacityUnit-Hrs under AmazonDynamoDB, against ReadRequestUnits and WriteRequestUnits in on-demand mode, and EUC1-Storage-ShardHour under AmazonKinesis. On Azure they are MeterCategory Azure Cosmos DB with 100 RU/s meters per hour, standard or autoscale, and Azure Data Explorer with instance hours per cluster. On Google Cloud BigQuery carries the SKUs for slot hours per edition, baseline and autoscaled, under BigQuery Reservation API. Beside them the metrics show consumed units far below the ordered ones. What the services charge in principle is in managed databases and data warehouses and analytics; the reservations built on capacity in reserved capacity for managed services.
How to detect it
AWS
The tables in provisioned mode with their units:
for t in $(aws dynamodb list-tables --query 'TableNames[]' --output text); do
aws dynamodb describe-table --table-name "$t" \
--query 'Table.[TableName,BillingModeSummary.BillingMode,ProvisionedThroughput.ReadCapacityUnits,ProvisionedThroughput.WriteCapacityUnits]' --output text
done
One table's consumed units over two weeks, as a sum per hour divided by 3,600 against the ordered ones:
aws cloudwatch get-metric-statistics --namespace AWS/DynamoDB --metric-name ConsumedReadCapacityUnits \
--dimensions Name=TableName,Value=<table> --statistics Sum \
--start-time 2026-10-07T00:00:00Z --end-time 2026-10-21T00:00:00Z --period 3600
Compute Optimizer classifies a table in provisioned mode as idle when no units were consumed at table or index level over 14 days, and recommends on-demand or a lower figure (read on 2026-10-21): aws compute-optimizer get-idle-recommendations --filters name=ResourceType,values=DynamoDBTable. Trusted Advisor also carries the purchase recommendation for DynamoDB reserved capacity. Kinesis streams with mode and shards:
aws kinesis list-streams --query 'StreamSummaries[].[StreamName,StreamModeDetails.StreamMode]' --output table
aws kinesis describe-stream-summary --stream-name <stream> --query 'StreamDescriptionSummary.[OpenShardCount,StreamModeDetails.StreamMode]'
The metric IncomingBytes per stream against the shards' capacity is the gap; in provisioned mode every shard-hour counts, in on-demand mode the stream-hour plus the GB read and written (Kinesis pricing). In billing data the candidate is a CapacityUnit-Hrs or ShardHour line with full hours (AWS Cost and Usage Report).
Azure
The throughput per container and the utilisation:
az cosmosdb sql container throughput show --account-name <account> --database-name <db> --name <container> --resource-group <rg>
az kusto cluster list --query "[].{name:name, state:state, sku:sku.name, capacity:sku.capacity, autoscale:optimizedAutoscale.isEnabled}" -o table
The metric NormalizedRUConsumption per container is the ratio of consumed to provisioned RU/s per partition. Autoscale bills per hour the highest figure reached at 1.5 times the standard throughput rate, scales between 10 and 100 percent of the maximum, and pays off when the full figure is needed in at most 66 percent of hours (manual or autoscale). Azure Advisor recommends autoscale from seven days of usage, flags Azure Cosmos DB containers without activity over 30 days, and for Data Explorer the stop of unused clusters, the deletion of clusters stopped for 60 days and Optimized Autoscale. In the cost export the candidate is a 100 RU/s meter with full hours at a low normalised utilisation (Azure cost exports).
Google Cloud
The reservations with baseline slots and autoscaling:
bq ls --reservation --project_id=<project-id> --location=EU
bq show --reservation --project_id=<project-id> --location=EU <reservation>
Baseline slots are always billed, used or not; autoscaled slots per second in steps of 50 slots with a minimum duration of one minute, and what is billed is the number of scaled slots, not the used ones (slot autoscaling). The recommender google.bigquery.capacityCommitments.Recommender proposes slot commitments from usage (Recommenders); the utilisation per reservation shows in the metric slots/allocated_for_reservation against the baseline. In the billing export the candidate is a slot SKU with full hours per reservation (Google Cloud billing export).
How to fix it
- Find the peak and the mean of the last two to four weeks per table, container, stream or reservation; the providers' rule is the same: steady, high utilisation stays provisioned, everything else scales or changes mode.
- Change the mode where the load varies or is low: DynamoDB
aws dynamodb update-table --table-name <table> --billing-mode PAY_PER_REQUEST, from provisioned to on-demand up to four times in 24 hours, back at any time (switching capacity modes); Kinesisaws kinesis update-stream-mode --stream-arn <arn> --stream-mode-details StreamMode=ON_DEMAND; Azure Cosmos DBaz cosmosdb sql container throughput migrate --account-name <account> --database-name <db> --name <container> --resource-group <rg> --throughput-type autoscale. - Lower the figure where the load is steady:
aws dynamodb update-table --table-name <table> --provisioned-throughput ReadCapacityUnits=50,WriteCapacityUnits=20with auto scaling at a 70 percent target,az cosmosdb sql container throughput update --throughput 1000,bq update --reservation --slots 100 --project_id=<project-id> --location=EU <reservation>for the baseline,az kusto cluster update --name <cluster> --resource-group <rg> --sku name=<sku> capacity=2 tier=Standardor Optimized Autoscale. - Write the figures into the templates: table and container definitions with autoscale or on-demand as the default, a baseline of zero slots where BigQuery only runs reports, and a stop schedule for Data Explorer clusters without night-time use.
None of these calls has a dry run; the list from the detection stands in for it. The new figure applies from the change, on Azure Cosmos DB from the next hour.
Risks and side effects
- Too little capacity shows as throttling: DynamoDB answers with
ProvisionedThroughputExceededException, Azure Cosmos DB with HTTP 429, Kinesis withProvisionedThroughputExceededExceptionper shard. The peak belongs in the target figure, and alarms on these errors come before the cut. - On-demand is more expensive per request than well-utilised provisioned capacity; at steady, high load the sum turns around, and the providers' limits, 66 percent on Azure Cosmos DB, are the rule of thumb.
- The move to on-demand on DynamoDB deletes the auto scaling settings in the console; through the CLI and SDK they are kept.
- Reserved capacity, DynamoDB reserved capacity or an Azure Cosmos DB reservation, covers provisioned units only; a move to on-demand leaves it idle (reserved capacity for managed services).
- Baseline slots on BigQuery secure the latency of dashboards at fixed times; a baseline of zero saves until the first report on Monday morning waits for slots.
How to verify the saving
Before: per resource, the capacity hours and their amount in the last full month, CapacityUnit-Hrs, ShardHour, 100 RU/s, slot hours, beside the consumed units. After: the same resource in the first full month after the change, in the new mode with request, byte or scaled slot lines, or at the lower figure; the sum has to fall at an equal request count, and the throttling errors stay at zero. The difference from the recommender or your own calculation is the estimate, the team's release makes it accepted, the change implemented, and the following month's invoice realises it in the pattern of estimated, accepted, implemented, verified. The ratio of consumed to provisioned units per resource is the figure for the cost review.
Sources
Read on 2026-10-21. Switching capacity modes in DynamoDB, Compute Optimizer idle resource recommendations, Trusted Advisor cost optimization checks, Kinesis Data Streams pricing, Azure Cosmos DB, manual or autoscale, Azure Cosmos DB autoscale, Azure Advisor cost recommendations, BigQuery slot autoscaling, Recommenders.