release 1.0.0: cost control, 41 tools, 29 skills, custom commands, auto-load
This commit is contained in:
1 parent
a22d8e13b1
commit
ffa9a02c26
97 files changed
+4791
-788
No files matched your search
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: db
|
||||
description: Design schemas, write migrations, or fix query and data problems. Use when adding a table, writing a migration, debugging a slow query, or choosing keys and indexes.
|
||||
---
|
||||
|
||||
# Databases
|
||||
|
||||
The schema is the hardest thing to change in the whole system. Design it for the queries, not
|
||||
the object model.
|
||||
|
||||
## Keys and constraints are the real schema
|
||||
|
||||
- Every table has a primary key; prefer a surrogate `id` unless a natural key is truly stable.
|
||||
- Foreign keys and `NOT NULL` are not optional decoration — they are the constraints that stop
|
||||
bad data at the door instead of in application code six months later.
|
||||
- Unique constraints belong on the thing that must be unique (email, slug), enforced by the
|
||||
database, not by a check-then-insert that races.
|
||||
|
||||
## Migrations are one-way and additive where possible
|
||||
|
||||
- Never edit a migration that has run anywhere. Add a new one.
|
||||
- Destructive changes (drop column, rename, change type) are two migrations: add the new shape,
|
||||
deploy code that writes both, then remove the old in a later release. A single migration that
|
||||
renames a column breaks every old copy of the app still running.
|
||||
- Test a migration against real data volume. `ALTER` on ten rows is instant; on ten million it
|
||||
locks the table.
|
||||
|
||||
## Indexes follow the queries
|
||||
|
||||
Index the columns you filter and join on, in the order the query uses them. A composite index
|
||||
`(a, b)` serves `WHERE a` and `WHERE a, b` but not `WHERE b` alone. Read the query plan
|
||||
(`EXPLAIN`) before adding one — a guess is an index that costs writes and serves nothing.
|
||||
|
||||
## The N+1 is the default bug
|
||||
|
||||
A query per row in a loop is the most common database performance defect. Fetch the set with a
|
||||
join or a batched `WHERE id IN (...)`. If a page does one query per item, that is the fix
|
||||
before any caching.
|
||||
Reference in new issue
Block a user