{"id":69139,"plugin_id":"plugin_asdk_app_6ae160c3d9e48191aaeffd03cc5ef09d","kind":"skill","collection_source":"plugin_package","comparison_source":null,"observed_at":"2026-10-28T18:07:04.016Z","digest":"8440a24d85c7a47c821703cf34d5cee8a10a6ec22cae27a25f420d7737efe5b6","against":null,"payload":{"description":"Estimates storage requirements for CockroachDB online schema change backfills using SHOW RANGES WITH DETAILS, KEYS, INDEXES. Use before CREATE INDEX, ADD COLUMN with INDEX/UNIQUE, ALTER PRIMARY KEY, CREATE MATERIALIZED VIEW, CREATE TABLE AS, REFRESH, or SET LOCALITY on tables with large per-index footprints, to avoid mid-backfill disk exhaustion.","included_files":[{"relative_path":"references/permissions.md","size_in_bytes":8526}],"name":"schema-change-storage-risk","skill_md_contents":"---\nname: schema-change-storage-risk\ndescription: Estimates storage requirements for CockroachDB online schema change backfills using SHOW RANGES WITH DETAILS, KEYS, INDEXES. Use before CREATE INDEX, ADD COLUMN with INDEX/UNIQUE, ALTER PRIMARY KEY, CREATE MATERIALIZED VIEW, CREATE TABLE AS, REFRESH, or SET LOCALITY on tables with large per-index footprints, to avoid mid-backfill disk exhaustion.\ncompatibility: Requires SQL access. SHOW RANGES WITH DETAILS computes span_stats on demand and is expensive on tables with many ranges; target specific tables. Mirrors official guidance at https://www.cockroachlabs.com/docs/stable/online-schema-changes#estimate-your-storage-capacity-before-performing-online-schema-changes.\n---\n\n# Analyzing Schema Change Storage Risk\n\nEstimates the storage headroom needed to safely run online schema changes.\nMirrors the [official guidance](https://www.cockroachlabs.com/docs/stable/online-schema-changes#estimate-your-storage-capacity-before-performing-online-schema-changes):\nsome operations may temporarily require up to **3× the size of the affected\ntable or index** while the schema change is in flight.\n\nFor ongoing range-distribution monitoring, see\n[analyzing-range-distribution](../analyze-range-distribution/SKILL.md).\n\n## When to Use This Skill\n\nRun a quick estimate before issuing any of these operations on a table whose\nindexes are large (multiple GB per index, or many ranges per index):\n\n- `CREATE INDEX`\n- `ADD COLUMN` with `INDEX` or `UNIQUE`\n- `ALTER PRIMARY KEY`\n- `CREATE MATERIALIZED VIEW`\n- `CREATE TABLE AS`\n- `REFRESH MATERIALIZED VIEW`\n- `ALTER TABLE ... SET LOCALITY` (when the locality change rewrites data)\n\nTables whose indexes are small (kilobytes to a few megabytes) carry trivial\nstorage risk; estimation is unnecessary.\n\n## Background\n\n### How much temporary space does a backfill actually need?\n\nThe honest answer depends on the operation:\n\n- **`CREATE INDEX` / `ADD COLUMN ... UNIQUE`**: needs roughly **1× the size of\n  the new index** — the indexed columns plus the primary key columns, written\n  into a fresh index span. This is typically a small fraction of the table.\n  Worst-case headroom is bounded by the size of that one index.\n- **`ALTER PRIMARY KEY`**: rewrites the primary index and any secondary indexes\n  whose definitions depend on the old PK. Old data sticks around until GC, so\n  peak on-disk usage during the change can approach the size of the table again.\n- **All bulk-ingest backfills**: extra MVCC versions and pre-compaction SSTs\n  add overhead until Pebble compacts and GC runs.\n\nThe official docs round these up into a single conservative recommendation:\nplan for up to **3× the size of the affected table or index** as free space.\nThat figure is a safety bound, not a precise prediction. For most\n`CREATE INDEX` operations the real cost is much smaller; for\n`ALTER PRIMARY KEY` on a large table it is the right ballpark.\n\n### What happens if the cluster runs out of disk mid-backfill?\n\nBackfills bulk-ingest data via `AddSSTable`, which checks the per-store\nremaining capacity before each ingestion. If the remaining fraction falls\nbelow `kv.bulk_io_write.min_capacity_remaining_fraction` (default `0.05`,\ni.e. 5%), the ingest is rejected with `InsufficientSpaceError`. Both the\nlegacy and declarative schema changers translate that error into a job pause\nrequest, so the schema change halts rather than wedging the cluster. To\nresume, free space (e.g. drop unused indexes, expand storage) and resume the\npaused job.\n\nThis is a *reactive* safety net, not a planning tool — by the time it fires,\nforeground writes on the affected store may already be unhealthy.\n\n## Estimating Capacity\n\n### Step 1 — Check free space per store\n\nThe minimum free space across stores is what bounds the schema change, not the\ntotal cluster free space (replicas are spread across nodes).\n\nNo production-safe SQL view exposes per-store capacity. Use the DB Console\n**Overview** → **Storage** page (sorts per-store usage), or scrape the\nper-node Prometheus endpoint and look at the smallest `capacity_available`:\n\n```bash\ncurl -ks https://<node>:8080/_status/vars | grep -E '^capacity( |_used|_available)'\n```\n\n### Step 2 — Estimate the affected table/index size\n\nUse the docs-recommended form of `SHOW RANGES`:\n\n```sql\nSHOW RANGES FROM TABLE <table> WITH DETAILS, KEYS, INDEXES;\n```\n\nThe output includes one row per range, with `range_size_mb` and `index_name`.\nAggregate by index for the per-index totals that matter for capacity planning:\n\n```sql\nWITH r AS (SHOW RANGES FROM TABLE <table> WITH DETAILS, KEYS, INDEXES)\nSELECT\n  index_name,\n  COUNT(*)                              AS range_count,\n  ROUND(SUM(range_size_mb), 2)          AS index_size_mb,\n  ROUND(SUM(range_size_mb) / 1024, 2)   AS index_size_gb\nFROM r\nGROUP BY index_name\nORDER BY index_size_mb DESC;\n```\n\n### Step 3 — Compare against the operation\n\n| Operation                                   | Conservative free-space target (per store)                                  |\n|---------------------------------------------|-----------------------------------------------------------------------------|\n| `CREATE INDEX` / `ADD COLUMN ... UNIQUE`    | Up to 3× the size of the *new* index (its indexed + PK columns).            |\n| `ALTER PRIMARY KEY`                          | Up to 3× the size of the *table* (sum of the relevant indexes from step 2). |\n| `CREATE MATERIALIZED VIEW` / `CREATE TABLE AS` | Up to 3× the expected size of the materialized result.                   |\n\nThe new index does not exist yet, so estimate it from a comparable existing\nindex (e.g. one on similarly typed columns) or from the source columns'\ncontribution to the primary index.\n\nIf the smallest free-space figure from step 1 is well above the target, the\noperation is safe to run. If it is close, free space first (drop unused\nindexes, expand storage) before issuing the DDL.\n\n## Operational Notes\n\n- **`SHOW RANGES ... WITH DETAILS` is expensive.** It computes span statistics\n  on demand. Always target a specific table, never run it cluster-wide, and\n  prefer maintenance windows on tables with thousands of ranges.\n- **Watch the job, not just disk.** If a backfill pauses with\n  `InsufficientSpaceError`, free disk on the affected store and resume the\n  paused schema change job. Check with:\n  ```sql\n  WITH j AS (SHOW JOBS)\n  SELECT job_id, status, error\n  FROM j\n  WHERE job_type = 'SCHEMA CHANGE' AND status = 'paused';\n  ```\n- **Drop unused indexes first.** Often the cheapest way to free headroom\n  before a large backfill is to drop indexes that\n  `crdb_internal.index_usage_statistics` shows are unused (this is one of the\n  12 production-safe `crdb_internal` views, per the\n  [docs](https://www.cockroachlabs.com/docs/stable/crdb-internal)).\n- **Statistics lag.** `range_size_mb` is approximate and can lag actual disk\n  usage; treat estimates as conservative ballparks, not exact figures.\n\n## References\n\n- [Online Schema Changes — Estimate your storage capacity](https://www.cockroachlabs.com/docs/stable/online-schema-changes#estimate-your-storage-capacity-before-performing-online-schema-changes)\n- [SHOW RANGES](https://www.cockroachlabs.com/docs/stable/show-ranges.html)\n\n## Related Skills\n\n- [analyzing-range-distribution](../analyze-range-distribution/SKILL.md) — range count, leaseholder placement, fragmentation\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}