database-schema-designer

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Database Schema Designer

数据库架构设计工具

Design production-ready database schemas with best practices built-in.

设计符合最佳实践的生产级数据库架构。

Quick Start

快速开始

Just describe your data model:
design a schema for an e-commerce platform with users, products, orders
You'll get a complete SQL schema like:
sql
CREATE TABLE users (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  email VARCHAR(255) UNIQUE NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE orders (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  user_id BIGINT NOT NULL REFERENCES users(id),
  total DECIMAL(10,2) NOT NULL,
  INDEX idx_orders_user (user_id)
);
What to include in your request:
  • Entities (users, products, orders)
  • Key relationships (users have orders, orders have items)
  • Scale hints (high-traffic, millions of records)
  • Database preference (SQL/NoSQL) - defaults to SQL if not specified

只需描述你的数据模型:
design a schema for an e-commerce platform with users, products, orders
你将得到完整的SQL架构,例如:
sql
CREATE TABLE users (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  email VARCHAR(255) UNIQUE NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE orders (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  user_id BIGINT NOT NULL REFERENCES users(id),
  total DECIMAL(10,2) NOT NULL,
  INDEX idx_orders_user (user_id)
);
请求中需包含的内容:
  • 实体(用户、商品、订单等)
  • 关键关系(用户拥有订单、订单包含商品项等)
  • 规模提示(高流量、百万级记录等)
  • 数据库偏好(SQL/NoSQL)- 未指定时默认使用SQL

Triggers

触发词

TriggerExample
design schema
"design a schema for user authentication"
database design
"database design for multi-tenant SaaS"
create tables
"create tables for a blog system"
schema for
"schema for inventory management"
model data
"model data for real-time analytics"
I need a database
"I need a database for tracking orders"
design NoSQL
"design NoSQL schema for product catalog"

触发词示例
design schema
"design a schema for user authentication"
database design
"database design for multi-tenant SaaS"
create tables
"create tables for a blog system"
schema for
"schema for inventory management"
model data
"model data for real-time analytics"
I need a database
"I need a database for tracking orders"
design NoSQL
"design NoSQL schema for product catalog"

Key Terms

关键术语

TermDefinition
NormalizationOrganizing data to reduce redundancy (1NF → 2NF → 3NF)
3NFThird Normal Form - no transitive dependencies between columns
OLTPOnline Transaction Processing - write-heavy, needs normalization
OLAPOnline Analytical Processing - read-heavy, benefits from denormalization
Foreign Key (FK)Column that references another table's primary key
IndexData structure that speeds up queries (at cost of slower writes)
Access PatternHow your app reads/writes data (queries, joins, filters)
DenormalizationIntentionally duplicating data to speed up reads

术语定义
Normalization(规范化)组织数据以减少冗余(1NF → 2NF → 3NF)
3NF第三范式 - 列之间不存在传递依赖
OLTP在线事务处理 - 写密集型场景,需采用规范化设计
OLAP在线分析处理 - 读密集型场景,采用反规范化设计更有利
Foreign Key (FK)(外键)引用另一张表主键的列
Index(索引)加速查询的数据结构(会降低写入速度)
Access Pattern(访问模式)应用读写数据的方式(查询、关联、过滤等)
Denormalization(反规范化)为加速读取而故意重复数据

Quick Reference

快速参考

TaskApproachKey Consideration
New schemaNormalize to 3NF firstDomain modeling over UI
SQL vs NoSQLAccess patterns decideRead/write ratio matters
Primary keysINT or UUIDUUID for distributed systems
Foreign keysAlways constrainON DELETE strategy critical
IndexesFKs + WHERE columnsColumn order matters
MigrationsAlways reversibleBackward compatible first

任务方法关键注意事项
新架构设计先规范化到3NF优先领域建模而非UI建模
SQL vs NoSQL选择由访问模式决定读写比是关键因素
主键选择INT或UUID分布式系统使用UUID
外键始终添加约束ON DELETE策略至关重要
索引外键+WHERE条件列列的顺序很重要
架构迁移始终支持回滚优先保证向后兼容

Process Overview

流程概述

Your Data Requirements
    |
    v
+-----------------------------------------------------+
| Phase 1: ANALYSIS                                   |
| * Identify entities and relationships               |
| * Determine access patterns (read vs write heavy)   |
| * Choose SQL or NoSQL based on requirements         |
+-----------------------------------------------------+
    |
    v
+-----------------------------------------------------+
| Phase 2: DESIGN                                     |
| * Normalize to 3NF (SQL) or embed/reference (NoSQL) |
| * Define primary keys and foreign keys              |
| * Choose appropriate data types                     |
| * Add constraints (UNIQUE, CHECK, NOT NULL)         |
+-----------------------------------------------------+
    |
    v
+-----------------------------------------------------+
| Phase 3: OPTIMIZE                                   |
| * Plan indexing strategy                            |
| * Consider denormalization for read-heavy queries   |
| * Add timestamps (created_at, updated_at)           |
+-----------------------------------------------------+
    |
    v
+-----------------------------------------------------+
| Phase 4: MIGRATE                                    |
| * Generate migration scripts (up + down)            |
| * Ensure backward compatibility                     |
| * Plan zero-downtime deployment                     |
+-----------------------------------------------------+
    |
    v
Production-Ready Schema

你的数据需求
    |
    v
+-----------------------------------------------------+
| 阶段1:分析                                   |
| * 识别实体和关系               |
| * 确定访问模式(读密集型 vs 写密集型)   |
| * 根据需求选择SQL或NoSQL         |
+-----------------------------------------------------+
    |
    v
+-----------------------------------------------------+
| 阶段2:设计                                     |
| * SQL规范化到3NF,NoSQL选择嵌入/引用 |
| * 定义主键和外键              |
| * 选择合适的数据类型                     |
| * 添加约束(UNIQUE、CHECK、NOT NULL)         |
+-----------------------------------------------------+
    |
    v
+-----------------------------------------------------+
| 阶段3:优化                                   |
| * 规划索引策略                            |
| * 读密集型查询考虑反规范化   |
| * 添加时间戳(created_at、updated_at)           |
+-----------------------------------------------------+
    |
    v
+-----------------------------------------------------+
| 阶段4:迁移                                    |
| * 生成迁移脚本(升级+回滚)            |
| * 确保向后兼容                     |
| * 规划零停机部署                     |
+-----------------------------------------------------+
    |
    v
生产级可用架构

Commands

命令

CommandWhen to UseAction
design schema for {domain}
Starting freshFull schema generation
normalize {table}
Fixing existing tableApply normalization rules
add indexes for {table}
Performance issuesGenerate index strategy
migration for {change}
Schema evolutionCreate reversible migration
review schema
Code reviewAudit existing schema
Workflow: Start with
design schema
→ iterate with
normalize
→ optimize with
add indexes
→ evolve with
migration

命令使用场景操作
design schema for {domain}
从零开始设计生成完整架构
normalize {table}
修复现有表应用规范化规则
add indexes for {table}
存在性能问题生成索引策略
migration for {change}
架构演进创建支持回滚的迁移脚本
review schema
代码评审审计现有架构
工作流:
design schema
开始 → 用
normalize
迭代 → 用
add indexes
优化 → 用
migration
演进

Core Principles

核心原则

PrincipleWHYImplementation
Model the DomainUI changes, domain doesn'tEntity names reflect business concepts
Data Integrity FirstCorruption is costly to fixConstraints at database level
Optimize for Access PatternCan't optimize for bothOLTP: normalized, OLAP: denormalized
Plan for ScaleRetrofitting is painfulIndex strategy + partitioning plan

原则原因实现方式
领域建模优先UI会变化,但领域不会实体名称反映业务概念
数据完整性优先数据损坏修复成本极高在数据库层面添加约束
针对访问模式优化无法同时兼顾所有场景OLTP用规范化,OLAP用反规范化
提前规划扩展性后期改造难度大索引策略+分区规划

Anti-Patterns

反模式

AvoidWhyInstead
VARCHAR(255) everywhereWastes storage, hides intentSize appropriately per field
FLOAT for moneyRounding errorsDECIMAL(10,2)
Missing FK constraintsOrphaned dataAlways define foreign keys
No indexes on FKsSlow JOINsIndex every foreign key
Storing dates as stringsCan't compare/sortDATE, TIMESTAMP types
SELECT * in queriesFetches unnecessary dataExplicit column lists
Non-reversible migrationsCan't rollbackAlways write DOWN migration
Adding NOT NULL without defaultBreaks existing rowsAdd nullable, backfill, then constrain

需避免的做法原因替代方案
到处使用VARCHAR(255)浪费存储空间,无法明确字段用途根据字段实际需求设置合适长度
用FLOAT存储金额会出现舍入误差使用DECIMAL(10,2)
缺失外键约束会产生孤立数据始终定义外键
外键上未加索引关联查询缓慢为所有外键添加索引
用字符串存储日期无法比较/排序使用DATE、TIMESTAMP类型
查询中使用SELECT *会获取不必要的数据显式指定列名
不支持回滚的迁移无法回滚到之前的状态始终编写DOWN迁移脚本
添加NOT NULL约束但无默认值会破坏现有数据行先添加可空列,回填数据后再设置约束

Verification Checklist

验证清单

After designing a schema:
  • Every table has a primary key
  • All relationships have foreign key constraints
  • ON DELETE strategy defined for each FK
  • Indexes exist on all foreign keys
  • Indexes exist on frequently queried columns
  • Appropriate data types (DECIMAL for money, etc.)
  • NOT NULL on required fields
  • UNIQUE constraints where needed
  • CHECK constraints for validation
  • created_at and updated_at timestamps
  • Migration scripts are reversible
  • Tested on staging with production data

<details> <summary><strong>Deep Dive: Normalization (SQL)</strong></summary>
设计完架构后,请检查:
  • 每张表都有主键
  • 所有关系都定义了外键约束
  • 每个外键都指定了ON DELETE策略
  • 所有外键都有对应的索引
  • 频繁查询的列都有索引
  • 使用了合适的数据类型(如金额用DECIMAL)
  • 必填字段设置了NOT NULL
  • 需要唯一值的字段设置了UNIQUE约束
  • 添加了CHECK约束用于验证
  • 包含created_at和updated_at时间戳
  • 迁移脚本支持回滚
  • 已在 staging 环境用生产数据测试

<details> <summary><strong>深入解析:SQL规范化</strong></summary>

Normal Forms

范式

FormRuleViolation Example
1NFAtomic values, no repeating groups
product_ids = '1,2,3'
2NF1NF + no partial dependenciescustomer_name in order_items
3NF2NF + no transitive dependenciescountry derived from postal_code
范式规则违反示例
1NF原子值,无重复组
product_ids = '1,2,3'
2NF满足1NF且无部分依赖order_items表中包含customer_name
3NF满足2NF且无传递依赖customer表中country由postal_code推导得出

1st Normal Form (1NF)

第一范式(1NF)

sql
-- BAD: Multiple values in column
CREATE TABLE orders (
  id INT PRIMARY KEY,
  product_ids VARCHAR(255)  -- '101,102,103'
);

-- GOOD: Separate table for items
CREATE TABLE orders (
  id INT PRIMARY KEY,
  customer_id INT
);

CREATE TABLE order_items (
  id INT PRIMARY KEY,
  order_id INT REFERENCES orders(id),
  product_id INT
);
sql
-- 错误:列中包含多个值
CREATE TABLE orders (
  id INT PRIMARY KEY,
  product_ids VARCHAR(255)  -- '101,102,103'
);

-- 正确:拆分到单独的表
CREATE TABLE orders (
  id INT PRIMARY KEY,
  customer_id INT
);

CREATE TABLE order_items (
  id INT PRIMARY KEY,
  order_id INT REFERENCES orders(id),
  product_id INT
);

2nd Normal Form (2NF)

第二范式(2NF)

sql
-- BAD: customer_name depends only on customer_id
CREATE TABLE order_items (
  order_id INT,
  product_id INT,
  customer_name VARCHAR(100),  -- Partial dependency!
  PRIMARY KEY (order_id, product_id)
);

-- GOOD: Customer data in separate table
CREATE TABLE customers (
  id INT PRIMARY KEY,
  name VARCHAR(100)
);
sql
-- 错误:customer_name仅依赖于customer_id
CREATE TABLE order_items (
  order_id INT,
  product_id INT,
  customer_name VARCHAR(100),  -- 部分依赖!
  PRIMARY KEY (order_id, product_id)
);

-- 正确:客户数据存到单独的表
CREATE TABLE customers (
  id INT PRIMARY KEY,
  name VARCHAR(100)
);

3rd Normal Form (3NF)

第三范式(3NF)

sql
-- BAD: country depends on postal_code
CREATE TABLE customers (
  id INT PRIMARY KEY,
  postal_code VARCHAR(10),
  country VARCHAR(50)  -- Transitive dependency!
);

-- GOOD: Separate postal_codes table
CREATE TABLE postal_codes (
  code VARCHAR(10) PRIMARY KEY,
  country VARCHAR(50)
);
sql
-- 错误:country依赖于postal_code
CREATE TABLE customers (
  id INT PRIMARY KEY,
  postal_code VARCHAR(10),
  country VARCHAR(50)  -- 传递依赖!
);

-- 正确:拆分postal_codes表
CREATE TABLE postal_codes (
  code VARCHAR(10) PRIMARY KEY,
  country VARCHAR(50)
);

When to Denormalize

何时使用反规范化

ScenarioDenormalization Strategy
Read-heavy reportingPre-calculated aggregates
Expensive JOINsCached derived columns
Analytics dashboardsMaterialized views
sql
-- Denormalized for performance
CREATE TABLE orders (
  id INT PRIMARY KEY,
  customer_id INT,
  total_amount DECIMAL(10,2),  -- Calculated
  item_count INT               -- Calculated
);
</details> <details> <summary><strong>Deep Dive: Data Types</strong></summary>
场景反规范化策略
读密集型报表预计算聚合值
关联查询成本高缓存派生列
分析仪表板物化视图
sql
-- 为性能优化的反规范化设计
CREATE TABLE orders (
  id INT PRIMARY KEY,
  customer_id INT,
  total_amount DECIMAL(10,2),  -- 计算得出
  item_count INT               -- 计算得出
);
</details> <details> <summary><strong>深入解析:数据类型</strong></summary>

String Types

字符串类型

TypeUse CaseExample
CHAR(n)Fixed lengthState codes, ISO dates
VARCHAR(n)Variable lengthNames, emails
TEXTLong contentArticles, descriptions
sql
-- Good sizing
email VARCHAR(255)
phone VARCHAR(20)
country_code CHAR(2)
类型使用场景示例
CHAR(n)固定长度州代码、ISO日期
VARCHAR(n)可变长度姓名、邮箱
TEXT长内容文章、描述
sql
-- 合理设置长度
email VARCHAR(255)
phone VARCHAR(20)
country_code CHAR(2)

Numeric Types

数值类型

TypeRangeUse Case
TINYINT-128 to 127Age, status codes
SMALLINT-32K to 32KQuantities
INT-2.1B to 2.1BIDs, counts
BIGINTVery largeLarge IDs, timestamps
DECIMAL(p,s)Exact precisionMoney
FLOAT/DOUBLEApproximateScientific data
sql
-- ALWAYS use DECIMAL for money
price DECIMAL(10, 2)  -- $99,999,999.99

-- NEVER use FLOAT for money
price FLOAT  -- Rounding errors!
类型范围使用场景
TINYINT-128 到 127年龄、状态码
SMALLINT-32K 到 32K数量
INT-2.1B 到 2.1BID、计数
BIGINT极大范围大型ID、时间戳
DECIMAL(p,s)精确精度金额
FLOAT/DOUBLE近似值科学数据
sql
-- 金额必须使用DECIMAL
price DECIMAL(10, 2)  -- 最大支持$99,999,999.99

-- 禁止用FLOAT存储金额
price FLOAT  -- 会出现舍入误差!

Date/Time Types

日期/时间类型

sql
DATE        -- 2025-10-31
TIME        -- 14:30:00
DATETIME    -- 2025-10-31 14:30:00
TIMESTAMP   -- Auto timezone conversion

-- Always store in UTC
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
sql
DATE        -- 2025-10-31
TIME        -- 14:30:00
DATETIME    -- 2025-10-31 14:30:00
TIMESTAMP   -- 自动时区转换

-- 始终以UTC存储
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

Boolean

布尔类型

sql
-- PostgreSQL
is_active BOOLEAN DEFAULT TRUE

-- MySQL
is_active TINYINT(1) DEFAULT 1
</details> <details> <summary><strong>Deep Dive: Indexing Strategy</strong></summary>
sql
-- PostgreSQL
is_active BOOLEAN DEFAULT TRUE

-- MySQL
is_active TINYINT(1) DEFAULT 1
</details> <details> <summary><strong>深入解析:索引策略</strong></summary>

When to Create Indexes

何时创建索引

Always IndexReason
Foreign keysSpeed up JOINs
WHERE clause columnsSpeed up filtering
ORDER BY columnsSpeed up sorting
Unique constraintsEnforced uniqueness
sql
-- Foreign key index
CREATE INDEX idx_orders_customer ON orders(customer_id);

-- Query pattern index
CREATE INDEX idx_orders_status_date ON orders(status, created_at);
需始终添加索引的场景原因
外键加速关联查询
WHERE子句中的列加速过滤
ORDER BY子句中的列加速排序
唯一约束强制唯一性
sql
-- 外键索引
CREATE INDEX idx_orders_customer ON orders(customer_id);

-- 针对查询模式的索引
CREATE INDEX idx_orders_status_date ON orders(status, created_at);

Index Types

索引类型

TypeBest ForExample
B-TreeRanges, equality
price > 100
HashExact matches only
email = 'x@y.com'
Full-textText search
MATCH AGAINST
PartialSubset of rows
WHERE is_active = true
类型最佳适用场景示例
B-Tree范围查询、等值查询
price > 100
Hash仅精确匹配
email = 'x@y.com'
全文索引文本搜索
MATCH AGAINST
部分索引行的子集
WHERE is_active = true

Composite Index Order

复合索引顺序

sql
CREATE INDEX idx_customer_status ON orders(customer_id, status);

-- Uses index (customer_id first)
SELECT * FROM orders WHERE customer_id = 123;
SELECT * FROM orders WHERE customer_id = 123 AND status = 'pending';

-- Does NOT use index (status alone)
SELECT * FROM orders WHERE status = 'pending';
Rule: Most selective column first, or column most queried alone.
sql
CREATE INDEX idx_customer_status ON orders(customer_id, status);

-- 会使用索引(customer_id在前)
SELECT * FROM orders WHERE customer_id = 123;
SELECT * FROM orders WHERE customer_id = 123 AND status = 'pending';

-- 不会使用索引(仅用status)
SELECT * FROM orders WHERE status = 'pending';
规则: 选择性最高的列优先,或单独查询最频繁的列优先。

Index Pitfalls

索引陷阱

PitfallProblemSolution
Over-indexingSlow writesOnly index what's queried
Wrong column orderUnused indexMatch query patterns
Missing FK indexesSlow JOINsAlways index FKs
</details> <details> <summary><strong>Deep Dive: Constraints</strong></summary>
陷阱问题解决方案
过度索引写入速度变慢只为查询需要的列添加索引
列顺序错误索引未被使用匹配查询模式
外键未加索引关联查询缓慢始终为外键添加索引
</details> <details> <summary><strong>深入解析:约束</strong></summary>

Primary Keys

主键

sql
-- Auto-increment (simple)
id INT AUTO_INCREMENT PRIMARY KEY

-- UUID (distributed systems)
id CHAR(36) PRIMARY KEY DEFAULT (UUID())

-- Composite (junction tables)
PRIMARY KEY (student_id, course_id)
sql
-- 自增主键(简单场景)
id INT AUTO_INCREMENT PRIMARY KEY

-- UUID主键(分布式系统)
id CHAR(36) PRIMARY KEY DEFAULT (UUID())

-- 复合主键(关联表)
PRIMARY KEY (student_id, course_id)

Foreign Keys

外键

sql
FOREIGN KEY (customer_id) REFERENCES customers(id)
  ON DELETE CASCADE     -- Delete children with parent
  ON DELETE RESTRICT    -- Prevent deletion if referenced
  ON DELETE SET NULL    -- Set to NULL when parent deleted
  ON UPDATE CASCADE     -- Update children when parent changes
StrategyUse When
CASCADEDependent data (order_items)
RESTRICTImportant references (prevent accidents)
SET NULLOptional relationships
sql
FOREIGN KEY (customer_id) REFERENCES customers(id)
  ON DELETE CASCADE     -- 删除父表时同时删除子表数据
  ON DELETE RESTRICT    -- 存在引用时禁止删除父表数据
  ON DELETE SET NULL    -- 删除父表时将子表对应列设为NULL
  ON UPDATE CASCADE     -- 更新父表时同步更新子表数据
策略使用场景
CASCADE依赖数据(如order_items)
RESTRICT重要引用(防止误删)
SET NULL可选关系

Other Constraints

其他约束

sql
-- Unique
email VARCHAR(255) UNIQUE NOT NULL

-- Composite unique
UNIQUE (student_id, course_id)

-- Check
price DECIMAL(10,2) CHECK (price >= 0)
discount INT CHECK (discount BETWEEN 0 AND 100)

-- Not null
name VARCHAR(100) NOT NULL
</details> <details> <summary><strong>Deep Dive: Relationship Patterns</strong></summary>
sql
-- 唯一约束
email VARCHAR(255) UNIQUE NOT NULL

-- 复合唯一约束
UNIQUE (student_id, course_id)

-- 检查约束
price DECIMAL(10,2) CHECK (price >= 0)
discount INT CHECK (discount BETWEEN 0 AND 100)

-- 非空约束
name VARCHAR(100) NOT NULL
</details> <details> <summary><strong>深入解析:关系模式</strong></summary>

One-to-Many

一对多

sql
CREATE TABLE orders (
  id INT PRIMARY KEY,
  customer_id INT NOT NULL REFERENCES customers(id)
);

CREATE TABLE order_items (
  id INT PRIMARY KEY,
  order_id INT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
  product_id INT NOT NULL,
  quantity INT NOT NULL
);
sql
CREATE TABLE orders (
  id INT PRIMARY KEY,
  customer_id INT NOT NULL REFERENCES customers(id)
);

CREATE TABLE order_items (
  id INT PRIMARY KEY,
  order_id INT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
  product_id INT NOT NULL,
  quantity INT NOT NULL
);

Many-to-Many

多对多

sql
-- Junction table
CREATE TABLE enrollments (
  student_id INT REFERENCES students(id) ON DELETE CASCADE,
  course_id INT REFERENCES courses(id) ON DELETE CASCADE,
  enrolled_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (student_id, course_id)
);
sql
-- 关联表
CREATE TABLE enrollments (
  student_id INT REFERENCES students(id) ON DELETE CASCADE,
  course_id INT REFERENCES courses(id) ON DELETE CASCADE,
  enrolled_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (student_id, course_id)
);

Self-Referencing

自引用

sql
CREATE TABLE employees (
  id INT PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  manager_id INT REFERENCES employees(id)
);
sql
CREATE TABLE employees (
  id INT PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  manager_id INT REFERENCES employees(id)
);

Polymorphic

多态关联

sql
-- Approach 1: Separate FKs (stronger integrity)
CREATE TABLE comments (
  id INT PRIMARY KEY,
  content TEXT NOT NULL,
  post_id INT REFERENCES posts(id),
  photo_id INT REFERENCES photos(id),
  CHECK (
    (post_id IS NOT NULL AND photo_id IS NULL) OR
    (post_id IS NULL AND photo_id IS NOT NULL)
  )
);

-- Approach 2: Type + ID (flexible, weaker integrity)
CREATE TABLE comments (
  id INT PRIMARY KEY,
  content TEXT NOT NULL,
  commentable_type VARCHAR(50) NOT NULL,
  commentable_id INT NOT NULL
);
</details> <details> <summary><strong>Deep Dive: NoSQL Design (MongoDB)</strong></summary>
sql
-- 方式1:单独外键(完整性更强)
CREATE TABLE comments (
  id INT PRIMARY KEY,
  content TEXT NOT NULL,
  post_id INT REFERENCES posts(id),
  photo_id INT REFERENCES photos(id),
  CHECK (
    (post_id IS NOT NULL AND photo_id IS NULL) OR
    (post_id IS NULL AND photo_id IS NOT NULL)
  )
);

-- 方式2:类型+ID(更灵活,完整性较弱)
CREATE TABLE comments (
  id INT PRIMARY KEY,
  content TEXT NOT NULL,
  commentable_type VARCHAR(50) NOT NULL,
  commentable_id INT NOT NULL
);
</details> <details> <summary><strong>深入解析:NoSQL设计(MongoDB)</strong></summary>

Embedding vs Referencing

嵌入 vs 引用

FactorEmbedReference
Access patternRead togetherRead separately
Relationship1:few1:many
Document sizeSmallApproaching 16MB
Update frequencyRarelyFrequently
因素嵌入引用
访问模式一起读取单独读取
关系一对少一对多
文档大小接近16MB
更新频率

Embedded Document

嵌入文档

json
{
  "_id": "order_123",
  "customer": {
    "id": "cust_456",
    "name": "Jane Smith",
    "email": "jane@example.com"
  },
  "items": [
    { "product_id": "prod_789", "quantity": 2, "price": 29.99 }
  ],
  "total": 109.97
}
json
{
  "_id": "order_123",
  "customer": {
    "id": "cust_456",
    "name": "Jane Smith",
    "email": "jane@example.com"
  },
  "items": [
    { "product_id": "prod_789", "quantity": 2, "price": 29.99 }
  ],
  "total": 109.97
}

Referenced Document

引用文档

json
{
  "_id": "order_123",
  "customer_id": "cust_456",
  "item_ids": ["item_1", "item_2"],
  "total": 109.97
}
json
{
  "_id": "order_123",
  "customer_id": "cust_456",
  "item_ids": ["item_1", "item_2"],
  "total": 109.97
}

MongoDB Indexes

MongoDB索引

javascript
// Single field
db.users.createIndex({ email: 1 }, { unique: true });

// Composite
db.orders.createIndex({ customer_id: 1, created_at: -1 });

// Text search
db.articles.createIndex({ title: "text", content: "text" });

// Geospatial
db.stores.createIndex({ location: "2dsphere" });
</details> <details> <summary><strong>Deep Dive: Migrations</strong></summary>
javascript
// 单字段索引
db.users.createIndex({ email: 1 }, { unique: true });

// 复合索引
db.orders.createIndex({ customer_id: 1, created_at: -1 });

// 全文索引
db.articles.createIndex({ title: "text", content: "text" });

// 地理空间索引
db.stores.createIndex({ location: "2dsphere" });
</details> <details> <summary><strong>深入解析:迁移</strong></summary>

Migration Best Practices

迁移最佳实践

PracticeWHY
Always reversibleNeed to rollback
Backward compatibleZero-downtime deploys
Schema before dataSeparate concerns
Test on stagingCatch issues early
实践原因
始终支持回滚需要能回滚到之前的状态
保证向后兼容支持零停机部署
先改架构再改数据分离关注点
在staging环境测试提前发现问题

Adding a Column (Zero-Downtime)

零停机添加列

sql
-- Step 1: Add nullable column
ALTER TABLE users ADD COLUMN phone VARCHAR(20);

-- Step 2: Deploy code that writes to new column

-- Step 3: Backfill existing rows
UPDATE users SET phone = '' WHERE phone IS NULL;

-- Step 4: Make required (if needed)
ALTER TABLE users MODIFY phone VARCHAR(20) NOT NULL;
sql
-- 步骤1:添加可空列
ALTER TABLE users ADD COLUMN phone VARCHAR(20);

-- 步骤2:部署写入新列的代码

-- 步骤3:回填现有数据
UPDATE users SET phone = '' WHERE phone IS NULL;

-- 步骤4:设置为必填(如果需要)
ALTER TABLE users MODIFY phone VARCHAR(20) NOT NULL;

Renaming a Column (Zero-Downtime)

零停机重命名列

sql
-- Step 1: Add new column
ALTER TABLE users ADD COLUMN email_address VARCHAR(255);

-- Step 2: Copy data
UPDATE users SET email_address = email;

-- Step 3: Deploy code reading from new column
-- Step 4: Deploy code writing to new column

-- Step 5: Drop old column
ALTER TABLE users DROP COLUMN email;
sql
-- 步骤1:添加新列
ALTER TABLE users ADD COLUMN email_address VARCHAR(255);

-- 步骤2:复制数据
UPDATE users SET email_address = email;

-- 步骤3:部署读取新列的代码
-- 步骤4:部署写入新列的代码

-- 步骤5:删除旧列
ALTER TABLE users DROP COLUMN email;

Migration Template

迁移模板

sql
-- Migration: YYYYMMDDHHMMSS_description.sql

-- UP
BEGIN;
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
CREATE INDEX idx_users_phone ON users(phone);
COMMIT;

-- DOWN
BEGIN;
DROP INDEX idx_users_phone ON users;
ALTER TABLE users DROP COLUMN phone;
COMMIT;
</details> <details> <summary><strong>Deep Dive: Performance Optimization</strong></summary>
sql
-- 迁移文件:YYYYMMDDHHMMSS_description.sql

-- UP(升级)
BEGIN;
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
CREATE INDEX idx_users_phone ON users(phone);
COMMIT;

-- DOWN(回滚)
BEGIN;
DROP INDEX idx_users_phone ON users;
ALTER TABLE users DROP COLUMN phone;
COMMIT;
</details> <details> <summary><strong>深入解析:性能优化</strong></summary>

Query Analysis

查询分析

sql
EXPLAIN SELECT * FROM orders
WHERE customer_id = 123 AND status = 'pending';
Look ForMeaning
type: ALLFull table scan (bad)
type: refIndex used (good)
key: NULLNo index used
rows: highMany rows scanned
sql
EXPLAIN SELECT * FROM orders
WHERE customer_id = 123 AND status = 'pending';
需关注的内容含义
type: ALL全表扫描(性能差)
type: ref使用了索引(性能好)
key: NULL未使用索引
rows: 数值大扫描了大量行

N+1 Query Problem

N+1查询问题

python
undefined
python
undefined

BAD: N+1 queries

错误:N+1次查询

orders = db.query("SELECT * FROM orders") for order in orders: customer = db.query(f"SELECT * FROM customers WHERE id = {order.customer_id}")
orders = db.query("SELECT * FROM orders") for order in orders: customer = db.query(f"SELECT * FROM customers WHERE id = {order.customer_id}")

GOOD: Single JOIN

正确:单次关联查询

results = db.query(""" SELECT orders.*, customers.name FROM orders JOIN customers ON orders.customer_id = customers.id """)
undefined
results = db.query(""" SELECT orders.*, customers.name FROM orders JOIN customers ON orders.customer_id = customers.id """)
undefined

Optimization Techniques

优化技巧

TechniqueWhen to Use
Add indexesSlow WHERE/ORDER BY
DenormalizeExpensive JOINs
PaginationLarge result sets
CachingRepeated queries
Read replicasRead-heavy load
PartitioningVery large tables
</details>
技巧使用场景
添加索引WHERE/ORDER BY查询缓慢
反规范化关联查询成本高
分页结果集过大
缓存查询重复率高
读副本读密集型负载
分区表数据量极大
</details>

Extension Points

扩展方向

  1. Database-Specific Patterns: Add MySQL vs PostgreSQL vs SQLite variations
  2. Advanced Patterns: Time-series, event sourcing, CQRS, multi-tenancy
  3. ORM Integration: TypeORM, Prisma, SQLAlchemy patterns
  4. Monitoring: Query performance tracking, slow query alerts
  1. 数据库特定模式: 添加MySQL、PostgreSQL、SQLite的差异实现
  2. 高级模式: 时间序列、事件溯源、CQRS、多租户
  3. ORM集成: TypeORM、Prisma、SQLAlchemy的使用模式
  4. 监控: 查询性能跟踪、慢查询告警