提示工程 | | 约 23 分钟 | 8,870 字

数据库设计提示词:从 ER 图到 SQL

用 AI 辅助数据库建模、SQL 编写、查询优化的提示词模板

为什么数据库设计适合用 AI

数据库设计是一个既需要经验又需要细心的工作。表结构设计、索引选择、查询优化——每一步都有大量的最佳实践和常见陷阱。

AI 在这个领域特别有用,因为:

  1. 它见过海量的数据库设计案例
  2. 它能快速生成规范的 DDL 语句
  3. 它能分析 SQL 查询的性能问题
  4. 它能帮你考虑到容易遗漏的边界情况

我们来看一套完整的数据库设计提示词模板。


提示词 1:需求到 ER 图

你是一个数据库架构师。请根据以下业务需求设计 ER 图。

业务描述:
[业务描述]

请输出:
1. 实体列表(每个实体的属性和主键)
2. 实体之间的关系(一对一、一对多、多对多)
3. 用文本格式画出 ER 图
4. 设计决策的说明(为什么这样设计)

注意:
- 考虑数据的完整性约束
- 标注哪些字段可以为 NULL
- 标注唯一约束

使用示例

业务描述:
我们要做一个在线课程平台。用户可以注册成为学生或讲师。
讲师可以创建课程,每个课程有多个章节。
学生可以购买课程,购买后可以观看所有章节。
学生可以对课程评分和评论。
每个课程有标签,方便搜索。

AI 输出:
实体列表:

1. users(用户)
   - id: BIGINT, PK, AUTO_INCREMENT
   - email: VARCHAR(255), UNIQUE, NOT NULL
   - password_hash: VARCHAR(255), NOT NULL
   - name: VARCHAR(100), NOT NULL
   - role: ENUM('student', 'instructor'), NOT NULL
   - avatar_url: VARCHAR(500), NULL
   - created_at: TIMESTAMP, NOT NULL, DEFAULT NOW()

2. courses(课程)
   - id: BIGINT, PK, AUTO_INCREMENT
   - instructor_id: BIGINT, FK -> users.id, NOT NULL
   - title: VARCHAR(200), NOT NULL
   - description: TEXT, NULL
   - price: DECIMAL(10,2), NOT NULL
   - status: ENUM('draft', 'published', 'archived'), DEFAULT 'draft'
   - created_at: TIMESTAMP, NOT NULL

3. chapters(章节)
   - id: BIGINT, PK
   - course_id: BIGINT, FK -> courses.id, NOT NULL
   - title: VARCHAR(200), NOT NULL
   - video_url: VARCHAR(500), NOT NULL
   - duration_seconds: INT, NOT NULL
   - sort_order: INT, NOT NULL

4. enrollments(选课记录)
   - id: BIGINT, PK
   - user_id: BIGINT, FK -> users.id, NOT NULL
   - course_id: BIGINT, FK -> courses.id, NOT NULL
   - purchased_at: TIMESTAMP, NOT NULL
   - UNIQUE(user_id, course_id)

5. reviews(评价)
   - id: BIGINT, PK
   - user_id: BIGINT, FK -> users.id, NOT NULL
   - course_id: BIGINT, FK -> courses.id, NOT NULL
   - rating: SMALLINT, NOT NULL, CHECK(1-5)
   - comment: TEXT, NULL
   - created_at: TIMESTAMP, NOT NULL
   - UNIQUE(user_id, course_id)

6. tags(标签)
   - id: BIGINT, PK
   - name: VARCHAR(50), UNIQUE, NOT NULL

7. course_tags(课程标签关联)
   - course_id: BIGINT, FK -> courses.id
   - tag_id: BIGINT, FK -> tags.id
   - PRIMARY KEY(course_id, tag_id)

关系:
users 1:N courses(一个讲师多个课程)
courses 1:N chapters(一个课程多个章节)
users M:N courses(通过 enrollments)
users M:N courses(通过 reviews)
courses M:N tags(通过 course_tags)

提示词 2:ER 图到 DDL

请将以下 ER 图转换为 [数据库类型] 的 DDL 语句。

ER 图:
[ER 图描述]

要求:
1. 包含所有表的 CREATE TABLE 语句
2. 包含外键约束
3. 包含索引(基于常见查询场景)
4. 包含注释
5. 按照依赖顺序排列(被引用的表先创建)
6. 数据库类型:[PostgreSQL/MySQL/SQLite]

输出示例

-- 用户表
CREATE TABLE users (
    id BIGSERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL,
    name VARCHAR(100) NOT NULL,
    role VARCHAR(20) NOT NULL CHECK (role IN ('student', 'instructor')),
    avatar_url VARCHAR(500),
    created_at TIMESTAMP NOT NULL DEFAULT NOW()
);

COMMENT ON TABLE users IS '用户表,包含学生和讲师';
COMMENT ON COLUMN users.role IS '用户角色:student 或 instructor';

