索引设计与命名映射
本教程共 54 篇 · 第 15 篇 · 更新于 2026-08-11 · 约 4 分钟阅读
本节目标:掌握 @@index 的配置参数与左前缀规则,学会用 @map/@@map 解耦命名。
数据一多,查询就慢。索引(index)是数据库为加速查询准备的数据结构,相当于书的目录。代价是写入变慢、占用空间。加索引,是在读写之间找平衡。
基础索引:单列与复合
Prisma 用 @@index 声明索引:
model Post {
id Int @id @default(autoincrement())
title String
author String
createdAt DateTime @default(now())
@@index([author])
@@index([author, createdAt(sort: Desc)])
}
单列索引服务等值查询。复合索引要遵守左前缀规则:查询条件必须命中最左边的字段,索引才生效。上面的第二个索引能加速 WHERE author = ?,也能加速 WHERE author = ? AND createdAt > ?,但单独查 createdAt 用不上它。
所以复合索引的字段顺序要按查询模式来排:最常过滤的放最前。
@unique 和 @@unique 会顺带创建唯一索引,既保证不重复,又加速查询:
model User {
id Int @id @default(autoincrement())
email String @unique
}
高级参数:type、sort、length、where
PostgreSQL 的 @@index 支持自定义访问类型:
model Session {
id Int @id @default(autoincrement())
token String
tags String[]
@@index([token], type: Hash) // 只服务等值查询
@@index([tags], type: Gin) // 服务数组包含查询
}
- Hash:等值查询快、省空间,但不支持范围查询
- Gin:适合 JSONB、数组、全文检索
- Gist、SpGist、Brin:分别服务网络地址、文本模式、时间序列类数据
sort 控制索引内列的排序方向,复合索引里常见 createdAt(sort: Desc);length 是 MySQL 专属,给超长字符串做前缀索引;Gin/Gist 索引还能用 ops 指定操作符类。
部分索引(partial index)只索引满足条件的行,体积小、写入快:
generator client {
provider = "prisma-client"
output = "./generated"
previewFeatures = ["partialIndexes"]
}
model User {
id Int @id @default(autoincrement())
email String
status String
deletedAt DateTime?
@@unique([email], where: raw("status = 'active'"))
@@index([email], where: { deletedAt: null })
}
where 有两种写法:raw(“SQL 片段”) 最灵活,对象字面量有类型安全。部分索引支持 PostgreSQL、SQLite、SQL Server、CockroachDB,MySQL 不支持。
Tip软删除场景是部分索引的经典用法:
WHERE "deletedAt" IS NULL让唯一索引只约束未删除的行,允许重复的已删除数据存在。
索引与查询匹配
判断索引有没有用,看查询的 where、orderBy 是否命中。常用手段:
- 覆盖查询:让索引包含 where 和 orderBy 用到的全部列
- 用 EXPLAIN 看执行计划,确认索引真被采用
- 别过度索引:每多一个索引,写入就多一分开销
Note不要「为每个字段都建索引」。先跑真实查询,用 EXPLAIN 找出慢的,再针对性地加。
命名映射:@map 与 @@map
数据库里叫 comments 的表,内省后会变成模型 Comment,并自动补上 @@map("comments")。模型名与表名就这样解耦了:
model Comment {
content String @map("comment_text")
email String @map("commenter_email")
@@map("comments")
}
好处是:数据库沿用团队的 snake_case 规范,Prisma Client API 里却用漂亮的 camelCase。
索引和约束的名字也能自定义,用 map 参数:
model Post {
id Int @id
title String
@@index([title], map: "my_custom_index_name")
}
不写 map 时,Prisma 按约定自动取名:{表名}_pkey、{表名}_{列名}_key、{表名}_{列名}_idx、{表名}_{列名}_fkey。注意命名以数据库里的实际表名、列名为准,不是 Schema 里的模型名。
Note内省时,只有不符合 Prisma 默认约定的索引名才会渲染出 map 参数,符合约定的省略不写,保持 Schema 干净。
参考来源
- Prisma 官方文档:Indexes
- Prisma 官方文档:Database mapping
- Mapagam:Implementing Database Indexes、Working with Model Attributes