learningequality / learningequality/studio
Increase database performance and reduce storage needs
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 191
- Forks
- 307
- Avg merge
- 5d 6h
- Merged PRs (30d)
- 10
Description
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.
Overview
- Studio's production database is 1,202 GB;
contentcuration_contentnodeaccounts for 957 GB of it across 16.8M rows. contentnodehas never hadANALYZErun, so the planner chooses plans for the largest table in the database without statistics.- Autovacuum has never run on
contentnodeorassessmentitem(vacuum_count = 0,autovacuum_count = 0). contentnode's indexes measure ~2,000 bytes per entry, against 24–34 bytes for healthy indexes on other tables in the same database — buffer cache is largely fragmented index pages.- 400 GB of the table is base64 thumbnail data in a
TextField(models.py:2116), duplicatingFilerecords that already exist in the content bucket.
Scope
In scope
- Per-table autovacuum and analyze thresholds for
contentnode,assessmentitem, andfile. - The instance-level autovacuum cost limit, currently
-1and falling back tovacuum_cost_limit = 200. - Removal of 12 never-scanned indexes on
contentnodeandfile, totalling 178 GB, around half of them Django'svarchar_pattern_opstwins. A further 39 GB of never-scanned indexes on other tables is measured but not scoped here, including the 33 GB twin oncontentnode's primary key, which is deferred with theuuidmigration. - Reindexing
contentnode's surviving indexes to reclaim fragmented pages. - Relocation of
contentnode.thumbnail_encodingbase64 data toFilerecords in the content bucket. - A cap on Cloud SQL disk autoresize, which the Terraform db module does not manage.
- Reducing the production instance tier.
Out of scope
- DMS migration onto a smaller-disk instance, which this work unblocks.
- Migrating char primary keys to native Postgres
uuid. - MPTT write amplification.
Strategy
Ordering is load-bearing.
- Autovacuum and analyze thresholds. Later gains re-accumulate without them.
- Drop never-scanned indexes.
DROP INDEX CONCURRENTLYneeds no additional disk, and frees headroom for the steps below. - Relocate thumbnail data. 16.8M UPDATEs plus content-bucket writes, so it depends on step 2's headroom and reduced index count.
- Reindex
contentnode's surviving indexes, one at a time, largest first. Must follow step 3, or the UPDATEs re-bloat freshly built indexes. - Reduce the instance tier.
Each reindex needs free space equal to the index being rebuilt, so headroom compounds through step 4. Btree deduplication applies only to freshly built indexes, so low-cardinality columns such as original_channel_id (877 distinct values across 16.8M rows) shrink only there.
Steps 3 and 4 run as management commands invoked from make deploy-migrate, per the procedure at Makefile:32-40. Both are exercised on hotfixes, whose database holds a full-size copy of the production data.
Nulling thumbnail_encoding leaves 400 GB of TOAST dead but not returned to the OS; VACUUM only marks it reusable within the relation.
Testing Requirements
- Capture the same measurements before and after each step:
pg_database_size, per-table heap/index/TOAST split, and per-index size,idx_scan, and bytes-per-entry. - Verify every step on
hotfixesbeforemaster. - Confirm
pg_index.indisvalidafter anyCONCURRENTLYoperation; a failed build leaves an invalid index needing manual cleanup. - Confirm no new slow-query-log entries attributable to dropped indexes.
log_min_duration_statementis already 500ms. - Confirm
last_autovacuumandlast_analyzeare non-null and recent oncontentnode,assessmentitem, andfileafter step 1.
AI usage
Drafted with Claude Code, which measured the production database directly through read-only queries run via the disposable debugging job; the table, index, bytes-per-entry, vacuum state, and column-width figures here come from those measurements. I confirmed the findings against the Terraform and Django source, and set the framing, scope, sequencing, and target branch.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
This issue is explicitly not open for contribution and spans database operations, Django management commands, and Terraform. Start with models.py:2116 and Makefile:32-40, then review the stated measurements and verify the procedure on hotfixes before master. Done means each step meets its listed vacuum, index, storage, slow-query, and integrity checks.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- django, postgresql, python, terraform
- Domain
- cloud, databases, devops, performance
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 15/100