Subchapter 78.12
references/redshift-storage-utilization.mdMarkdown34 KBView on GitHub
Answers what is consuming space and why; act via references/redshift-storage-remediation.md. Attribute before remediating, and establish Serverless vs provisioned first (SKILL.md STEP 0) — the views and what “used” means differ, and does not tell you which one you’re on.
SELECT version()Always name the specific system views and columns you would query, then interpret them. A verdict with no views behind it is not actionable — state the view, the column, and what value would confirm or refute each candidate cause.
Answer shape — front-load it. Lead with (1) the verdict, (2) the causal chain including why the symptom looks the way it does, (3) the remediation list — every action, in order — then (4) what you explicitly rule OUT. A reader who stops after the opening should already hold both the diagnosis and every fix; supporting queries, caveats, and background come after the conclusions they support, never before. Answer the question asked, completely. Cover every conclusion, every diagnostic step, and every remediation the question needs, with the reasoning that makes each one verifiable — never omit a step or a caveat to be brief. Stay on the question: a spike question gets the spike diagnosis, a vacuum question gets the vacuum answer; do not append an unrelated investigation the customer did not raise. Explain each mechanism where it is used rather than repeating it across sections.
Snapshot / backup billing questions: use the S16 matrix at the end of this file — do not answer from the general AWS Backup rule or from “Redshift snapshots are incremental” alone. Billing depends on snapshot type (automated vs manual) AND platform (RA3 vs Serverless/RG), and on RA3 each retained manual snapshot bills close to its own full size.
STV_NODE_STORAGE_CAPACITY used/capacity (provisioned single-AZ only — the STL_/STV_ families are disabled on Multi-AZ and absent on Serverless, so a monitoring query built on them breaks on a single-AZ → Multi-AZ move).PercentageDiskSpaceUsed is not a pure data-growth signal — query spill and temp blocks raise it too, which is why a spike can self-recover with no data change. Pair it with SVV_TABLE_INFO.size (logical permanent data) before concluding growth.STL_DISK_FULL_DIAG is the documented first stop — it is the one view that answers which query filled which node: SELECT node_num, query_id, temp_blocks FROM stl_disk_full_diag; (for the event time add '2000-01-01'::timestamp + (currenttime/1000000.0) * interval '1 second' AS currenttime). temp_blocks ≈ 0 ⇒ the fill is persistent data; non-zero ⇒ attribute it to that query_id‘s spill rather than to growth or maintenance debt. Check this before reaching for VACUUM — it is the fastest split between the two causes. Provisioned single-AZ only, like the rest of the STL_/STV_ family.svv_table_info.SVV_TABLES_SPACE_USAGE is the fastest way to split that total per node — one row per node with capacity, local_perm_tables_space_used, local_temp_tables_space_used and datasharing_tables_space_used, which answers “is this my data, my temp/spill, or inbound shared data?” in a single query and shows which nodes carry the imbalance: SELECT node, capacity, local_perm_tables_space_used, local_temp_tables_space_used, datasharing_tables_space_used FROM svv_tables_space_usage ORDER BY node;. Requires superuser. Pair its verdict with the figures the customer can cross-check directly — svv_table_info for permanent size and PercentageDiskSpaceUsed in CloudWatch for the fill.STL_/STV_ views are unreachable while it is down, so read PercentageDiskSpaceUsed there to confirm whether the fill really is near 100%, and use stv_node_storage_capacity once it is back. Do not assume storage is the cause: an active regional event, a hardware fault, a Serverless control-plane workflow, or the state of a datashare producer can each wedge a cluster whose storage is fine. Confirm the fill first, then hand off to references/redshift-storage-remediation.md (S12 for a stuck cluster, S18 for a failed/rolled-back resize) for the recovery playbook — the customer cannot force a stuck workflow, so recovery is adding capacity via elastic resize for headroom plus escalating to the Redshift service team, never a VACUUM first.SVV_TABLE_INFO is superuser-gated (GRANT SELECT ON svv_table_info TO <user>).
SELECT "schema","table",size/1024.0 AS size_gb,tbl_rows,estimated_visible_rows,
tbl_rows-estimated_visible_rows AS ghost_rows,unsorted AS pct_unsorted,
vacuum_sort_benefit,stats_off,skew_rows,diststyle
FROM svv_table_info ORDER BY size DESC LIMIT <n, integer, no quotes>;Growth vs debt: size+tbl_rows up = real growth; large ghost_rows = VACUUM DELETE ONLY debt; pct_unsorted high + vacuum_sort_benefit>0 = sort debt, ≈0 = do-not-vacuum trap; skew_rows high = distribution debt (remediate with EVEN diststyle or a better distribution key); stats_off high = ANALYZE. ghost_rows is a raw count, not a ratio — always judge it against tbl_rows before acting (14 ghost rows out of 600M is noise; 10B out of 12B is the whole problem). Tombstoned blocks are not just the residue of deleted rows — a delete marks rows deleted (making them ghost rows, cleared by VACUUM DELETE ONLY), whereas a tombstoned block is a superseded block version pending release, so uncommitted / rolled-back writes and in-flight transactions also hold tombstones and they can appear with no DELETE workload at all. Tombstoned blocks free at commit, not via VACUUM. Never conclude “nothing to reclaim” from stv_partitions.tossed=0. tossed counts blocks pending release at the next commit and is also set by a dropped column, by INSERTs, and by disk-based queries — it is a transient counter, not a measure of accumulated reclaimable space, so a table carrying billions of ghost rows can sit at tossed=0. Measure reclaimable space with ghost_rows above, and per-table tombstones with the documented query:
SELECT trim(name) AS tablename, COUNT(CASE WHEN tombstone > 0 THEN 1 END) AS tombstones
FROM svv_diskusage GROUP BY 1 HAVING COUNT(CASE WHEN tombstone > 0 THEN 1 END) > 0 ORDER BY 2 DESC;Transient spill: sys_query_detail (spilled_block_local_disk, summed per query) — temp blocks, not growth. “Temp blocks” covers two different consumers — separate them before prescribing anything, because the fixes do not overlap. (1) Rowset spill: a query exceeding its memory grant writes intermediate results to disk; measure per query via sys_query_detail.spilled_block_local_disk (query_temp_blocks_to_disk / blocks_to_disk on the legacy views), and fix it with WLM/QMR limits, lower concurrency, or a distribution change. (2) User temp and staging tables from CREATE TEMP TABLE or an ETL scratch schema; measure them via stv_tbl_perm with temp=1, and fix by dropping them at end of ETL or letting the session disconnect. Both inflate PercentageDiskSpaceUsed identically, so the metric alone cannot tell you which one you have.
Each heading is a signal signature, not a fixed case — match on the pattern (which views disagree, which nodes diverge from the cluster average, whether the reading is transient or sustained), never on specific percentages, sizes or node counts. Any threshold quoted inside a scenario is illustrative; real clusters arrive with different numbers and the same diagnosis holds. Only error codes (1016, 34507) and documented limits are literal.
Four different things put a subset of nodes ahead of the rest — do not default to slice geometry, rank them by evidence. (a) Slice-to-node imbalance (S9 in redshift-storage-remediation.md): requires a net elastic resize to a node count that does not divide the slice count, AND svv_table_info skew ≈ 1.0. A resize that returned to its original node count (e.g. 14→20→14) restores the original balanced layout and is NOT a slice-geometry cause — rule it out immediately, even if the customer proposes it. Do the slice arithmetic before offering geometry as a candidate at all. The data-slice count is fixed at cluster creation or the last classic resize: original node count × slices per node for that type (ra3.large/ra3.xlplus/dc2.large = 2, ra3.4xlarge = 4, ra3.16xlarge/dc2.8xlarge = 16; confirm with SELECT COUNT(*) FROM stv_slices WHERE type = 'D'). If that count divides evenly by the current node count, every node holds the same number of slices and geometry cannot produce the imbalance — drop it from the answer and commit to whichever remaining cause the evidence supports, rather than presenting two candidates and leaving the customer to run the deciding query. Intermediate node counts along the way are irrelevant; only the current layout matters. (b) Distribution-key skew (S2 here / S13 in redshift-storage-remediation.md): skew_rows ≫ 1 on a large table concentrates rows on specific slices, so any even-ish wave of query spill overflows those nodes first while the cluster average hides it — this is the default explanation for a transient, self-recovering hotspot on a fixed node subset. (c) Inbound datashare data localized onto low-numbered slices (S6): the cluster is a datashare consumer and local permanent tables do not account for the volume. (d) A single runaway spiller on one node (S11): stl_disk_full_diag names the query_id. State the causal link between the hot nodes and the cause as an explicit sentence in the opening — “these nodes saturate because …” — a list of numbers without that link is not a diagnosis.
S1 — disk near-full with Disk Full 1016, VACUUM won’t finish, on a table with a recurring bulk delete+reload cycle: start with stl_disk_full_diag (above) — temp_blocks ≈ 0 confirms the space is persistent data and not spill, which is the first thing to establish; corroborate with sys_query_detail (spilled_block_local_disk, temp). Then attribute per table with svv_table_info/stv_tbl_perm/svv_vacuum_progress, and use stl_vacuum for what a vacuum actually reclaimed in rows and blocks — svv_table_info‘s ghost-row figure is an estimated row count, not a byte measure, so judge it against tbl_rows rather than reading it as reclaimable bytes. Cause = ghost row/tombstone accumulation (maintenance debt, not new data). Near-full, VACUUM cannot reclaim — there is no free space for it to work in, and a failed VACUUM’s own undo/rollback holds space and can block the next VACUUM, so name that chicken-and-egg explicitly rather than just retrying — so the order is strict and must be stated in this sequence: elastic resize / add nodes FIRST to create headroom, and only THEN VACUUM DELETE ONLY (never VACUUM FULL), ordered smallest-reclaimable-first, retrying the largest table last. Do not put VACUUM before the resize for this scenario.
S2 — a near-full spike that self-recovers, where a contiguous subset of compute nodes saturates while the cluster average still looks comfortable: (1) decompose with svv_table_info (+stv_blocklist/svv_diskusage), permanent data flat; (2) consumer is query spill (temp block / temporary block / disk-based) from a concurrency surge; (3) the hot nodes are distribution key/distkey skew onto their slices (cluster average masks it) — and NOT slice-to-node geometry: an elastic resize that ended back at the starting node count changed nothing about the layout, so reject that even when the customer raises it. State the per-node causation as an explicit sentence early in the answer — “only these nodes saturate because the data is distribution-skewed onto the slices on those nodes, so a roughly even spill wave overflows them first while the cluster-wide average hides it” — an answer that reports the numbers without that causal link does not count. Then give the fix list in the same breath, not at the end: QMR (query monitoring rule) on temp blocks, cap WLM / concurrency scaling, ANALYZE, fix the skew, and a per-node 85% alarm (not an average-based one). Reject permanent growth, VACUUM/tombstones, datashare reservation, a bare resize, and a single runaway query.
S3 — querying a shared late-binding VIEW over a DATASHARE consumes far more consumer storage than the filtered result implies (error 34507 = consumer capacity): this is expected datashare behavior, not a bug or physically-downloaded data — compare paths via sys_query_detail/svl_query_summary/stl_scan/svv_table_info/stv_tbl_perm/stv_blocklist and note that querying a shared view reserves/localizes storage for the FULL backing table regardless of WHERE (34507 = consumer capacity), because the view forces a full refresh re-localization that loses the range-restricted scan / block elimination the table path keeps (metadata reservation ≠ result size). Fix: share a pre-filtered / persisted / materialized table, a producer retention filter, partition the shared object, and give the consumer headroom.
S5 — very high daily spill volume against low permanent utilization, with many objects in pg_automv: trace via svl_mv_refresh_status, enumerate svv_mv_info/stv_mv_info — the cause is stale AutoMV (automated materialized view) auto-refresh, i.e. materialized view maintenance debt rather than data growth. Individual pg_automv objects can’t be dropped; the only fix is setting auto_mv=false in the cluster parameter group and rebooting.
S6 — a contiguous low-numbered node group materially fuller than the rest, which the customer attributes to multi-TB tombstones: check stv_blocklist/svv_diskusage/stv_node_storage_capacity for capacity, then measure the tombstone load with the two documented signals — not stv_partitions.tossed: the per-table tombstone count from svv_diskusage, and tbl_rows - estimated_visible_rows (ghost_rows) from the anchor query. Both near zero ⇒ tossed/tombstones are tiny, nothing to reclaim — the tombstone theory is refuted and the space must be attributed to something else. Attribute it with one measurement rather than inferring from the shape: read svv_tables_space_usage per node (local_perm_tables_space_used, local_temp_tables_space_used, datasharing_tables_space_used against capacity) and see which bucket carries the excess on the heavy nodes. Then branch: (a) datasharing_tables_space_used explains the excess ⇒ the consumer is live inbound datashare data localized onto those slices — commit to that as the verdict. Shared blocks localize onto a fixed set of slices and elastic resizes preserve that placement, which is exactly why the imbalance survives repeated elastic resizes; a datashare consumer whose heavy nodes persist across resizes while local perm data doesn’t account for the volume is the fingerprint. (b) The datasharing bucket is ~0 and the imbalance is in local perm data itself, with every table at skew ≈ 1.0 ⇒ slice-to-node geometry — that is S9 in redshift-storage-remediation.md, not this. Whichever nodes are heavy is incidental; the bucket is the diagnosis. Fix for (a): classic resize to rebuild the slice layout + producer distribution key/distkey change; not VACUUM or RMS garbage collection.
S7 — after a resize, disk creeps up at a steady slow rate and is reset only by a periodic reboot; datasharing consumer: decompose permanent vs datasharing per node with svv_tables_space_usage — local_perm_tables_space_used flat while datasharing_tables_space_used climbs is the whole diagnosis; corroborate with svv_table_info/svv_diskusage/stv_blocklist. Cause = datashare consumer cache hydration (persists at idle, rebuilds after reboot; VACUUM/ANALYZE irrelevant). Rule out tombstone + temp spill. Fix: stop the periodic reboots; Redshift reclaims the cache at internal thresholds. Not VACUUM, not scaling back nodes. Before calling a low or dropped disk-utilization reading “expected cache behavior,” check whether the drop is sudden, sustained, and lines up with a maintenance/patch date (compare cluster version/patch history) — a drop that persists across multiple reboots after a specific patch is a possible patch regression, not routine cache behavior, and should be escalated with that timeline rather than waved off on timing alone. Separately, on a datashare consumer, a temp-block spike that tracks the producer’s write activity (not the consumer’s own workload) can be the producer’s writes invalidating the consumer’s cached datashare metadata, forcing a costly re-fetch for the shared tables being queried — this can dwarf ordinary query spill; the fix is coordinating producer write timing away from consumer query windows, or moving the largest shared tables to Spectrum instead of a datashare (no local metadata caching to invalidate).
S8 — STV_TBL_PERM full of localhost@ (temp=0, no PG_CLASS); disk sawtooths between a post-restart floor and an under-load ceiling, reset by restart: stv_tbl_perm/stv_node_storage_capacity/sys_query_detail/svv_diskusage, plus the anchor query’s tbl_rows - estimated_visible_rows (ghost_rows) and the svv_diskusage tombstone count. localhost@ = expected RA3 cross-database internal relations (block_count = logical managed storage / RMS, not local SSD); not orphaned/defect. Confirm the split with svv_tables_space_usage: a sawtooth in local_temp_tables_space_used against a flat local_perm_tables_space_used is the signature. Sawtooth = transient working-set spill / cache on local SSD cleared by restart; ghost_rows and tombstones both ≈0 ⇒ nothing to vacuum (no tombstone to reclaim). Fix: reduce spill, larger node type, WLM cleanup.
S10 — a provisioned snapshot restored into Serverless reports a footprint several times the source size; zero-ETL from Aurora in the picture: decompose it, don’t call it monolithically “expected” — attribute with svv_table_info, review sys_serverless_usage, VACUUM post-restore bloat, and prune recovery points. The three real drivers: (a) per-slice preallocation / minimum block allocation — Serverless spreads the restored data over many more slices and each slice takes a minimum block allocation, so the same logical data reports far larger (review DISTSTYLE ALL tables, which pay that cost on every slice); (b) real zero-etl integration data (svv_integration_table_state; pause/filter if test-only); (c) recovery-point/backup storage.
S11 — Disk Full 1016 on a single node while managed storage still has ample free space; join keys cast to varchar: red herring — free managed storage ≠ no disk-full. sys_query_detail/svl_query_summary/svl_query_metrics_summary/stl_query_metrics: query spill (query_temp_blocks_to_disk / blocks_to_disk / spilled_block_local_disk) exhausts the node’s local SSD. The varchar casts defeat the distribution key → broadcast/redistribution concentrating spill on one node. Fix: remove casts, better DISTKEY / DISTSTYLE, guardrail QMR on query_temp_blocks_to_disk + max_execution_time + lower concurrency. Not VACUUM, not a capacity resize.
S15 — SUM(size) from svv_table_info far below SUM(used) from stv_node_storage_capacity, often by more than an order of magnitude: expected, different scopes, and an accounting question rather than an emergency — svv_table_info covers permanent user tables only, while stv_node_storage_capacity is raw usage including temp/spill, system/catalog, ghost rows, snapshot/tombstone blocks, metadata, and datashare blocks (RA3 capacity reflects the managed-storage quota). Break the gap down with svv_tables_space_usage first — it attributes the difference across perm / temp / datashared in one query — then stv_tbl_perm (temp=1) / stv_blocklist / svv_diskusage + PercentageDiskSpaceUsed; VACUUM is not the primary fix.
S16 — any snapshot/backup billing question (bill higher than expected, “incremental so it should be cheaper”, cross-region copy billed like full size), very often with AWS Backup in the picture: Resolve two variables BEFORE answering, because each combination has a different correct answer: the snapshot type (automated vs manual — and AWS Backup only ever creates manual snapshots, whatever the customer calls them) and the platform (Serverless/RG vs RA3 provisioned). Never give one blanket “Redshift snapshots are incremental” reply, and do not answer from AWS Backup’s own incremental-copy documentation even if you have it to hand — it describes AWS Backup’s behavior, not Redshift’s per-platform manual-snapshot metering. Pick the cell, then state the type and the platform explicitly in the answer:
| Snapshot type | Serverless / RG | RA3 provisioned |
|---|---|---|
| Automated | Incremental (only changed blocks after the first); free up to 100% of provisioned cluster storage | Same: incremental, free up to 100% of provisioned storage |
| Manual (AWS Backup creates manual snapshots, so it never gets the free allowance) | Metered on unique data blocks across all active manual snapshots — i.e. deduplicated / incremental (since Jun 2026) | NOT deduplicated — each retained manual snapshot bills close to its own full size |
Lead the answer with the verdict for the matching cell, never with a general rule. Automated, either platform → incremental and free up to 100% of provisioned storage, so an unexpected charge is coming from manual snapshots or retention elsewhere, not from these. Manual on Serverless/RG → metered on unique blocks across active manual snapshots, so the customer’s “this should cost less than N full copies” intuition is correct and a full-size bill genuinely warrants investigation. Manual on RA3 provisioned → not deduplicated; each retained manual snapshot bills close to its own full size, so a full-size bill is expected behavior, not a billing error. That last cell is the one where the customer is usually right and the “it must be incremental” intuition is wrong. (1) “The copy is still incremental” is right for automated snapshots and for manual snapshots on Serverless/RG, and wrong for manual-on-RA3 — so establish the cell before either using or rejecting it. (2) “There is no free allowance in the destination region” is never the explanation anywhere: the allowance is a concept offsetting automated snapshot storage against the source cluster’s own provisioned capacity, it has no cross-region counterpart, and it never applied to snapshots (which is all AWS Backup creates) in either region — so its absence explains nothing about a manual-snapshot bill.
Scope gate — read this section only when the customer asks about growth over time or what is driving an increase (“it keeps climbing”, “what is eating the space month over month”, “what changed”). Do NOT fold it into a question about a spike, a stuck cluster, a single full node, snapshot billing, or a datashare footprint — those are answered by the scenarios above, and adding a growth investigation to them makes the answer longer without making it more correct. When it does apply, it is the fourth question in the decomposition, after the first three are settled. This question inverts the usual answer shape. For a spike or a stuck cluster the fix is the answer and the method is supporting detail; for “what is driving the growth” the method is the answer — the customer is asking how to find out — so the opening must carry three things before any remediation: (1) the attribution method itself, stated as the ranked per-table size change over a named time window from SYS_VACUUM_HISTORY.size_before_vacuum, tied to each table’s write pattern; (2) the attributed-vs-unattributed split, in words; (3) what cannot be answered from customer-side views today — composition over time is not retained anywhere public — said up front as a scoped answer, not buried as a closing caveat. Data-lifecycle remediation comes after those three, and name the mechanism rather than the category: a retention limit on the history/append tables (trim to the window the workload actually queries); archiving cold data to S3 with UNLOAD (to an encrypted bucket — add ENCRYPTED KMS_KEY_ID '<arn>' per SKILL.md’s security defaults) and then dropping the archived rows or partitions — the only fix that removes bytes permanently, since VACUUM reclaims deleted rows but cannot shrink data the customer still keeps; a time-series design (date-partitioned tables behind a UNION ALL view) so an old partition is DROPped instead of deleted and vacuumed; and resize for headroom when the trend is genuine growth and the data has to stay. Maintenance commands alone (VACUUM, ANALYZE) cannot fix growth — they reclaim debt, not live data — so a growth answer that stops at VACUUM has not answered it. An answer that leads with remediation and leaves the method and the limits for the end has answered a different question than the one asked. And because a growth question is usually several questions at once, open by stating the conclusion to each question before elaborating on any of them, so the customer holds all four answers before reading any of the reasoning: is vacuum the problem (ghost-row ratio against tbl_rows, so “no, N% reclaimable ≈ ~M points on the gauge, auto-vacuum already returns more than that” or “yes, table X”); what the trend is and where it comes from (CloudWatch over months); what is driving it (the write pattern, in one clause per table class); what you can and cannot attribute (the split, and that composition over time is not retained). Then, and only then, the method in full, then remediation. A reader who stops after the verdict block should hold every conclusion; the elaboration is for the reader who wants to verify them.
“Storage is high” is not one question. Split it before answering: (1) is it really that full — platform first, since on RA3/Serverless local fill is storage + cache + spill; (2) is it maintenance debt — the ghost-row ratio against tbl_rows, never the raw count; (3) how much would VACUUM return — the reclaim estimate in redshift-storage-remediation.md; (4) is it growing, and what is driving it — which needs a time series that no point-in-time view can supply. This section is (4).
The cluster total comes from CloudWatch, and only from CloudWatch. No public system view retains storage history — STV_NODE_STORAGE_CAPACITY, SVV_TABLES_SPACE_USAGE and SVV_TABLE_INFO are point-in-time, so yesterday’s value is gone once you query today’s. Pull PercentageDiskSpaceUsed with the per-node NodeID dimension (the cluster aggregate hides the hottest node), statistic Maximum per period (spill spikes inflate the average and self-recover), over months, not weeks — a short window can invert the answer, reading as flat when the multi-month trend is clearly up, because daily spill churn swamps a modest monthly slope. What the metric counts is everything on disk: permanent tables, ghost rows (a deleted row’s block stays allocated until VACUUM rewrites it), temp/spill, catalog, tombstoned and datashare blocks. It cannot be decomposed, so its slope is the slope of the whole bucket. If the workload is stable the spill baseline is roughly stationary and the slope is mostly permanent growth — but that is an inference; say so.
Per-table growth comes from SYS_VACUUM_HISTORY.size_before_vacuum. Each vacuum run logs the table’s size in 1 MB blocks, so successive runs form a measured size series per table — the only long-horizon size source, because SVV_TABLE_INFO cannot be retained. Attribute the mechanism with SYS_QUERY_DETAIL (table_id, step_name = insert / delete / merge, and output_rows on the same row) and SYS_QUERY_HISTORY.query_type for the statement kind; repeated file loads via STL_LOAD_COMMITS, comparing COUNT(*) to COUNT(DISTINCT filename). In:out ≈ 1 does not mean “reload table” — Redshift implements UPDATE as delete + insert, so it is equally consistent with UPDATE traffic; discriminate by checking whether the same query_id appears in both the insert and delete steps, and by comparing insert volume against the table’s own row count to see whether it actually turns over. Retention for STL_/SYS_ views is 7 days; the S3 Tables long-term retention integration extends SYS_* views only. Derived growth is not measured growth: net rows × bytes-per-row usually lands near the measured size change but can disagree outright — a rolling window cleared by TRUNCATE reads as growing by rows while shrinking by size. Cross-check both and report a disagreement as unresolved, not as a single figure.
Three failure modes travel with this method — the third is the one that gets retracted in front of a customer.
TRUNCATE is invisible. It emits no delete step, so it appears in neither STL_DELETE nor SYS_QUERY_DETAIL. A truncate-and-reload table shows all of its inserts and none of its removals and appears to grow without bound — a small staging table can compute as many times its own size. Restrict to tables above a size floor and discard any whose estimated growth exceeds a large fraction of its current size; that filter also drops legitimate fast-growing small tables, so it costs real signal and you should say which tables it removed.SYS_VACUUM_HISTORY and contributes nothing to the sum while contributing real bytes to the cluster.Composition over time — perm vs temp vs datashare as a series — is the one part of this diagnosis that cannot currently be answered from customer-side views. SVV_TABLES_SPACE_USAGE gives the split for now; nothing public retains it. State that limit plainly rather than papering over it with the per-table sum. Be exact about what needs escalating and what does not. The cluster-wide amount of growth is fully answerable by the customer from CloudWatch — never send them to Support for a number they can read themselves. What only AWS Support can supply is the composition of that growth over time, from internal telemetry that retains the per-node permanent/temp/datashare split historically. So when the customer needs that split — “how much of the increase is permanent data versus temp versus shared” — the correct move is: give them the CloudWatch trend and the per-table attribution you can produce, state that composition-over-time is not exposed customer-side, and recommend a support case that asks specifically for the historical per-node storage composition over the period in question. A precise ask gets a precise answer; “storage is growing, please investigate” does not.
Cross-region specifics, which sit on top of whichever cell applies: the data transfer moves only the changed / incremental blocks and is billed in the source region; the copy’s storage in the destination region is billed at that region’s own backup-storage (S3) rates, governed by the same matrix row as the source. A first/baseline copy is full by definition, so savings only appear from the second copy onward and only while a common ancestor is retained — which also means a lifecycle policy that expires the baseline forces the next copy to re-baseline at full size. Verify rather than assert: run describe-cluster-snapshots in the destination region and compare ActualIncrementalBackupSizeInMegaBytes against TotalBackupSizeInMegaBytes per snapshot, and confirm the matching cell’s metering rule against the current Amazon Redshift backup-storage billing documentation before quoting it — the matrix reflects behavior as of Oct 2026 and metering rules change over time.