35 lines
1.8 KiB
Markdown
35 lines
1.8 KiB
Markdown
---
|
|
name: db-migration-safety
|
|
description: Use when designing database schemas, writing schema migrations, optimizing slow SQL queries, or planning zero-downtime database changes.
|
|
---
|
|
|
|
# Safe Database Migrations & SQL Optimization
|
|
|
|
## Purpose
|
|
Ensure all database schema changes execute safely in production without blocking table locks, downtime, or data corruption, while optimizing query execution plans.
|
|
|
|
## Safe Migration Rules (Zero-Downtime Pattern)
|
|
|
|
### 1. Adding Columns
|
|
- **Safe:** Adding nullable columns or columns with default values (PostgreSQL >= 11 handles constant defaults instantly without table rewrites).
|
|
- **Unsafe:** Adding `NOT NULL` without a default on large tables (locks table). Use a 3-step migration: add nullable column $\to$ backfill data in batches $\to$ add `NOT NULL` constraint with `NOT VALID` then `VALIDATE CONSTRAINT`.
|
|
|
|
### 2. Renaming & Dropping Columns
|
|
- **Never rename/drop in one step:** Old application instances running during deployment will crash when the column disappears.
|
|
- **Expand/Contract Pattern:**
|
|
1. Add new column.
|
|
2. Write to both old and new columns in application code.
|
|
3. Backfill existing rows.
|
|
4. Switch reads to new column.
|
|
5. Stop writing to old column.
|
|
6. Drop old column.
|
|
|
|
### 3. Adding Indexes Safely
|
|
- In PostgreSQL: Always use `CREATE INDEX CONCURRENTLY` (or `DROP INDEX CONCURRENTLY`) to avoid acquiring exclusive write locks.
|
|
- In MySQL: Use `ALGORITHM=INPLACE, LOCK=NONE` or gh-ost / pt-online-schema-change for heavy tables.
|
|
|
|
## SQL Performance & Query Optimization
|
|
- Analyze queries with `EXPLAIN (ANALYZE, BUFFERS)` (Postgres) or `EXPLAIN ANALYZE` (MySQL).
|
|
- Eliminate Seq Scans / Full Table Scans on high-cardinality tables by adding composite indexes matching query `WHERE` and `ORDER BY` predicates.
|
|
- Prevent N+1 queries by leveraging `JOIN`, eager loading, or DataLoader patterns.
|