Loading...
Loading...
Compare original and translation side by side
undefinedundefined
**Step 2**: Apply normalization rules (at minimum 3NF):
- **1NF**: No repeating groups, atomic values
- **2NF**: No partial dependencies on composite keys
- **3NF**: No transitive dependencies
- **Load** `references/normalization-guide.md` for detailed examples
**Step 3**: Add essential elements to every table:
```sql
CREATE TABLE your_table (
-- Primary key (required)
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Business columns with proper types
name VARCHAR(200) NOT NULL, -- Use appropriate lengths
-- Audit columns (always include)
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL
);
**步骤2**:应用规范化规则(至少达到3NF):
- **1NF**:无重复组,原子值
- **2NF**:复合主键无部分依赖
- **3NF**:无传递依赖
- 查看`references/normalization-guide.md`获取详细示例
**步骤3**:为每个表添加必要元素:
```sql
CREATE TABLE your_table (
-- 主键(必填)
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- 带有合适类型的业务列
name VARCHAR(200) NOT NULL, -- 使用合适的长度
-- 审计列(始终包含)
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL
);| Rule | Reason |
|---|---|
| Every table has PRIMARY KEY | Ensures row uniqueness, enables relationships |
| Foreign keys defined explicitly | Enforces referential integrity, prevents orphans |
| Index all foreign keys | Prevents slow JOINs, critical for performance |
| NOT NULL on required fields | Data integrity, prevents NULL pollution |
| Audit columns (created_at, updated_at) | Track changes, debugging, compliance |
| Appropriate data types | Storage efficiency, validation, indexing |
| Check constraints for enums | Enforces valid values at database level |
| ON DELETE/UPDATE rules specified | Prevents accidental data loss or orphans |
| 规则 | 原因 |
|---|---|
| 每个表都要有主键 | 确保行唯一性,支持关系定义 |
| 显式定义外键 | 强制引用完整性,防止孤立记录 |
| 为所有外键创建索引 | 避免慢JOIN,对性能至关重要 |
| 必填字段设置NOT NULL | 保证数据完整性,防止NULL污染 |
| 包含审计列(created_at、updated_at) | 追踪变更、调试、合规需求 |
| 使用合适的数据类型 | 存储高效、支持验证、便于索引 |
| 为枚举类型添加Check约束 | 在数据库层面强制有效值 |
| 指定ON DELETE/UPDATE规则 | 防止意外数据丢失或孤立记录 |
| Anti-Pattern | Why It's Bad |
|---|---|
| VARCHAR(MAX) everywhere | Wastes space, slows indexes, no validation |
| Dates as VARCHAR | No date math, no validation, sorting broken |
| Missing foreign keys | No referential integrity, orphaned records |
| Premature denormalization | Hard to maintain, data anomalies |
| EAV (Entity-Attribute-Value) | Query complexity, no type safety, slow |
| Polymorphic associations | No foreign key integrity, complex queries |
| Circular dependencies | Impossible to populate, breaks CASCADE |
| No indexes on foreign keys | Extremely slow JOINs, performance killer |
| 反模式 | 危害 |
|---|---|
| 到处使用VARCHAR(MAX) | 浪费空间、减慢索引、无验证机制 |
| 日期存储为VARCHAR | 无法进行日期运算、无验证、排序失效 |
| 缺失外键 | 无引用完整性,产生孤立记录 |
| 过早反规范化 | 难以维护,出现数据异常 |
| EAV(实体-属性-值) | 查询复杂、无类型安全、性能低下 |
| 多态关联 | 无外键完整性,查询逻辑复杂 |
| 循环依赖 | 无法填充数据,破坏CASCADE规则 |
| 外键未加索引 | JOIN操作极慢,严重影响性能 |
-- ❌ Bad
CREATE TABLE users (
email VARCHAR(255),
name VARCHAR(100)
);
-- ✅ Good
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL
);-- ❌ 错误示例
CREATE TABLE users (
email VARCHAR(255),
name VARCHAR(100)
);
-- ✅ 正确示例
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL
);-- ❌ Bad
CREATE TABLE orders (
id UUID PRIMARY KEY,
user_id UUID -- No constraint!
);
-- ✅ Good
CREATE TABLE orders (
id UUID PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE
);
-- Index the foreign key
CREATE INDEX idx_orders_user_id ON orders(user_id);-- ❌ 错误示例
CREATE TABLE orders (
id UUID PRIMARY KEY,
user_id UUID -- 无约束!
);
-- ✅ 正确示例
CREATE TABLE orders (
id UUID PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE
);
-- 为外键创建索引
CREATE INDEX idx_orders_user_id ON orders(user_id);-- ❌ Bad
CREATE TABLE products (
name VARCHAR(MAX),
sku VARCHAR(MAX),
status VARCHAR(MAX)
);
-- ✅ Good
CREATE TABLE products (
name VARCHAR(200) NOT NULL,
sku VARCHAR(50) UNIQUE NOT NULL,
status VARCHAR(20) NOT NULL
CHECK (status IN ('draft', 'active', 'archived'))
);-- ❌ 错误示例
CREATE TABLE products (
name VARCHAR(MAX),
sku VARCHAR(MAX),
status VARCHAR(MAX)
);
-- ✅ 正确示例
CREATE TABLE products (
name VARCHAR(200) NOT NULL,
sku VARCHAR(50) UNIQUE NOT NULL,
status VARCHAR(20) NOT NULL
CHECK (status IN ('draft', 'active', 'archived'))
);-- ❌ Bad
CREATE TABLE events (
event_date VARCHAR(50) -- '2025-12-15' or 'Dec 15, 2025'?
);
-- ✅ Good
CREATE TABLE events (
event_date DATE NOT NULL, -- Validated, sortable
event_time TIMESTAMPTZ -- With timezone
);-- ❌ 错误示例
CREATE TABLE events (
event_date VARCHAR(50) -- 格式混乱:'2025-12-15' 或 'Dec 15, 2025'?
);
-- ✅ 正确示例
CREATE TABLE events (
event_date DATE NOT NULL, -- 可验证、可排序
event_time TIMESTAMPTZ -- 带时区
);-- Always index foreign keys
CREATE TABLE order_items (
order_id UUID NOT NULL REFERENCES orders(id),
product_id UUID NOT NULL REFERENCES products(id)
);
-- ✅ Required indexes
CREATE INDEX idx_order_items_order_id ON order_items(order_id);
CREATE INDEX idx_order_items_product_id ON order_items(product_id);-- 始终为外键创建索引
CREATE TABLE order_items (
order_id UUID NOT NULL REFERENCES orders(id),
product_id UUID NOT NULL REFERENCES products(id)
);
-- ✅ 必填索引
CREATE INDEX idx_order_items_order_id ON order_items(order_id);
CREATE INDEX idx_order_items_product_id ON order_items(product_id);-- ❌ Bad
CREATE TABLE products (
id UUID PRIMARY KEY,
name VARCHAR(200)
);
-- ✅ Good
CREATE TABLE products (
id UUID PRIMARY KEY,
name VARCHAR(200) NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL
);
-- Auto-update trigger (PostgreSQL)
CREATE TRIGGER products_updated_at
BEFORE UPDATE ON products
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();-- ❌ 错误示例
CREATE TABLE products (
id UUID PRIMARY KEY,
name VARCHAR(200)
);
-- ✅ 正确示例
CREATE TABLE products (
id UUID PRIMARY KEY,
name VARCHAR(200) NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL
);
-- 自动更新触发器(PostgreSQL)
CREATE TRIGGER products_updated_at
BEFORE UPDATE ON products
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();-- ❌ Bad (EAV)
CREATE TABLE product_attributes (
product_id UUID,
attribute_name VARCHAR(100), -- 'color', 'size', 'price'
attribute_value TEXT -- Everything as text!
);
-- ✅ Good (Structured + JSONB)
CREATE TABLE products (
id UUID PRIMARY KEY,
name VARCHAR(200) NOT NULL,
price DECIMAL(10,2) NOT NULL, -- Required fields as columns
color VARCHAR(50), -- Common attributes as columns
size VARCHAR(20),
attributes JSONB -- Optional/dynamic attributes
);
-- Index JSONB
CREATE INDEX idx_products_attributes ON products USING GIN(attributes);references/error-catalog.md-- ❌ 错误示例(EAV模式)
CREATE TABLE product_attributes (
product_id UUID,
attribute_name VARCHAR(100), -- 'color', 'size', 'price'
attribute_value TEXT -- 所有值都存为文本!
);
-- ✅ 正确示例(结构化+JSONB)
CREATE TABLE products (
id UUID PRIMARY KEY,
name VARCHAR(200) NOT NULL,
price DECIMAL(10,2) NOT NULL, -- 必填字段作为列
color VARCHAR(50), -- 通用属性作为列
size VARCHAR(20),
attributes JSONB -- 可选/动态属性
);
-- 为JSONB创建索引
CREATE INDEX idx_products_attributes ON products USING GIN(attributes);references/error-catalog.md| Pattern | Use Case | Template |
|---|---|---|
| Basic CRUD | Standard users/products/orders | |
| One-to-One | User → Profile | |
| One-to-Many | User → Orders | |
| Many-to-Many | Students ↔ Courses | |
| Hierarchical | Categories tree, org chart | |
| Soft Delete | Mark deleted, keep history | |
| Versioning | Track changes over time | |
| Multi-Tenant | Isolated data per organization | |
| 模式 | 适用场景 | 模板 |
|---|---|---|
| 基础CRUD | 标准用户/产品/订单场景 | |
| 一对一 | 用户→用户资料 | |
| 一对多 | 用户→订单 | |
| 多对多 | 学生↔课程 | |
| 层级结构 | 分类树、组织架构 | |
| 软删除 | 标记删除、保留历史 | |
| 版本控制 | 追踪记录变更历史 | |
| 多租户 | 按组织隔离数据 | |
| Form | Rule | Example |
|---|---|---|
| 1NF | Atomic values, no repeating groups | |
| 2NF | 1NF + no partial dependencies | Composite key dependency → separate table |
| 3NF | 2NF + no transitive dependencies | |
| BCNF | 3NF + every determinant is candidate key | Rare edge cases |
| 4NF | BCNF + no multi-valued dependencies | Complex many-to-many |
| 5NF | 4NF + no join dependencies | Very rare, academic |
references/normalization-guide.md| 范式 | 规则 | 示例 |
|---|---|---|
| 1NF | 原子值,无重复组 | |
| 2NF | 满足1NF且无部分依赖 | 复合主键依赖→拆分到独立表 |
| 3NF | 满足2NF且无传递依赖 | |
| BCNF | 满足3NF且每个决定因素都是候选键 | 罕见边缘场景 |
| 4NF | 满足BCNF且无多值依赖 | 复杂多对多场景 |
| 5NF | 满足4NF且无连接依赖 | 非常罕见,学术场景 |
references/normalization-guide.md-- Primary Keys
id UUID PRIMARY KEY DEFAULT gen_random_uuid()
-- OR for performance-critical:
id BIGSERIAL PRIMARY KEY
-- Text
name VARCHAR(200) NOT NULL
description TEXT
code CHAR(10) -- Fixed-length codes only
-- Numbers
price DECIMAL(10,2) NOT NULL -- Money: NEVER use FLOAT
quantity INT NOT NULL
rating DECIMAL(3,2) -- 0.00 to 9.99
-- Dates/Times
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL -- With timezone
event_date DATE
duration INTERVAL
-- Boolean
is_active BOOLEAN DEFAULT true NOT NULL
-- JSON
attributes JSONB -- Binary, faster, indexable
-- Enum Alternative (preferred over ENUM type)
status VARCHAR(20) NOT NULL
CHECK (status IN ('draft', 'active', 'archived'))-- 主键
id UUID PRIMARY KEY DEFAULT gen_random_uuid()
-- 或针对性能敏感场景:
id BIGSERIAL PRIMARY KEY
-- 文本类型
name VARCHAR(200) NOT NULL
description TEXT
code CHAR(10) -- 仅用于固定长度编码
-- 数字类型
price DECIMAL(10,2) NOT NULL -- 金额:绝不要用FLOAT
quantity INT NOT NULL
rating DECIMAL(3,2) -- 范围0.00到9.99
-- 日期/时间类型
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL -- 带时区
event_date DATE
duration INTERVAL
-- 布尔类型
is_active BOOLEAN DEFAULT true NOT NULL
-- JSON类型
attributes JSONB -- 二进制存储,更快,可索引
-- 枚举替代方案(优先于ENUM类型)
status VARCHAR(20) NOT NULL
CHECK (status IN ('draft', 'active', 'archived'))-- MySQL doesn't have:
TIMESTAMPTZ -- Use TIMESTAMP (stored as UTC)
gen_random_uuid() -- Use UUID() function
JSONB -- Use JSON (same performance in 8.0+)
-- MySQL equivalent:
id CHAR(36) PRIMARY KEY DEFAULT (UUID())
-- OR:
id BIGINT AUTO_INCREMENT PRIMARY KEY
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
attributes JSONreferences/data-types-guide.md-- MySQL不支持:
TIMESTAMPTZ -- 使用TIMESTAMP(以UTC存储)
gen_random_uuid() -- 使用UUID()函数
JSONB -- 使用JSON(8.0+版本性能相当)
-- MySQL等效写法:
id CHAR(36) PRIMARY KEY DEFAULT (UUID())
-- 或:
id BIGINT AUTO_INCREMENT PRIMARY KEY
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
attributes JSONreferences/data-types-guide.mdreferences/schema-design-patterns.mdreferences/schema-design-patterns.mdreferences/normalization-guide.mdreferences/normalization-guide.mdreferences/relationship-patterns.mdreferences/relationship-patterns.mdreferences/data-types-guide.mdreferences/data-types-guide.mdreferences/constraints-catalog.mdreferences/constraints-catalog.mdreferences/error-catalog.mdreferences/error-catalog.mdCREATE TABLE users (
email VARCHAR(MAX), -- Issue: No primary key, VARCHAR(MAX)
password VARCHAR(MAX),
created VARCHAR(50) -- Issue: Date as string
);
CREATE TABLE orders (
id UUID PRIMARY KEY,
user_email VARCHAR(MAX), -- Issue: No foreign key
total VARCHAR(20), -- Issue: Money as string
status VARCHAR(MAX) -- Issue: No validation
);CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL
);
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
total DECIMAL(10,2) NOT NULL CHECK (total >= 0),
status VARCHAR(20) NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'processing', 'shipped', 'delivered', 'canceled')),
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL
);
CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_orders_status ON orders(status);CREATE TABLE users (
email VARCHAR(MAX), -- 问题:无主键、使用VARCHAR(MAX)
password VARCHAR(MAX),
created VARCHAR(50) -- 问题:日期存为字符串
);
CREATE TABLE orders (
id UUID PRIMARY KEY,
user_email VARCHAR(MAX), -- 问题:无外键
total VARCHAR(20), -- 问题:金额存为字符串
status VARCHAR(MAX) -- 问题:无验证机制
);CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL
);
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
total DECIMAL(10,2) NOT NULL CHECK (total >= 0),
status VARCHAR(20) NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'processing', 'shipped', 'delivered', 'canceled')),
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL
);
CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_orders_status ON orders(status);references/error-catalog.mdreferences/error-catalog.mdtemplates/basic-schema.sqltemplates/relationships.sqltemplates/constraints.sqltemplates/audit-columns.sqlreferences/normalization-guide.mdreferences/relationship-patterns.mdreferences/data-types-guide.mdreferences/constraints-catalog.mdreferences/schema-design-patterns.mdreferences/error-catalog.mdtemplates/basic-schema.sqltemplates/relationships.sqltemplates/constraints.sqltemplates/audit-columns.sqlreferences/normalization-guide.mdreferences/relationship-patterns.mdreferences/data-types-guide.mdreferences/constraints-catalog.mdreferences/schema-design-patterns.mdreferences/error-catalog.md