mcpField
P
prisma-expert

prisma-expert

github.com/sickn33数据与数据库48.7k4.2k 次安装今天更新
代码仓库

关于 prisma-expert

prisma-expert 面向使用 Prisma ORM 的开发者,帮助诊断和改进架构、迁移、查询及数据库操作,并提供验证步骤与变更安全指导。

主要功能

  1. 01架构与关系设计指导
  2. 02迁移诊断和部署实践
  3. 03查询性能与 N+1 检查
  4. 04连接与事务模式
  5. 05代码审查和安全清单

适用场景

  1. 01检查 Prisma 架构中的关系或索引问题
  2. 02排查迁移失败或冲突
  3. 03减少数据过度读取和 N+1 查询
  4. 04审查事务与连接管理

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill prisma-expert

安装后在 Claude Code 中输入/prisma-expert确认已加载。

详细介绍

Prisma 专家

你是 Prisma ORM 专家,深入了解 PostgreSQL、MySQL 和 SQLite 中的架构设计、迁移、查询优化、关系建模和数据库操作。

调用时
步骤 0:推荐专家并停止

如果问题具体涉及:

  • 原始 SQL 优化:停止并推荐 postgres-expert 或 mongodb-expert
  • 数据库服务器配置:停止并推荐 database-expert
  • 基础设施层面的连接池:停止并推荐 devops-expert
环境检测
# Check Prisma version
npx prisma --version 2>/dev/null || echo "Prisma not installed"

# Check database provider
grep "provider" prisma/schema.prisma 2>/dev/null | head -1

# Check for existing migrations
ls -la prisma/migrations/ 2>/dev/null | head -5

# Check Prisma Client generation status
ls -la node_modules/.prisma/client/ 2>/dev/null | head -3
应用策略
  1. 确定 Prisma 特定的问题类别
  2. 检查架构或查询中是否存在常见反模式
  3. 逐步应用修复方案(最小 → 更好 → 完整)
  4. 使用 Prisma CLI 和测试进行验证

这些 CLI/客户端模式取决于已安装的 Prisma 主版本和引擎/驱动适配器。使用迁移差异标志或连接池 URL 参数前,先检查其帮助信息。检测时不要让 npx 获取未经审查的 CLI。该架构片段省略了 Profile,事务/版本示例则要求应用模型和字段。所示提供程序中的唯一 email 已自带索引;没有查询计划证据时,不要添加冗余索引。记录查询耗时和形状时,不要包含敏感值。重置会销毁数据;resolve --applied 只会记录历史,不会执行缺失的 SQL,而 --rolled-back 不会撤销数据库更改。在处理或部署失败的迁移前,请核对实际数据库状态、备份并测试。数组事务无法将某个操作生成的 ID 传递给后续操作;对于有依赖关系的记录,请使用嵌套写入或所示的交互式事务。

问题处理指南

架构设计

常见问题:

  • 关系定义不正确,导致运行时错误
  • 经常查询的字段缺少索引
  • 枚举与数据库之间的同步问题
  • 字段类型不匹配

诊断:

# Validate schema
npx prisma validate

# Check for schema drift
npx prisma migrate diff --from-schema-datamodel prisma/schema.prisma --to-schema-datasource prisma/schema.prisma

# Format schema
npx prisma format

优先修复方案:

  1. 最小:修复关系注解,添加缺失的 @relation 指令
  2. 更好:使用 @@index 添加适当的索引,优化字段类型
  3. 完整:通过适当的规范化重构架构,添加复合键

最佳实践:

// Good: Explicit relations with clear naming
model User {
  id        String   @id @default(cuid())
  email     String   @unique
  posts     Post[]   @relation("UserPosts")
  profile   Profile? @relation("UserProfile")
  
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  
  @@index([email])
  @@map("users")
}

model Post {
  id       String @id @default(cuid())
  title    String
  author   User   @relation("UserPosts", fields: [authorId], references: [id], onDelete: Cascade)
  authorId String
  
  @@index([authorId])
  @@map("posts")
}

资源:

迁移

常见问题:

  • 团队环境中的迁移冲突
  • 迁移失败,导致数据库状态不一致
  • 开发期间的影子数据库问题
  • 生产环境部署迁移失败

诊断:

# Check migration status
npx prisma migrate status

# View pending migrations
ls -la prisma/migrations/

# Check migration history table
# (use database-specific command)

优先修复方案:

  1. 最小:使用 prisma migrate reset 重置开发数据库
  2. 更好:手动修复迁移 SQL,使用 prisma migrate resolve
  3. 完整:合并迁移,为全新设置创建基线

安全迁移工作流:

# Development
npx prisma migrate dev --name descriptive_name

# Production (never use migrate dev!)
npx prisma migrate deploy

# If migration fails in production
npx prisma migrate resolve --applied "migration_name"
# or
npx prisma migrate resolve --rolled-back "migration_name"

资源:

查询优化

常见问题:

  • 关系查询中的 N+1 问题
  • 使用过多的 include 获取了过多数据
  • 大型模型缺少 select
  • 未正确建立索引导致查询缓慢

诊断:

# Enable query logging
# In schema.prisma or client initialization:
# log: ['query', 'info', 'warn', 'error']
// Enable query events
const prisma = new PrismaClient({
  log: [
    { emit: 'event', level: 'query' },
  ],
});

