summit/DATABASE.md

4.4 KiB
Raw Permalink Blame History

数据库设计文档 (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 缓存更新逻辑

  1. Read-Through: 读取数据时,先查 Redis。命中则返回未命中则查 PostgreSQL写入 Redis 并返回。
  2. 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;