# 数据库迁移

<cite>
**本文引用的文件**
- [backend/alembic/versions/488d0bd5ab01_initial_migration.py](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py)
- [backend/alembic/env.py](file://backend/alembic/env.py)
- [backend/alembic.ini](file://backend/alembic.ini)
- [backend/alembic/script.py.mako](file://backend/alembic/script.py.mako)
- [backend/app/database.py](file://backend/app/database.py)
- [backend/app/models/__init__.py](file://backend/app/models/__init__.py)
- [backend/app/models/user.py](file://backend/app/models/user.py)
- [backend/app/models/query.py](file://backend/app/models/query.py)
- [backend/app/models/citation_record.py](file://backend/app/models/citation_record.py)
- [backend/app/models/query_task.py](file://backend/app/models/query_task.py)
- [backend/app/models/subscription.py](file://backend/app/models/subscription.py)
- [backend/app/config.py](file://backend/app/config.py)
</cite>

## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)

## 简介
本文件面向GEO项目的数据库迁移与版本管理，系统性说明基于Alembic的迁移框架配置与使用方式，覆盖迁移脚本生成、版本管理、数据库升级策略、初始迁移实现（含表创建、索引与约束）、迁移命令（upgrade、downgrade、autogenerate）以及生产环境最佳实践与风险控制。读者无需深入Python或SQLAlchemy即可理解并安全地执行迁移。

## 项目结构
GEO后端采用异步SQLAlchemy与Alembic进行数据库迁移管理，迁移相关代码集中在backend/alembic目录中，并通过env.py与应用模型（models）建立连接。数据库连接由应用配置提供，迁移脚本位于versions子目录中，按版本顺序命名。

```mermaid
graph TB
subgraph "迁移配置"
A["alembic.ini<br/>脚本位置、日志、URL等"]
B["env.py<br/>在线/离线迁移入口"]
C["script.py.mako<br/>迁移模板"]
end
subgraph "模型定义"
D["models/__init__.py<br/>导出所有模型"]
E["models/user.py"]
F["models/query.py"]
G["models/citation_record.py"]
H["models/query_task.py"]
I["models/subscription.py"]
end
subgraph "数据库"
J["PostgreSQL 实例"]
end
A --> B
B --> D
D --> E
D --> F
D --> G
D --> H
D --> I
B --> J
```

**图表来源**
- [backend/alembic.ini:1-150](file://backend/alembic.ini#L1-L150)
- [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89)
- [backend/alembic/script.py.mako:1-29](file://backend/alembic/script.py.mako#L1-L29)
- [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14)
- [backend/app/models/user.py:1-41](file://backend/app/models/user.py#L1-L41)
- [backend/app/models/query.py:1-55](file://backend/app/models/query.py#L1-L55)
- [backend/app/models/citation_record.py:1-42](file://backend/app/models/citation_record.py#L1-L42)
- [backend/app/models/query_task.py:1-39](file://backend/app/models/query_task.py#L1-L39)
- [backend/app/models/subscription.py:1-37](file://backend/app/models/subscription.py#L1-L37)

**章节来源**
- [backend/alembic.ini:1-150](file://backend/alembic.ini#L1-L150)
- [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89)
- [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14)

## 核心组件
- 迁移配置与入口
  - alembic.ini：定义脚本位置、日志级别、数据库URL等全局设置。
  - env.py：根据运行模式（在线/离线）加载目标元数据并执行迁移。
  - script.py.mako：迁移脚本模板，定义upgrade/downgrade骨架。
- 模型与元数据
  - models/__init__.py：聚合导出所有ORM模型，供Alembic扫描。
  - 各模型文件：定义表结构、字段类型、索引与外键关系。
- 数据库引擎
  - app/database.py：创建异步引擎与Base，为迁移提供元数据基础。
  - app/config.py：提供DATABASE_URL，被env.py与alembic.ini共同使用。

**章节来源**
- [backend/alembic.ini:1-150](file://backend/alembic.ini#L1-L150)
- [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89)
- [backend/alembic/script.py.mako:1-29](file://backend/alembic/script.py.mako#L1-L29)
- [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14)
- [backend/app/models/user.py:1-41](file://backend/app/models/user.py#L1-L41)
- [backend/app/models/query.py:1-55](file://backend/app/models/query.py#L1-L55)
- [backend/app/models/citation_record.py:1-42](file://backend/app/models/citation_record.py#L1-L42)
- [backend/app/models/query_task.py:1-39](file://backend/app/models/query_task.py#L1-L39)
- [backend/app/models/subscription.py:1-37](file://backend/app/models/subscription.py#L1-L37)
- [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29)
- [backend/app/config.py:1-17](file://backend/app/config.py#L1-L17)

## 架构总览
下图展示从命令到数据库的迁移执行链路，包括在线与离线两种模式，以及模型元数据对迁移的影响。

```mermaid
sequenceDiagram
participant CLI as "命令行"
participant Alembic as "Alembic CLI"
participant Env as "env.py"
participant DB as "PostgreSQL"
CLI->>Alembic : 执行迁移命令
Alembic->>Env : 加载配置与元数据
Env->>Env : 判断在线/离线模式
alt 在线模式
Env->>DB : 异步连接并执行事务
else 离线模式
Env->>DB : 使用URL直接执行DDL
end
Env-->>Alembic : 返回迁移结果
Alembic-->>CLI : 输出状态与日志
```

**图表来源**
- [backend/alembic/env.py:33-89](file://backend/alembic/env.py#L33-L89)
- [backend/alembic.ini:86-89](file://backend/alembic.ini#L86-L89)

## 详细组件分析

### 初始迁移脚本（488d0bd5ab01）
该脚本实现首次数据库初始化，包含以下要点：
- 表创建
  - users：用户主表，包含唯一邮箱、计划等级、配额、激活状态等字段。
  - queries：查询任务表，关联users，包含关键词、品牌、平台列表、频率、状态及时间戳。
  - citation_records：引用记录表，关联queries，包含平台、是否引用、竞品品牌、原始响应等。
  - query_tasks：查询任务执行表，关联queries，包含状态、错误信息与调度/开始/完成时间。
  - subscriptions：订阅表，关联users，包含计划、状态、起止日期、金额与支付信息。
- 索引建立
  - queries：按user_id、status、next_query_at建立索引。
  - citation_records：按query_id、queried_at、platform建立索引。
  - query_tasks：按status建立索引。
- 约束与默认值
  - 外键约束：各子表均对父表执行级联删除。
  - 默认值：广泛使用服务器默认值（如NOW()、JSONB空数组、字符串默认值）。
- 回滚策略
  - downgrade按逆序删除表与索引，确保幂等与可恢复。

```mermaid
flowchart TD
Start(["执行初始迁移"]) --> CreateUsers["创建 users 表"]
CreateUsers --> CreateQueries["创建 queries 表<br/>建立索引"]
CreateQueries --> CreateRecords["创建 citation_records 表<br/>建立索引"]
CreateRecords --> CreateTasks["创建 query_tasks 表<br/>建立索引"]
CreateTasks --> CreateSubs["创建 subscriptions 表"]
CreateSubs --> End(["完成"])
```

**图表来源**
- [backend/alembic/versions/488d0bd5ab01_initial_migration.py:21-128](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L21-L128)

**章节来源**
- [backend/alembic/versions/488d0bd5ab01_initial_migration.py:1-128](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L1-L128)

### 迁移环境与元数据
- 元数据来源
  - env.py通过app.database.Base.metadata提供目标元数据，确保Alembic能识别应用模型的变更。
  - models/__init__.py统一导出所有模型，避免遗漏。
- 在线/离线模式
  - 在线模式：使用异步引擎连接数据库，适合生产与容器环境。
  - 离线模式：直接使用URL执行DDL，便于测试与快速验证。
- 配置来源
  - DATABASE_URL来自app/config.py，同时在alembic.ini中也有默认示例URL。

```mermaid
graph LR
A["env.py"] --> B["Base.metadata"]
B --> C["models/*"]
A --> D["在线/离线执行器"]
D --> E["PostgreSQL"]
```

**图表来源**
- [backend/alembic/env.py:10-25](file://backend/alembic/env.py#L10-L25)
- [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14)
- [backend/app/database.py](file://backend/app/database.py#L20)
- [backend/app/config.py](file://backend/app/config.py#L7)

**章节来源**
- [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89)
- [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14)
- [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29)
- [backend/app/config.py:1-17](file://backend/app/config.py#L1-L17)

### 迁移命令与工作流
- 常用命令
  - 升级：将数据库迁移到最新版本。
  - 降级：将数据库回退到指定版本。
  - 自动化生成：基于模型变更自动生成迁移脚本。
- 工作流建议
  - 开发阶段：先在本地dev环境验证，再合并到测试环境。
  - 测试阶段：在隔离数据库上执行，验证数据完整性与索引有效性。
  - 生产阶段：严格遵循“只读优先”原则，先备份，再执行，最后验证。

```mermaid
flowchart TD
Dev["开发环境"] --> Test["测试环境"]
Test --> Prod["生产环境"]
Dev --> |dry-run/验证| Test
Test --> |备份/演练| Prod
```

[本节为通用流程说明，不直接分析具体文件，故无“章节来源”]

### 数据保护、回滚与版本控制
- 数据保护
  - 在生产环境执行前务必备份数据库。
  - 对大表操作（如重建索引）选择维护窗口，避免高峰时段。
- 回滚机制
  - 初始迁移提供完整的downgrade路径，确保可逆。
  - 建议每次迁移仅包含单一逻辑变更，降低回滚复杂度。
- 版本控制
  - 迁移脚本以版本号命名，保持顺序与可追溯性。
  - 将迁移脚本纳入版本控制系统，配合提交信息描述变更意图。

**章节来源**
- [backend/alembic/versions/488d0bd5ab01_initial_migration.py:114-128](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L114-L128)

### 生产环境最佳实践与风险控制
- 风险控制
  - 限制迁移窗口，避免业务高峰期。
  - 使用只读副本或独立测试库先行验证。
  - 对DDL操作进行分批执行，逐步替换索引与约束。
- 可观测性
  - 记录迁移日志，监控执行时长与失败原因。
  - 在应用侧增加迁移状态检查，防止未完成迁移导致的数据不一致。
- 安全与合规
  - 严格管理DATABASE_URL与访问权限。
  - 对敏感字段（如密码哈希）迁移需遵循最小暴露原则。

**章节来源**
- [backend/alembic.ini:115-150](file://backend/alembic.ini#L115-L150)
- [backend/alembic/env.py:33-89](file://backend/alembic/env.py#L33-L89)

## 依赖分析
- 组件耦合
  - env.py依赖app/config.py提供的DATABASE_URL与app/database.py的Base元数据。
  - models/__init__.py集中导出所有模型，提升扫描效率与一致性。
- 外部依赖
  - PostgreSQL作为目标数据库，UUID、JSONB、时间戳等类型在迁移脚本中被广泛使用。
- 潜在问题
  - 若models/__init__.py遗漏导出，可能导致autogenerate无法识别新模型。
  - 在线迁移依赖异步引擎，需确保网络与连接池配置正确。

```mermaid
graph TB
Env["env.py"] --> Cfg["app/config.py"]
Env --> DB["app/database.py"]
DB --> Meta["Base.metadata"]
Meta --> Models["models/*"]
```

**图表来源**
- [backend/alembic/env.py:10-25](file://backend/alembic/env.py#L10-L25)
- [backend/app/config.py](file://backend/app/config.py#L7)
- [backend/app/database.py](file://backend/app/database.py#L20)
- [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14)

**章节来源**
- [backend/alembic/env.py:1-89](file://backend/alembic/env.py#L1-L89)
- [backend/app/config.py:1-17](file://backend/app/config.py#L1-L17)
- [backend/app/database.py:1-29](file://backend/app/database.py#L1-L29)
- [backend/app/models/__init__.py:1-14](file://backend/app/models/__init__.py#L1-L14)

## 性能考虑
- 索引设计
  - 初始迁移已为高频查询字段建立索引，有助于提升查询性能。
  - 对于大表，建议在维护窗口内重建索引，避免阻塞。
- 迁移窗口
  - 将DDL密集型操作安排在低峰时段，减少对线上服务的影响。
- 幂等性
  - 迁移脚本应具备幂等特性，避免重复执行造成资源浪费。

**章节来源**
- [backend/alembic/versions/488d0bd5ab01_initial_migration.py:57-94](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L57-L94)

## 故障排查指南
- 常见问题
  - 迁移失败：检查DATABASE_URL是否正确，确认数据库可达。
  - 模型未识别：确保models/__init__.py导出了新增模型。
  - 在线/离线模式混淆：确认运行环境与配置文件一致。
- 排查步骤
  - 查看日志：调整alembic.ini中的日志级别以获取更详细输出。
  - 回滚验证：使用downgrade验证回滚路径是否完整。
  - 数据核对：迁移完成后执行简单查询，核对关键索引与约束是否生效。

**章节来源**
- [backend/alembic.ini:115-150](file://backend/alembic.ini#L115-L150)
- [backend/alembic/env.py:33-89](file://backend/alembic/env.py#L33-L89)
- [backend/alembic/versions/488d0bd5ab01_initial_migration.py:114-128](file://backend/alembic/versions/488d0bd5ab01_initial_migration.py#L114-L128)

## 结论
GEO项目已建立完善的Alembic迁移体系：清晰的配置、可靠的元数据扫描、完备的初始迁移脚本与回滚路径。遵循本文的命令使用方法、最佳实践与风险控制措施，可在保障数据安全的前提下高效推进数据库演进。

## 附录
- 迁移命令速查
  - 升级到最新：alembic upgrade head
  - 降级到上一版本：alembic downgrade -1
  - 降级到指定版本：alembic downgrade <版本号>
  - 自动生成迁移：alembic revision --autogenerate -m "<描述>"
- 关键文件定位
  - 配置：backend/alembic.ini
  - 环境：backend/alembic/env.py
  - 模板：backend/alembic/script.py.mako
  - 初始迁移：backend/alembic/versions/488d0bd5ab01_initial_migration.py
  - 模型聚合：backend/app/models/__init__.py
  - 数据库配置：backend/app/config.py