# 国际指数数据表设计文档
## 📊 表结构
### 表名:`global_index_data`
基于 Tushare `index_global` 接口的数据格式设计,直接映射接口返回的所有字段。
| 字段名 | 类型 | 说明 | 是否可空 |
|--------|------|------|---------|
| `ts_code` | TEXT | TS指数代码(如:XIN9、HSI、DJI等) | NOT NULL |
| `trade_date` | TEXT | 交易日期(YYYYMMDD格式,如:20241201) | NOT NULL |
| `open` | REAL | 开盘点位 | NULL |
| `close` | REAL | 收盘点位 | NULL |
| `high` | REAL | 最高点位 | NULL |
| `low` | REAL | 最低点位 | NULL |
| `pre_close` | REAL | 昨日收盘点 | NULL |
| `change` | REAL | 涨跌点位 | NULL |
| `pct_chg` | REAL | 涨跌幅(百分比) | NULL |
| `swing` | REAL | 振幅(百分比) | NULL |
| `vol` | REAL | 成交量(大部分指数无此项数据) | NULL |
| `amount` | REAL | 成交额(大部分指数无此项数据) | NULL |
| `created_at` | REAL | 数据创建时间戳 | NOT NULL |
### 主键
- **复合主键**:`(ts_code, trade_date)`
- 确保同一指数的同一天只有一条数据
- 使用 `INSERT OR REPLACE` 实现数据去重和更新
### 索引
为了提升查询性能,创建了以下索引:
1. **idx_ts_code**:`ts_code` 单列索引
- 用于按指数代码查询
2. **idx_trade_date**:`trade_date` 单列索引
- 用于按日期查询
3. **idx_ts_code_date**:`(ts_code, trade_date)` 复合索引
- 用于按指数代码和日期组合查询(覆盖主键查询)
4. **idx_created_at**:`created_at` 单列索引
- 用于按创建时间查询和统计
## 🔄 缓存策略
### 永不失效策略
1. **数据永久保存**
- 所有指数数据永久保存在数据库中
- 不设置过期时间
- 不进行自动清理
2. **数据去重机制**
- 使用 `INSERT OR REPLACE` 确保数据唯一性
- 如果同一指数的同一天数据已存在,则更新为新数据
- 保留 `created_at` 时间戳记录数据创建时间
3. **查询逻辑**
- 优先从数据库查询
- 如果数据库中没有数据,才从 Tushare API 获取
- 获取后立即保存到数据库,供后续查询使用
4. **数据更新**
- 如果 API 返回的数据与数据库中的数据相同(同一指数、同一日期),则自动更新
- 不会创建重复记录
## 📝 使用示例
### Python 代码示例
```python
from cache.index_cache_manager import index_cache_manager
# 保存指数数据
df = pro.index_global(ts_code='XIN9', start_date='20240101', end_date='20241231')
saved_count = index_cache_manager.save_index_data(df)
print(f"保存了 {saved_count} 条记录")
# 查询特定日期的数据
df = index_cache_manager.get_index_data(
ts_code='XIN9',
trade_date='20241201'
)
# 查询日期范围的数据
df = index_cache_manager.get_index_data(
ts_code='XIN9',
start_date='20240101',
end_date='20241231'
)
# 查询最近10条数据
df = index_cache_manager.get_index_data(
ts_code='XIN9',
limit=10,
order_by='DESC'
)
# 检查数据是否存在
has_data = index_cache_manager.has_data('XIN9', '20241201')
# 获取数据日期范围
date_range = index_cache_manager.get_date_range('XIN9')
# 返回: {'start_date': '20240101', 'end_date': '20241231'}
# 获取统计信息
stats = index_cache_manager.get_stats()
```
## 🔍 SQL 查询示例
### 查询特定指数的所有数据
```sql
SELECT * FROM global_index_data
WHERE ts_code = 'XIN9'
ORDER BY trade_date DESC;
```
### 查询特定日期的所有指数数据
```sql
SELECT * FROM global_index_data
WHERE trade_date = '20241201'
ORDER BY ts_code;
```
### 查询日期范围内的数据
```sql
SELECT * FROM global_index_data
WHERE ts_code = 'XIN9'
AND trade_date >= '20240101'
AND trade_date <= '20241231'
ORDER BY trade_date DESC;
```
### 统计每个指数的数据量
```sql
SELECT
ts_code,
COUNT(*) as record_count,
MIN(trade_date) as earliest_date,
MAX(trade_date) as latest_date
FROM global_index_data
GROUP BY ts_code
ORDER BY ts_code;
```
## 🎯 优势
1. **性能优化**
- 直接存储字段,无需 JSON 序列化/反序列化
- 索引优化查询性能
- 支持高效的日期范围查询
2. **数据完整性**
- 主键约束确保数据唯一性
- 数据永久保存,不会丢失
- 支持历史数据查询
3. **灵活性**
- 支持按指数代码、日期、日期范围查询
- 支持排序和限制返回数量
- 支持统计和数据分析
4. **维护简单**
- 表结构清晰,字段直接映射 API 返回数据
- 无需复杂的缓存过期管理
- 数据自动去重和更新
## 📊 数据量估算
假设:
- 支持 22 个国际指数
- 每个指数每年约 250 个交易日
- 每条记录约 200 字节
**年数据量**:22 × 250 × 200 字节 ≈ 1.1 MB/年
**10年数据量**:约 11 MB
数据量很小,完全可以使用 SQLite 存储,无需担心性能问题。