rag / implement.md
gaojintao01
pg 适配
0fb4a2f
# PostgreSQL 迁移实施文档
## 1. 问题描述
在将 AnythingLLM 从 SQLite 迁移到 PostgreSQL 过程中,用户遇到了以下错误:
### 错误信息
- **P3018 错误**: `A migration failed to apply. New migration failed to apply`
- **P3009 错误**: `migration found a failed migration`
### 具体错误详情
执行 `npx prisma migrate dev` 时出现:
```
Error: P3018
A migration failed to apply. New migration failed to apply.
Query failed: database error
ERROR: syntax error at or near "AUTOINCREMENT"
LINE 1: ...id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT
```
## 2. 错误原因分析
### 2.1 根本原因
Prisma 生成的迁移文件包含了 SQLite 特定的 `AUTOINCREMENT` 语法,但 PostgreSQL 不支持此语法。
### 2.2 问题详情
- **SQLite 语法**: `PRIMARY KEY AUTOINCREMENT`
- **PostgreSQL 语法**: 使用 `SERIAL``BIGSERIAL` 类型,或使用 `IDENTITY`
### 2.3 受影响的表
查看迁移文件发现以下表都使用了 `AUTOINCREMENT`
- `api_keys`
- `workspace_documents`
- `invites`
- `system_settings`
- `users`
- `document_vectors`
- `welcome_messages`
- `workspaces`
- `workspace_chats`
- `workspace_users`
- `workspace_parsed_files`
## 3. 解决方案
### 方案一:重置迁移(推荐用于开发环境)
```bash
# 1. 删除所有迁移文件
rm -rf server/prisma/migrations/*
# 2. 重置数据库
npx prisma migrate reset --force
# 3. 重新生成迁移
npx prisma migrate dev --name init
```
### 方案二:手动修复迁移文件
```bash
# 1. 编辑迁移文件,将 AUTOINCREMENT 替换为 PostgreSQL 语法
# 例如:
# 原始:id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT
# 修改为:id SERIAL PRIMARY KEY
# 2. 手动执行修复后的 SQL
psql $DATABASE_URL -f server/prisma/migrations/20230921191814_init/migration.sql
```
### 方案三:使用 Prisma 数据迁移功能
```bash
# 1. 创建新的空迁移
npx prisma migrate dev --name fix-postgresql-syntax --create-only
# 2. 编辑新迁移文件,添加修复 SQL
```
## 4. 具体实施步骤
### 4.1 环境准备
```bash
# 1. 安装 PostgreSQL
# Ubuntu/Debian
sudo apt-get install postgresql postgresql-contrib
# 2. 创建数据库和用户
sudo -u postgres psql
CREATE USER anythingllm WITH PASSWORD 'your_password';
CREATE DATABASE anythingllm OWNER anythingllm;
GRANT ALL PRIVILEGES ON DATABASE anythingllm TO anythingllm;
\q
# 3. 配置环境变量
export DATABASE_URL="postgresql://anythingllm:your_password@localhost:5432/anythingllm"
```
### 4.2 使用方案一的实施步骤
```bash
# 进入项目目录
cd /path/to/anythingllm
# 1. 备份现有数据(如果需要)
sqlite3 server/storage/anythingllm.db ".backup backup.db"
# 2. 删除现有迁移
rm -rf server/prisma/migrations/*
# 3. 更新 schema.prisma 确保使用正确的数据库类型
# 确保 provider = "postgresql"
# 4. 重置并重新生成迁移
npx prisma migrate reset --force
npx prisma migrate dev --name init
# 5. 生成客户端
npx prisma generate
# 6. 运行种子数据(如果有)
node server/prisma/seed.js
```
### 4.3 手动迁移数据(从 SQLite 到 PostgreSQL)
```bash
# 1. 安装迁移工具
npm install -g pgloader
# 2. 创建迁移配置文件 load.command
LOAD DATABASE
FROM sqlite://server/storage/anythingllm.db
INTO postgresql://anythingllm:your_password@localhost:5432/anythingllm
WITH include no drop, create tables, create indexes, reset sequences, foreign keys
SET maintenance_work_mem to '128MB', work_mem to '12MB';
CAST
type datetime to timestamptz drop default drop not null using zero-datetime-to-timestamptz,
type date drop not null drop default using zero-date-to-date;
# 3. 执行迁移
pgloader load.command
```
## 5. 预防措施
### 5.1 开发实践
1. **使用数据库抽象**
- 在 schema.prisma 中使用 Prisma 的类型系统
- 避免使用特定数据库的原始 SQL
2. **多数据库测试**
```bash
# 在 CI/CD 中测试多个数据库
# SQLite
DATABASE_URL="file:./dev.db" npx prisma migrate dev
# PostgreSQL
DATABASE_URL="postgresql://user:pass@localhost/db" npx prisma migrate dev
```
3. **迁移审查**
- 所有迁移文件需要代码审查
- 检查是否使用了特定数据库语法
### 5.2 配置管理
```javascript
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql" // 明确指定数据库类型
url = env("DATABASE_URL")
}
```
## 6. 最佳实践
### 6.1 多数据库支持建议
1. ** schema 设计原则**
- 使用 Prisma 的标准类型
- 避免使用特定数据库的功能
- 保持模型简单和可移植
2. **迁移策略**
```bash
# 创建迁移时指定数据库
npx prisma migrate dev --create-only --name add_new_feature
# 检查生成的 SQL
cat server/prisma/migrations/*/migration.sql
# 应用迁移
npx prisma migrate dev
```
3. **测试策略**
- 在开发中使用 SQLite
- 在测试和生产中使用 PostgreSQL
- 定期在不同数据库间测试迁移
### 6.2 生产环境部署
```yaml
# docker-compose.yml
version: '3.8'
services:
postgres:
image: postgres:15
environment:
POSTGRES_DB: anythingllm
POSTGRES_USER: anythingllm
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
anything-llm:
build: .
environment:
DATABASE_URL: "postgresql://anythingllm:${POSTGRES_PASSWORD}@postgres:5432/anythingllm"
depends_on:
- postgres
ports:
- "3001:3001"
volumes:
postgres_data:
```
### 6.3 监控和维护
1. **数据库监控**
```sql
-- 检查表大小
SELECT
schemaname,
tablename,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;
```
2. **定期维护**
```bash
# 更新统计信息
npx prisma db execute --stdin <<< "ANALYZE;"
# 清理旧数据(根据需要)
npx prisma db execute --stdin <<< "VACUUM;"
```
## 7. 故障排除
### 7.1 常见错误及解决方案
1. **连接错误**
```
Error: P1001: Can't reach database server
```
解决方案:检查 PostgreSQL 服务是否运行,验证连接字符串
2. **权限错误**
```
Error: P1003: Database does not exist
```
解决方案:创建数据库并授予正确权限
3. **迁移冲突**
```
Error: P1010: Database error
```
解决方案:使用 `prisma migrate resolve` 解决冲突
### 7.2 调试命令
```bash
# 检查迁移状态
npx prisma migrate status
# 查看数据库信息
npx prisma db execute --stdin <<< "SELECT version();"
# 测试连接
npx prisma db push --preview-feature
```
## 8. 总结
PostgreSQL 迁移的主要挑战在于数据库语法差异。通过遵循本文档的解决方案和最佳实践,可以成功将 AnythingLLM 从 SQLite 迁移到 PostgreSQL,并获得更好的性能和可扩展性。
关键要点:
1. 使用 Prisma 的抽象层避免特定数据库语法
2. 在开发早期测试多数据库兼容性
3. 建立完善的迁移和测试流程
4. 定期备份和维护数据库