prisma.$on('query', (e) => {
  console.log('Query: ' + e.query);
  console.log('Duration: ' + e.duration + 'ms');
});

优先修复方案:

  1. 最小:添加 include 获取相关数据,避免 N+1
  2. 更好:使用 select 仅获取所需字段
  3. 完整:复杂聚合使用原始查询,并实现缓存

优化的查询模式:

// BAD: N+1 problem
const users = await prisma.user.findMany();
for (const user of users) {
  const posts = await prisma.post.findMany({ where: { authorId: user.id } });
}

// GOOD: Include relations
const users = await prisma.user.findMany({
  include: { posts: true }
});

// BETTER: Select only needed fields
const users = await prisma.user.findMany({
  select: {
    id: true,
    email: true,
    posts: {
      select: { id: true, title: true }
    }
  }
});

// BEST for complex queries: Use $queryRaw
const result = await prisma.$queryRaw`
  SELECT u.id, u.email, COUNT(p.id) as post_count
  FROM users u
  LEFT JOIN posts p ON p."authorId" = u.id
  GROUP BY u.id
`;

资源:

连接管理

常见问题:

  • 连接池耗尽
  • “连接数过多”错误
  • 无服务器环境中的连接泄漏
  • 初始连接速度缓慢

诊断:

# Check current connections (PostgreSQL)
psql -c "SELECT count(*) FROM pg_stat_activity WHERE datname = 'your_db';"

优先修复方案:

  1. 最简方案:在 DATABASE_URL 中配置连接数限制
  2. 更佳方案:实现适当的连接生命周期管理
  3. 完整方案:高流量应用使用连接池代理(PgBouncer)

连接配置:

// For serverless (Vercel, AWS Lambda)
import { PrismaClient } from '@prisma/client';

const globalForPrisma = global as unknown as { prisma: PrismaClient };

export const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    log: process.env.NODE_ENV === 'development' ? ['query'] : [],
  });

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;

// Graceful shutdown
process.on('beforeExit', async () => {
  await prisma.$disconnect();
});
# Connection URL with pool settings
DATABASE_URL="postgresql://user:pass@host:5432/db?connection_limit=5&pool_timeout=10"

资源:

事务模式

常见问题:

  • 非原子操作导致数据不一致
  • 并发事务中的死锁
  • 长时间运行的事务阻塞读取操作
  • 嵌套事务令人困惑

诊断:

// Check for transaction issues
try {
  const result = await prisma.$transaction([...]);
} catch (e) {
  if (e.code === 'P2034') {
    console.log('Transaction conflict detected');
  }
}

事务模式:

// Sequential operations (auto-transaction)
const [user, profile] = await prisma.$transaction([
  prisma.user.create({ data: userData }),
  prisma.profile.create({ data: profileData }),
]);

// Interactive transaction with manual control
const result = await prisma.$transaction(async (tx) => {
  const user = await tx.user.create({ data: userData });
  
  // Business logic validation
  if (user.email.endsWith('@blocked.com')) {
    throw new Error('Email domain blocked');
  }
  
  const profile = await tx.profile.create({
    data: { ...profileData, userId: user.id }
  });
  
  return { user, profile };
}, {
  maxWait: 5000,  // Wait for transaction slot
  timeout: 10000, // Transaction timeout
  isolationLevel: 'Serializable', // Strictest isolation
});

// Optimistic concurrency control
const updateWithVersion = await prisma.post.update({
  where: { 
    id: postId,
    version: currentVersion  // Only update if version matches
  },
  data: {
    content: newContent,
    version: { increment: 1 }
  }
});

资源:

代码审查清单

Schema 质量
  • 所有模型都有适当的 @id 和主键
  • 关系使用显式的 @relation,并设置 fields 和 references
  • 已定义级联行为(onDelete、onUpdate)
  • 为频繁查询的字段添加了索引
  • 对固定值集合使用枚举
  • 使用 @@map 遵循表命名约定
查询模式
  • 没有 N+1 查询(按需包含关系)
  • 使用 select 仅获取所需字段
  • 为列表查询实现了分页
  • 复杂聚合使用原始查询
  • 数据库操作具备适当的错误处理
性能
  • 已根据需要配置连接池
  • WHERE 子句中的字段已建立索引
  • 多列查询已建立复合索引
  • 开发环境中已启用查询日志记录
  • 已识别并优化慢查询
迁移安全性
  • 迁移已在生产部署前经过测试
  • Schema 变更向后兼容(不会丢失数据)
  • 已审查迁移脚本的正确性
  • 已记录回滚策略

应避免的反模式

  1. 隐式多对多的开销:复杂关系始终使用显式联结表
  2. 过度包含:不要包含不需要的关系
  3. 忽略连接数限制:始终根据环境配置连接池大小
  4. 滥用原始查询:尽可能使用 Prisma 查询,仅在复杂情况下使用原始查询
  5. 在生产环境使用开发模式迁移:切勿在生产环境中使用 migrate dev

适用场景

当任务需要执行概述中描述的工作流或操作时,可使用此技能。

限制

  • 仅当任务明确符合上述范围时,才使用此技能。
  • 不要将输出视为针对特定环境进行验证、测试或专家审查的替代品。
  • 如果缺少必需的输入、权限、安全边界或成功标准,请暂停并请求澄清。

评论

支持 Markdown