4.4 KiB
4.4 KiB
数据库设计文档 (DATABASE.md)
本项目采用 PostgreSQL (PostGIS) 作为主数据库,Redis 作为多级缓存层。
1. PostgreSQL 数据库设计
1.1 扩展 (Extensions)
必须启用 PostGIS 扩展以支持地理空间数据存储与查询。
CREATE EXTENSION IF NOT EXISTS postgis;
1.2 表结构 (Tables)
1.2.1 peaks (山峰表)
存储 14 座 8000 米级山峰的核心元数据。
CREATE TABLE peaks (
id SERIAL PRIMARY KEY,
name_en VARCHAR(100) NOT NULL UNIQUE, -- 英文名 (e.g., "Everest")
name_cn VARCHAR(100), -- 中文名
elevation_m INTEGER NOT NULL, -- 海拔 (米)
prominence_m INTEGER, -- 地形突起度
location GEOMETRY(POINT, 4326), -- 经纬度坐标 (WGS84)
first_ascent_year INTEGER, -- 首登年份
description TEXT, -- 简介
thumbnail_url VARCHAR(255), -- 缩略图 URL
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- 索引
CREATE INDEX idx_peaks_location ON peaks USING GIST (location);
1.2.2 routes (攀登路线表)
存储山峰的攀登路线,支持一条山峰多条路线。路线的几何数据量较大,通过 GeoJSON 或 PostGIS LineString 存储。
CREATE TABLE routes (
id SERIAL PRIMARY KEY,
peak_id INTEGER REFERENCES peaks(id) ON DELETE CASCADE,
name VARCHAR(100) NOT NULL, -- 路线名称 (e.g., "South Col Route")
difficulty VARCHAR(50), -- 难度等级
path_geometry GEOMETRY(LINESTRINGZ, 4326), -- 3D 路径 (包含海拔 Z)
description TEXT,
is_standard_route BOOLEAN DEFAULT FALSE, -- 是否为常规路线
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- 索引
CREATE INDEX idx_routes_peak_id ON routes(peak_id);
CREATE INDEX idx_routes_geometry ON routes USING GIST (path_geometry);
1.2.3 camps (营地表)
存储攀登路线上的关键营地位置 (Base Camp, C1, C2, etc.)。
CREATE TABLE camps (
id SERIAL PRIMARY KEY,
route_id INTEGER REFERENCES routes(id) ON DELETE CASCADE,
name VARCHAR(50) NOT NULL, -- 营地名 (e.g., "Camp 4")
elevation_m INTEGER, -- 营地海拔
location GEOMETRY(POINT, 4326), -- 营地坐标
camp_type VARCHAR(20) CHECK (camp_type IN ('BaseCamp', 'AdvancedBaseCamp', 'Camp', 'Summit')),
description TEXT
);
-- 索引
CREATE INDEX idx_camps_route_id ON camps(route_id);
2. Redis 缓存策略 (Cache Strategy)
采用多层缓存结构以提升 API 响应速度和减轻数据库 GIS 计算压力。
2.1 键命名规范 (Key Naming Convention)
{prefix}:{resource}:{identifier}:{field}
2.2 缓存层级与 TTL
| 数据类型 | Redis Key 模式 | 数据结构 | TTL (过期时间) | 说明 |
|---|---|---|---|---|
| API 响应 | api:peaks:list |
String (JSON) | 24 Hours | 所有山峰列表的轻量级 JSON |
| 山峰详情 | data:peak:{id} |
Hash | 7 Days | 单个山峰的详细信息 |
| 路线 GeoJSON | data:route:{id}:geojson |
String (GeoJSON) | 30 Days | 路线的完整几何数据 (体积大,极少变动) |
| 高程查询 | cache:elev:{lat}_{lon} |
String | 30 Days | 特定坐标的高程缓存 (避免重复栅格计算) |
| 用户会话 | session:{token} |
String | 2 Hours | 用户登录状态 (如有) |
2.3 缓存更新逻辑
- Read-Through: 读取数据时,先查 Redis。命中则返回;未命中则查 PostgreSQL,写入 Redis 并返回。
- Write-Invalidate: 更新数据库 (如修正路线数据) 时,立即删除对应的 Redis Key (e.g.,
DEL data:route:123:geojson),下次读取时自动重建。
3. 示例查询 (Example Queries)
3.1 查找珠峰附近 50km 内的所有其他 8000 米山峰
SELECT name_en, elevation_m,
ST_Distance(location::geography, (SELECT location::geography FROM peaks WHERE name_en = 'Everest')) as dist_meters
FROM peaks
WHERE id != (SELECT id FROM peaks WHERE name_en = 'Everest')
AND ST_DWithin(location::geography, (SELECT location::geography FROM peaks WHERE name_en = 'Everest'), 50000);
3.2 获取某条路线的 3D 长度
SELECT name, ST_3DLength(path_geometry::geography) as length_meters
FROM routes
WHERE id = 1;