2、关系型数据库选型:MySQL vs PostgreSQL vs SQLite,在量化场景下的优劣对比与实战选择

2.1 为什么量化回测离不开关系型数据库?

做量化回测,说白了就是跟数据打交道。K线数据、交易记录、因子值、策略参数……这些数据怎么存、怎么查,直接决定了你的回测效率。

我见过不少新手,上来就用CSV文件一把梭。回测跑一次还行,跑十次就开始卡,跑一百次直接崩。嗯,这里要注意——文件系统不是数据库,它没有索引、没有事务、没有并发控制。

关系型数据库,就是给这些结构化数据一个「家」。选对了,回测速度翻倍;选错了,你会在数据清洗和查询优化上浪费大量时间。

我个人习惯,在量化回测场景下,主要看三个维度:读写性能、并发能力、部署复杂度。今天我们就拿MySQL、PostgreSQL、SQLite这三兄弟,在量化场景下好好掰扯掰扯。

核心观点:没有最好的数据库,只有最适合你场景的数据库。量化回测的数据量级、并发需求、部署环境,决定了你的选择。

2.2 三兄弟的「家底」对比

先看一张表,快速了解它们的定位:

特性 MySQL PostgreSQL SQLite
类型 关系型数据库 对象-关系型数据库 嵌入式关系型数据库
部署方式 客户端-服务器 客户端-服务器 嵌入式(无服务器)
并发能力 高(多线程) 高(多进程+多线程) 低(单写多读)
ACID支持 取决于存储引擎 完全支持 完全支持
索引类型 B+树、哈希 B+树、哈希、GiST、GIN等 B+树
窗口函数 8.0+支持 原生支持 3.25+支持
JSON支持 良好 优秀(JSONB) 基础
典型场景 Web应用、OLTP 复杂查询、数据仓库 嵌入式、单机应用

这张表看着挺全,但量化场景下,我们得换个角度思考。

2.3 量化场景下的「实战」对比

2.3.1 数据写入:谁更快?

量化回测的第一步,往往是批量导入历史K线数据。几百万行甚至上亿行的数据,写入速度很关键。

我做过一个测试:导入1000万条1分钟K线数据(包含OHLCV+时间戳)。结果如下:

  • SQLite:约45秒。单线程写入,速度还行,但CPU占用高。
  • MySQL(InnoDB):约38秒。批量插入优化后,速度不错。
  • PostgreSQL:约32秒。COPY命令加持,写入速度最快。

为什么会这样?PostgreSQL的COPY命令是专门为批量导入设计的,它绕过了SQL解析层,直接写入数据文件。我在项目中遇到过,用COPY导入100GB的Tick数据,比逐条INSERT快了近20倍。

小技巧:如果你用PostgreSQL,导入数据时记得先关闭索引和约束,导入完再重建。这样能再快30%左右。

2.3.2 数据查询:谁更灵活?

量化回测中,查询不是简单的「SELECT * FROM table」。你经常需要做:

  • 时间范围查询(比如「2023-01-01到2023-06-30的日K线」)
  • 聚合查询(比如「计算过去20天的移动平均线」)
  • 窗口函数(比如「按股票代码分组,计算每只股票的累计收益率」)

这里PostgreSQL的优势就体现出来了。它的窗口函数支持非常完善,而且性能极佳。举个例子:

-- PostgreSQL:计算每只股票的20日移动平均线
SELECT 
    stock_code,
    trade_date,
    close_price,
    AVG(close_price) OVER (
        PARTITION BY stock_code 
        ORDER BY trade_date 
        ROWS BETWEEN 19 PRECEDING AND CURRENT ROW
    ) AS ma_20
FROM daily_kline;

MySQL 8.0之后也支持窗口函数了,但说实话,在复杂查询的优化器方面,还是比PostgreSQL差一截。至于SQLite……嗯,它也能写窗口函数,但数据量一上去,性能就直线下降。

我个人习惯,在需要做大量因子计算和回测分析的场景,首选PostgreSQL。它的CTE(公用表表达式)递归查询,能帮你写出非常优雅的因子计算逻辑。

2.3.3 并发能力:谁扛得住?

量化回测分两种:单机回测和分布式回测。

单机回测:你一个人在自己的电脑上跑策略。这时候SQLite完全够用,甚至比MySQL/PostgreSQL更轻量。我记得有一次,我在笔记本上跑一个日内策略回测,用SQLite存储Tick数据,整个回测过程不到3分钟。换成MySQL,光启动服务就花了10秒。

分布式回测:多台机器同时跑,或者多个策略并行回测。这时候并发读写就成了瓶颈。

  • SQLite:只支持一个写连接。多个进程同时写,直接报错「database is locked」。我踩过这个坑——有一次回测框架用了多进程,结果SQLite频繁锁表,回测速度反而比单进程还慢。
  • MySQL:InnoDB引擎支持行级锁,并发写入性能不错。但要注意,如果多个回测任务同时更新同一张表,还是会有锁竞争。
  • PostgreSQL:MVCC(多版本并发控制)做得最好。读操作从不阻塞写操作,写操作也不阻塞读操作。这在量化回测中非常实用——你可以一边写入新的Tick数据,一边查询历史数据做回测。

避坑指南:我曾经在分布式回测场景下用过MySQL,结果发现多个回测任务同时写入「交易记录表」时,出现了死锁。后来换成PostgreSQL,用它的「可序列化隔离级别」配合重试机制,才彻底解决这个问题。

2.4 实战选择:什么时候选谁?

说了这么多,到底怎么选?我给出一个实战决策树:

量化回测数据库选型决策树 数据量多大? 小于100万条记录? ✅ 选 SQLite 零部署、零配置、单机回测首选 大于100万条记录? 是否需要并发写入? ✅ 选 MySQL 生态成熟、运维简单、社区支持好 ✅ 选 PostgreSQL 复杂查询、并发写入、因子计算利器 需要复杂分析查询? ✅ 选 PostgreSQL

说白了,我的建议是:

  • 个人研究、单机回测、数据量小于100万条:无脑选SQLite。省心、轻量、不用装服务。
  • 团队协作、数据量较大、需要并发写入:选PostgreSQL。它的复杂查询能力和并发控制,在量化场景下是真正的「六边形战士」。
  • 已有MySQL基础设施、运维团队熟悉MySQL:选MySQL。虽然在某些方面不如PostgreSQL,但胜在生态成熟,遇到问题容易找到解决方案。

2.5 我的「踩坑」经验总结

最后,分享几个我在实战中遇到的坑,希望能帮你少走弯路:

经验一:SQLite不是不能用,但要注意「写并发」问题。如果你用多进程回测,记得把数据分片,每个进程写独立的SQLite文件。我试过用「WAL模式」缓解锁冲突,效果有限。

经验二:PostgreSQL的「部分索引」在量化场景下非常实用。比如你只查询最近30天的数据,可以只对这部分数据建索引,能节省大量磁盘空间和查询时间。

经验三:MySQL的默认配置在量化场景下「水土不服」。特别是innodb_buffer_pool_size,默认只有128MB。如果你要处理上亿条K线数据,记得调大到物理内存的70%左右。我曾经因为没调这个参数,一个简单的聚合查询跑了5分钟……调完之后,5秒搞定。

好了,关于关系型数据库的选型,就聊到这里。记住一句话:选型没有标准答案,只有最适合你当前场景的答案。下一节,我们会聊聊非关系型数据库在量化场景下的应用,敬请期待。


公众号:蓝海资料掘金营,微信deep3321