Vibe Tutorial
数据持久化与数据库

7.11 数据库性能优化

Tip

同样的功能,有的人写出来是"秒开",有的人写出来是"转圈圈"。区别不在于电脑好坏,而在于你是否懂得"吝啬"。


1. 为什么要学这个?

你的电商网站刚上线时,因只有 10 个商品,怎么点都飞快。 今天上午,运营导入了 10 万个商品。 你再次打开首页,加载圈圈足足转了 5 秒钟才出来。

也就是这 5 秒钟,一半的用户以为网站挂了,直接关掉页面走了。 学会这章的技巧,哪怕数据量再翻 100 倍,你的网站依然能像闪电一样快。


2. 核心概念:让程序变快的三招

第一招:给数据编目录 (索引)

场景:你要在 10 万个用户里找一个叫 "张三" 的人。

  • 慢做法 (没索引):你得拿着名单,从第一个人名开始,一行一行往下看。如果运气不好,张三在最后一行,你就得看 10 万次。
  • 快做法 (有索引):你手里有一本"姓氏目录"。直接翻到 "Z",瞬间就找到了。

怎么做? 告诉 Prisma,你会经常按 "email" 查人。它就会自动给 email 造一个目录。

model User {
  email String 
  @@index([email]) // 👈 这里!给 email 加个目录
}

第二招:只拿你需要的 (查询瘦身)

场景:你去超市买瓶水。

  • 慢做法 (findMany 不加参数):售货员把超市里所有的商品(大米、电视、冰箱...)都打包塞进你车里,虽然你其实只要一瓶水。
  • 快做法 (select):你明确告诉售货员:"我只要水"。

代码对比

// ❌ 慢:把用户的头像、简介、密码全拿回来了,浪费流量
const users = await prisma.user.findMany();

// ✅ 快:只取 id 和 name,轻装上阵
const users = await prisma.user.findMany({
  select: { id: true, name: true }
});

第三招:别让快递员跑空趟 (解决 N+1)

场景:你要给 100 个客户送货。

  • 笨办法 (N+1):回公司取第 1 个快件 -> 送到客户家 -> 空手回公司 -> 取第 2 个快件...
    • 你得在路上跑 200 趟!
  • 聪明办法 (include):在公司一次性把 100 个快件装车 -> 出发一趟送完。

代码对比

// ❌ 笨办法:在循环里查数据库
for (const user of users) {
  // 每一轮循环,都要去数据库跑一趟,极慢!
  await prisma.post.findMany(...) 
}

// ✅ 聪明办法:一次打包带走
const users = await prisma.user.findMany({
  include: { posts: true } // 👈 顺便把这人的文章也带回来
});

3. 避坑指南

❌ 错误做法 ✅ 正确做法 💡 为什么
循环里查库 打包查询 这是新手最容易犯的错。记住:for 循环里永远不要写 await 数据库代码
全都查出来 分页 (take) 永远不要试图一次性把所有数据都展示给用户。如果表里有 100 万行,你的服务器内存会瞬间撑爆。
到处加索引 也就是查谁加谁 索引虽然好,但如果不查的字段也加索引,就像给书的每一页都贴标签,反而让书变厚了(写入变慢)。

4. 真实案例

Story

Stack Overflow 的 2 台服务器神话

全球最大的程序员问答网站 Stack Overflow,每天有几千万人在上面查问题。但你敢信吗?支撑这庞大流量的数据库服务器,竟然只有 2 台。 他们的秘诀不是买超贵的电脑,而是极其吝啬。 工程师会为了节省哪怕 1 毫秒的时间,反复修改查询代码,确保绝不拿多余的数据,绝不跑冤枉路。

Vibe 心法:电脑虽然很快,但也不禁造。写代码时要像守财奴一样,对每一个字节、每一次查询都精打细算。


5. 本章小结

  1. 查得慢:先看看是不是忘了加索引(目录)。
  2. 传得慢:是不是拿了太多不该拿的字段?
  3. 循环慢:是不是在循环里反复跑腿了?