15.3 数据库不是黑盒
为什么需要理解数据库
在 Vibe Coding 中,AI 会替你写所有 SQL 语句。你可以永远不学 SQL 语法。
但是,当你的应用变得很慢(加载一个页面要 5 秒),90% 的可能是数据库查询的问题。这时候如果你对数据库有一个简单的心理模型,就能准确地向 AI 描述问题并快速修复。
这个心理模型不需要多深——你只需要知道"数据库是一堆表格"和"索引像书的目录"这两个概念,就能解决 80% 的性能问题。
数据库是怎么工作的
你可以把数据库想象成一个超大型的 Excel 表格集合:
- 每个"表"(Table)就像 Excel 中的一个 Sheet
- 每"行"(Row)是一行数据
- 每"列"(Column)是一种数据类型
当你执行一个查询:
SELECT * FROM users WHERE email = 'alice@example.com';
数据库会做:
- 找到
users这个"表格" - 遍历每一行,检查
email列是否等于alice@example.com - 返回所有匹配的行
如果没有索引,数据库要扫描整个表——就像你在 Excel 里从上到下逐行查找。如果表里有 100 万行用户数据,这个查询可能需要几秒钟。
一个重要的认知:数据库不像人类那样"聪明"。 人类看到"找 alice@example.com"会自然地从字母 A 开头的区域开始找。但数据库不会——它会老老实实地从第 1 行开始逐行扫描到最后一行。除非你(或 AI 帮你)告诉它"在 email 列上建一个索引"。
索引:加速查询的关键
索引是数据库最核心的优化手段——也是 AI 生成的代码中经常遗漏的东西。
索引的概念和书的目录一样:没有目录,你要翻遍整本书才能找到"Vibe Coding"这个词出现在哪一页。有目录,直接翻到对应页码。
-- 创建索引——告诉数据库"经常要用 email 查用户,帮我记住每个 email 在哪一行"
CREATE INDEX idx_users_email ON users (email);
创建索引后,上面的 WHERE email = 'alice@example.com' 查询从"扫描 100 万行"变成了"直接跳到对应的那一行",时间从秒级降到毫秒级。
在 Vibe Coding 中检查索引:
你不需要自己写 CREATE INDEX 语句。当你发现页面加载慢时,直接问 AI:
"这个页面加载很慢,是不是数据库缺少索引?帮我检查一下需要在哪里加索引。"
AI 会检查你的 Prisma Schema 或 SQL 查询,在需要的地方添加索引定义。
什么时候需要索引:
- 经常出现在
WHERE子句中的列(筛选条件) - 经常出现在
ORDER BY中的列(排序) - 经常用于 JOIN 的列(表关联)
什么时候不需要索引:
- 数据量很小的表(几百行,全表扫描比查索引更快)
- 频繁写入但很少查询的列(索引会减慢写入速度)
复合索引(索引进阶):
有时候你经常组合使用两个列来查询:
SELECT * FROM orders WHERE user_id = 123 ORDER BY created_at DESC LIMIT 20;
这时 AI 可能创建一个复合索引(包含两列):
CREATE INDEX idx_orders_user_created ON orders (user_id, created_at);
这个索引同时加速了"按 user_id 筛选"和"按 created_at 排序"两个操作。如果你告诉 AI "查询还是很慢",它可能会建议复合索引。
常见的性能问题模式
N+1 查询问题
这是最常见的性能陷阱:
# 伪代码
posts = db.query("SELECT * FROM posts") # 1 次查询
for post in posts:
comments = db.query("SELECT * FROM comments WHERE post_id = ?", post.id) # N 次查询
如果有 100 篇文章,这个循环会产生 1 + 100 = 101 次查询。用 JOIN 一次就能完成:
SELECT posts.*, comments.*
FROM posts
LEFT JOIN comments ON posts.id = comments.post_id;
AI 经常犯 N+1 错误吗? 是的,尤其在生成 ORM 代码时。解决方案:遇到页面加载慢时,直接问 AI "这个页面是不是有 N+1 查询问题?"
AI 会识别出 ORM 代码中的循环查询模式,并用 include(Prisma)或 JOIN 替换。
N+1 问题的典型症状:
- 页面加载随着数据量增加线性变慢
- 看 Network 面板,发现发了几十上百个 API 请求
- 服务器日志中有大量结构相似的数据库查询
如果你怀疑有 N+1 问题,告诉 AI:
"加载用户列表页面时,Network 面板显示发了 50 个请求,每个请求都是查一个用户的订单数据。这是不是 N+1 问题?"
AI 会确认并修复。
缺少索引
场景:应用刚上线时数据少,一切正常。运行一个月后,数据量增长了 100 倍,页面加载越来越慢。
原因:AI 生成数据表时可能没有考虑你未来的数据量。当数据量增长后,EXPLAIN QUERY PLAN 一看——全是全表扫描。
数据量增长的三个典型阶段:
| 数据量 | 表现 | 对策 |
|---|---|---|
| < 1 万行 | 不管有没有索引,查询都很快 | 不需要索引 |
| 1 万 ~ 10 万行 | 没有索引时查询变慢 | 在常用查询字段上加索引 |
| > 10 万行 | 必须要有索引,否则查询以秒计 | 检查所有查询的索引覆盖 |
如何向 AI 描述数据库问题
我的应用首页加载非常慢(约 5 秒),数据表大概有 10 万条记录。
主要的查询是:SELECT * FROM orders WHERE user_id = ? ORDER BY created_at DESC LIMIT 20。
帮我检查这个查询是否需要加索引。
AI 会建议在 user_id 和 created_at 上创建复合索引。创建后,查询时间会降到十几毫秒。
更完整的描述模板:
页面:[页面名称] 加载慢,耗时约 [X] 秒。
哪个操作慢:[点击按钮/打开页面/提交表单]。
数据量:orders 表约 [X] 万条记录。
慢的查询(如果知道):[把 SQL 或 ORM 查询贴出来]。
什么时候开始变慢:[一直慢 / 最近数据量大了才慢]。
不需要把所有字段都填满——填你知道的就行。AI 会追问不清楚的细节。
数据库类型的不同
不同类型的数据库在一些细节上不同,但核心概念相同:
| 数据库 | 适合场景 | 在 Vibe Coding 中 |
|---|---|---|
| SQLite | 本地开发、数据量小 | 默认选择——零配置,文件级数据库 |
| PostgreSQL | 生产环境、数据量大 | Prisma 连接,Vercel/ Railway 部署 |
| MySQL | 传统 Web 应用 | 不推荐——易用性不如 PostgreSQL |
| MongoDB | 文档型数据 | AI 也很熟悉,但查询模式不同 |
你不需要自己选——告诉 AI "这个项目要用什么数据库",AI 会根据项目需求推荐。大多数情况 AI 会推荐 SQLite(开发阶段)+ PostgreSQL(生产环境)的组合。
理解 vs 不必理解
关于数据库,你不需要知道:
- B+ 树的内部结构(索引的实现原理)
- 事务的隔离级别(除非你在做金融系统)
- 查询优化器的成本计算
关于数据库,你最好知道:
- 索引 = 书的目录,能加速查询
- JOIN 比 N 次单独查询更高效
- 数据量大到一定程度(万级以上)时,查询速度会明显下降
这三个"最好知道"的点,能帮你解决 80% 的数据库性能问题。把症状告诉 AI,AI 做诊断,你做验证。
- 数据库像超大型 Excel 表——表 = Sheet,行 = 一行数据,列 = 一种数据类型。数据不会像人类那样"聪明地"查找,需要索引指引。
- 索引 = 书的目录——没有索引时数据库要扫描整个表。需要告诉 AI "帮我检查缺少索引"。
- N+1 查询是最常见的性能问题——用 JOIN 替代循环查询。症状是数据量增加时页面线性变慢。
- 数据量增长的三个阶段:< 1 万行不需要索引,1 万~10 万行需要索引,> 10 万行必须索引。
- 数据库类型不同但核心概念相同:开发用 SQLite,生产用 PostgreSQL。AI 会自动选择。
- 你不需要懂 B+ 树,但最好知道索引、JOIN、数据量增长这三个概念。
对 Claude Code 说:
"我有一个 SQLite 数据库,orders 表有 50 万条数据。查询 SELECT * FROM orders WHERE status = 'pending' ORDER BY created_at DESC 需要 3 秒。请帮我诊断并提供优化方案。"
进阶练习:
让 AI "在我的项目中创建一个简单的演示:创建 10000 条测试数据插入 orders 表,然后分别用有索引和无索引的情况下执行同一个查询,展示查询时间差异。" 这个练习会让你亲眼看到索引的效果——从"秒级"到"毫秒级"的差异。