-- 课程表
CREATE TABLE courses (
    id BIGSERIAL PRIMARY KEY,
    instructor_id BIGINT NOT NULL REFERENCES users(id),
    title VARCHAR(200) NOT NULL,
    description TEXT,
    price DECIMAL(10,2) NOT NULL CHECK (price >= 0),
    status VARCHAR(20) NOT NULL DEFAULT 'draft'
        CHECK (status IN ('draft', 'published', 'archived')),
    created_at TIMESTAMP NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_courses_instructor ON courses(instructor_id);
CREATE INDEX idx_courses_status ON courses(status);

-- 章节表
CREATE TABLE chapters (
    id BIGSERIAL PRIMARY KEY,
    course_id BIGINT NOT NULL REFERENCES courses(id) ON DELETE CASCADE,
    title VARCHAR(200) NOT NULL,
    video_url VARCHAR(500) NOT NULL,
    duration_seconds INT NOT NULL CHECK (duration_seconds > 0),
    sort_order INT NOT NULL,
    UNIQUE(course_id, sort_order)
);

CREATE INDEX idx_chapters_course ON chapters(course_id);

-- 选课记录表
CREATE TABLE enrollments (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL REFERENCES users(id),
    course_id BIGINT NOT NULL REFERENCES courses(id),
    purchased_at TIMESTAMP NOT NULL DEFAULT NOW(),
    UNIQUE(user_id, course_id)
);

CREATE INDEX idx_enrollments_user ON enrollments(user_id);
CREATE INDEX idx_enrollments_course ON enrollments(course_id);

-- 评价表
CREATE TABLE reviews (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL REFERENCES users(id),
    course_id BIGINT NOT NULL REFERENCES courses(id),
    rating SMALLINT NOT NULL CHECK (rating BETWEEN 1 AND 5),
    comment TEXT,
    created_at TIMESTAMP NOT NULL DEFAULT NOW(),
    UNIQUE(user_id, course_id)
);

CREATE INDEX idx_reviews_course ON reviews(course_id);

提示词 3:业务查询生成

你是一个 SQL 专家。请根据以下表结构和业务需求,编写 SQL 查询。

表结构:
[DDL 或表结构描述]

查询需求:
[用自然语言描述你想查什么]

要求:
1. 使用 [PostgreSQL/MySQL] 语法
2. 查询要高效(避免不必要的子查询和全表扫描)
3. 添加注释说明查询逻辑
4. 如果需要索引支持,请指出

常见查询场景模板

场景 1:排行榜查询
"查询评分最高的前 10 门课程,包含课程名、讲师名、平均评分、评价数量"

场景 2:统计报表
"按月统计每个讲师的课程销售额和学生数量"

场景 3:复杂筛选
"查询价格在 100-500 之间、评分 4 分以上、包含 'Python' 标签的课程"

场景 4:用户行为分析
"查询购买了课程 A 的用户中,有多少也购买了课程 B(协同过滤)"

提示词 4:查询优化

请优化以下 SQL 查询。

原始查询:
```sql
[你的 SQL]

执行计划(如果有): [EXPLAIN 输出]

当前问题: [描述性能问题,如”查询耗时 5 秒”]

表数据量:

  • [表名]:约 [数量] 行
  • [表名]:约 [数量] 行

请:

  1. 分析性能瓶颈
  2. 给出优化后的 SQL
  3. 建议需要添加的索引
  4. 估算优化后的性能提升

### 优化示例

原始查询(慢): SELECT c.*, AVG(r.rating) as avg_rating FROM courses c LEFT JOIN reviews r ON c.id = r.course_id WHERE c.status = ‘published’ GROUP BY c.id HAVING AVG(r.rating) > 4 ORDER BY avg_rating DESC LIMIT 10;

表数据量:courses 10万行,reviews 100万行

AI 优化建议:

问题分析:

  1. LEFT JOIN 100万行的 reviews 表,然后 GROUP BY,开销很大
  2. 没有利用索引

优化方案:

-- 方案 1:使用子查询预聚合
SELECT
    c.*,
    rs.avg_rating
FROM courses c
INNER JOIN (
    SELECT
        course_id,
        AVG(rating) as avg_rating
    FROM reviews
    GROUP BY course_id
    HAVING AVG(rating) > 4
) rs ON c.id = rs.course_id
WHERE c.status = 'published'
ORDER BY rs.avg_rating DESC
LIMIT 10;

-- 建议索引
CREATE INDEX idx_reviews_course_rating ON reviews(course_id, rating);
CREATE INDEX idx_courses_status ON courses(status);

预估提升:从 5 秒降到 0.2 秒以内。


---

## 提示词 5:迁移脚本生成

请生成数据库迁移脚本。

当前表结构: [当前 DDL]

目标变更: [描述要做的变更]

要求:

  1. 生成 UP 迁移(升级)和 DOWN 迁移(回滚)
  2. 考虑数据迁移(如果有)
  3. 考虑在线迁移的安全性(不锁表或最小化锁表时间)
  4. 添加注释说明每步操作
  5. 使用 [Alembic/Flyway/Prisma] 格式

### 使用示例

目标变更:

  1. 给 courses 表添加 category_id 字段
  2. 创建 categories 表
  3. 将现有课程的标签迁移为分类

AI 输出:

— UP 迁移 — Step 1: 创建分类表 CREATE TABLE categories ( id BIGSERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL UNIQUE, parent_id BIGINT REFERENCES categories(id), sort_order INT NOT NULL DEFAULT 0, created_at TIMESTAMP NOT NULL DEFAULT NOW() );

— Step 2: 添加 category_id 字段(允许 NULL,因为现有数据还没有分类) ALTER TABLE courses ADD COLUMN category_id BIGINT REFERENCES categories(id);

— Step 3: 数据迁移 - 从标签创建分类 INSERT INTO categories (name) SELECT DISTINCT t.name FROM tags t INNER JOIN course_tags ct ON t.id = ct.tag_id;

— Step 4: 数据迁移 - 为课程设置分类(取第一个标签作为分类) UPDATE courses c SET category_id = ( SELECT cat.id FROM categories cat INNER JOIN tags t ON t.name = cat.name INNER JOIN course_tags ct ON ct.tag_id = t.id AND ct.course_id = c.id LIMIT 1 );

— Step 5: 添加索引 CREATE INDEX idx_courses_category ON courses(category_id);

— DOWN 迁移 DROP INDEX IF EXISTS idx_courses_category; ALTER TABLE courses DROP COLUMN IF EXISTS category_id; DROP TABLE IF EXISTS categories;


---

## 提示词 6:索引推荐

请分析以下表结构和查询模式,推荐索引策略。

表结构: [DDL]

常见查询模式:

  1. [查询描述 + SQL]
  2. [查询描述 + SQL]
  3. [查询描述 + SQL]

写入模式:

  • 每秒约 [N] 次插入
  • 每秒约 [N] 次更新

请输出:

  1. 推荐的索引列表
  2. 每个索引的作用(加速哪些查询)
  3. 索引的存储开销估算
  4. 不建议添加的索引及原因

---

## 提示词 7:数据库选型

请帮我做数据库选型。

业务场景: [描述业务场景]

数据特征:

  • 数据量:[预估]
  • 读写比:[如 读:写 = 10:1]
  • 数据结构:[结构化/半结构化/非结构化]
  • 一致性要求:[强一致/最终一致]
  • 查询模式:[OLTP/OLAP/混合]

约束条件:

  • 团队技术栈:[现有经验]
  • 预算:[预算范围]
  • 运维能力:[自建/托管]

请对比分析 2-3 种候选数据库,给出推荐。


### 输出示例

场景:实时数据分析平台,每天 1 亿条日志,需要秒级查询

维度PostgreSQLClickHouseElasticsearch
写入性能
查询性能很高
聚合分析很好一般
全文搜索一般很好
运维复杂度
团队学习成本

推荐:ClickHouse 原因:日志分析场景,写入量大,聚合查询为主,ClickHouse 的列式存储和向量化执行引擎最适合。


---

## 提示词 8:数据建模审查

请审查以下数据库设计,指出问题和改进建议。

表结构: [DDL]

业务场景: [描述]

请从以下维度审查:

  1. 范式化程度(是否过度范式化或反范式化)
  2. 数据完整性(约束是否完整)
  3. 性能考虑(索引、分区)
  4. 扩展性(未来需求变化时是否容易修改)
  5. 命名规范

---

## 组合使用:完整的数据库设计流程

把上面的提示词串联起来,形成一个完整的工作流:

第 1 步:需求 → ER 图(提示词 1) ↓ 第 2 步:ER 图 → DDL(提示词 2) ↓ 第 3 步:DDL 审查(提示词 8) ↓ 第 4 步:编写业务查询(提示词 3) ↓ 第 5 步:查询优化(提示词 4) ↓ 第 6 步:索引推荐(提示词 6) ↓ 第 7 步:生成迁移脚本(提示词 5)


每一步都用专门的提示词,前一步的输出作为后一步的输入。这就是 Prompt Chaining 在数据库设计中的实际应用。

---

## 使用技巧

### 1. 提供足够的上下文

AI 不知道你的业务,所以要把业务场景描述清楚。"用户表"可以有一百种设计,但"日活 10 万的 SaaS 平台的用户表"就具体多了。

### 2. 指定数据库类型

PostgreSQL 和 MySQL 的语法差异不小。始终明确指定数据库类型。

### 3. 给出数据量级

"优化这个查询"和"优化这个查询,表有 1 亿行"是完全不同的问题。

### 4. 验证生成的 SQL

AI 生成的 SQL 不一定能直接运行。始终在测试环境验证。

> 数据库设计是软件的地基。用 AI 加速设计过程,但最终的决策权在你手里。AI 是你的参谋,不是你的替代。

评论

加载中...

相关文章

分享:

评论

加载中...