4、日志数据存储:关系型数据库、时序数据库与云存储方案

日志数据存哪里?怎么存?这个问题我当年刚入行时也纠结过。

说实话,没有银弹。不同的场景,适合不同的存储方案。我个人习惯把日志数据分成三类:结构化交易记录、高频时序指标、以及冷备归档文件。这三类数据,分别对应三种存储方案。

4.1 关系型数据库:MySQL / PostgreSQL

交易日志里,那些需要频繁查询、关联、统计的数据,我建议放关系型数据库。比如订单记录、成交明细、账户流水。

为什么选关系型? 因为你要做绩效评估时,经常要算「某策略在某个时间段内的总收益」、「最大回撤发生在哪一天」。这些查询涉及多表关联、聚合计算,关系型数据库最擅长。

核心设计原则:

  • 按时间分区:交易日志天然带时间戳,按日期或月份分区,查询效率翻倍
  • 索引别贪多:只对查询频繁的字段建索引,比如 strategy_id、trade_time
  • 字段类型要抠:金额用 DECIMAL(18,8),别用 FLOAT,否则精度丢失你会哭

我分享一个实际用过的表结构,MySQL 和 PostgreSQL 通用:

CREATE TABLE trade_logs (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    strategy_id VARCHAR(32) NOT NULL,
    symbol VARCHAR(16) NOT NULL,
    trade_time DATETIME NOT NULL,
    side ENUM('BUY', 'SELL') NOT NULL,
    price DECIMAL(18, 8) NOT NULL,
    volume DECIMAL(18, 8) NOT NULL,
    cost DECIMAL(18, 8) NOT NULL,
    pnl DECIMAL(18, 8) DEFAULT 0,
    status TINYINT DEFAULT 0,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_strategy_time (strategy_id, trade_time),
    INDEX idx_trade_time (trade_time)
) PARTITION BY RANGE (YEAR(trade_time)) (
    PARTITION p2023 VALUES LESS THAN (2024),
    PARTITION p2024 VALUES LESS THAN (2025),
    PARTITION p_future VALUES LESS THAN MAXVALUE
);

我的经验: PostgreSQL 的 JSONB 字段很适合存策略参数或附加信息。我曾经用 MySQL 的 TEXT 字段存 JSON,查询时解析慢得离谱。后来换成 PG,直接用 JSONB 做条件过滤,性能提升了一个数量级。

4.2 时序数据库:InfluxDB

量化交易里,高频数据才是大头。每秒几十上百条的 tick 数据、逐笔成交、盘口快照……这些数据用关系型数据库存,你想想看,一张表几亿行,查询一次要等半天。

时序数据库就是为这种场景设计的。 InfluxDB 是我用得最多的,原因很简单:写入快、查询快、存储压缩率高。

我举个例子。记录策略的实时净值曲线:

-- 写入数据(InfluxDB Line Protocol)
net_value,strategy_id=ma_strategy,symbol=BTCUSDT value=1.0234,equity=102340.00 1704067200000000000

-- 查询最近1小时每5分钟的均值
SELECT MEAN(value) 
FROM net_value 
WHERE strategy_id='ma_strategy' 
  AND time > now() - 1h 
GROUP BY time(5m)

InfluxDB 设计要点:

  • Tag vs Field:Tag 是索引字段(如 strategy_id),Field 是数值字段(如 value)。Tag 不要太多,否则内存扛不住
  • 保留策略(Retention Policy):高频数据保留7天,降采样后的数据保留1年。我习惯用 Continuous Query 自动做降采样
  • 时间精度:纳秒级精度够用,但存储成本高。如果只是秒级或毫秒级数据,指定精度能省不少空间

避坑指南: 我曾经把策略 ID 设成 Field,结果查询时无法按策略过滤,全表扫描,写入也变慢。后来改成 Tag,查询效率直接起飞。记住:需要过滤的字段,一律放 Tag

4.3 云存储方案:AWS S3

日志数据不能只存热数据。那些几个月前的原始日志、回测结果、报告文件,放数据库里既贵又慢。这时候就该 S3 出场了。

S3 适合存什么?

  • 原始 tick 数据(CSV/Parquet 格式)
  • 每日绩效报告(PDF/HTML)
  • 模型参数快照
  • 数据库备份文件

我常用的目录结构是这样的:

s3://quant-logs/
├── raw_tick/
│   ├── year=2024/
│   │   ├── month=01/
│   │   │   ├── day=15/
│   │   │   │   ├── BTCUSDT.parquet
│   │   │   │   └── ETHUSDT.parquet
│   │   │   └── ...
│   │   └── ...
│   └── ...
├── reports/
│   ├── 2024-01-15_daily_report.pdf
│   └── ...
└── backups/
    └── trade_db_2024-01-15.sql.gz

用 S3 的好处是便宜、无限扩展。配合 Athena 或 Redshift Spectrum,可以直接在 S3 上跑 SQL 查询,不用把数据导进来。

我的建议: 数据格式尽量用 Parquet,别用 CSV。Parquet 是列式存储,压缩率高,查询时只读需要的列。同样一份数据,Parquet 比 CSV 省 70% 的存储空间,查询速度还快 5 倍以上。

4.4 三种方案如何选?一张图看懂

说了这么多,到底怎么选?我画了张图,把决策逻辑梳理清楚了:

日志数据存储方案决策流程 原始日志数据 需要频繁查询? 高频时序数据? (tick/净值/指标) InfluxDB 时序数据库 MySQL / PostgreSQL 关系型数据库 AWS S3 云存储(冷备/归档) 实际项目中,三种方案往往组合使用:热数据放 InfluxDB/MySQL,冷数据定期归档到 S3 查询时通过 Presto/Athena 跨数据源联合查询

4.5 实际项目中的组合方案

说了这么多理论,聊聊我实际怎么用的。

我之前维护过一个高频交易系统,每天产生大约 500GB 的原始 tick 数据。我的方案是这样的:

数据类型 存储方案 保留周期 查询场景
实时净值、风险指标 InfluxDB 30天(原始),1年(降采样) 实时监控、日内分析
订单、成交、账户流水 PostgreSQL 永久 绩效评估、对账、审计
原始 tick 数据 S3(Parquet 格式) 永久 回测、策略研究
每日报告、备份 S3 1年 归档、合规

避坑指南: 我曾经把所有数据都塞进 MySQL,结果半年后一张表 20 亿行,查询一条记录要 30 秒。后来把 tick 数据迁移到 InfluxDB,把历史归档扔到 S3,MySQL 只保留结构化交易记录,查询瞬间变快。记住:不要用一把钥匙开所有的锁

嗯,日志存储这块,核心就这些。选对方案,你的量化系统才能跑得稳、查得快、存得省。

专注资料整理