文章 "MQL5 中的 SQLite 功能示例:按交易品种及 Magic 编码展示交易统计信息的仪表盘" - 页 2

 
SQLite: нативная работа с базами данных на SQL в MQL5
SQLite: нативная работа с базами данных на SQL в MQL5
  • 2020.02.18
  • www.mql5.com
Разработка торговых стратегий связана с обработкой больших объемов данных. Теперь прямо в MQL5 вы можете работать с базами данных с помощью SQL-запросов на основе SQLite. Важным преимуществом данного движка является то, что вся база данных содержится в единственном файле, который находится на компьютере пользователя.
 
没深入探究本质就草率下结论了。抱歉——说SQLite是“学生玩的玩具”确实言过其实,它不该被这么评价。

我深入研究了一番(借助AI,Opus 5——搭建了测试平台,生成了50万笔交易的数据,包含20个交易品种和20个交易策略,并进行了性能测试)。总结如下。

1) fxsaber 耗时五分钟的情况,几乎可以肯定不是 SQLite 造成的。

自动提交模式下,每笔交易INSERT操作:50万笔耗时约245秒。
同样的数据以批量方式在单个事务内处理:2.35秒。

差距达104倍。245秒——这正是所谓的“五分钟”。 每次插入操作 = 一次带有 fsync 的独立事务。只需两行代码即可解决:DatabaseTransactionBegin() / DatabaseTransactionCommit()。与这个数字相比,这场争论中的其他内容都微不足道。

2) 马克西姆关于索引的说法是对的,但指的不是那些索引。

文章中的查询,无索引的模式:395 毫秒。
同一查询 + 普通索引(MAGIC、ENTRY):427毫秒。也就是说完全没有帮助。
同样的查询加上覆盖索引(MAGIC、ENTRY、PROFIT、SWAP、COMMISSION):80毫秒。

对于完整的 GROUP BY 操作,普通索引毫无用处——表还是会被全表读取,SCAN ... USING INDEX 执行计划实质上也是全表扫描。 必须让查询中的所有列都包含在索引中,这样执行计划才会变成 SEARCH ... USING COVERING INDEX,从而无需读取表中的行。这样性能才能提升 5 倍。

而索引真正发挥作用的地方,在于每次重绘时控制面板都会执行的按单个符号进行的查询:20个 WHERE SYMBOL=? 查询 AND ENTRY=1 的查询——无索引时耗时 711 毫秒,而使用索引时仅需 208 毫秒。

3) 关于结构体数组。本质上我是对的,但如果编写自己的封装类,并包含所需的索引和方法,SQLite 当然会缩短开发时间,但会以牺牲性能和资源消耗为代价。

读取整个 45.8 MB 二进制文件:25 毫秒。
单次遍历,同时按魔数和字符聚合:7 毫秒。
作为对比——将相同的50万行数据从SQLite导出到结构数组(使用DatabaseReadBind 循环):220毫秒。

实际性能提升显著——根据操作不同,可达4至18倍。220毫秒与25毫秒的对比数据颇具说服力:如果统计数据仍需在MQL5中处理,那么在此场景下,数据库的表现简直就像是一种低效的文件格式。

但磁盘数据库占用84 MB,而二进制文件仅占46 MB——这多出的38 MB,能让你免费获得任意筛选、排序、分页以及任何新的报表功能。 而在结构化数组中,这些功能并不存在,除非您手动编写代码。因此,“不需要任何数据库”这一说法仅在您尚未遇到未预先设想的查询需求之前才是正确的。 Enrique在这点上说得对:如果需要查询数据,而不仅仅是加载数据,那么SQL是无可匹敌的。

4) 关于 PostgreSQL,我收回之前的话。

它是客户端-服务器架构,无法嵌入:需要单独的进程、安装、端口和管理权限。 对于沙盒中的单用户终端,这种架构并不适用。而对于本地分析,SQLite往往更快——没有IPC和往返通信。 关于JSONB的论点也站不住脚:SQLite从3.45版本起就支持JSONB,而交易记录根本不需要JSON,那里使用的是严格类型化的字段。

总结

对这篇文章的主要质疑在于数据模型和代码,而非数据库引擎本身。“文章中提到的SQLite”与“正确实现的SQLite”之间存在百倍之差;而正确实现的SQLite与结构体数组之间的差距则仅为数倍。

而该讨论串中最中肯的建议来自用户92746290:不要重新加载整个交易历史,而是从最后一条已记录的交易开始加载。无论您使用的是二进制文件还是数据库,这种方法都能解决问题。

如果感兴趣,我可以分享包含覆盖索引、批量插入和增量 Sync() 的方案,以及基于结构体数组的版本。

再次强调:我本人当然使用的是带索引和所需方法的轻量级类,完全不依赖任何数据库,这种方式在资源消耗和性能方面具有明显的优势。
 
Nikolai Semko #:
没深入探究本质就草率下结论了。请原谅我——说SQLite是“学生玩意儿”确实言过其实,它不该被这么评价。

虽然可能不适合学生,但终究只是个“玩具”。毕竟在使用SQLite 之前 ,必须将整个历史数据“翻个遍”,并逐条导入到表中。 这将耗费大量时间。如果非要将其与MQL5结合起来,那么读取订单和交易历史数据也必须直接从表中读取……仅代表个人观点

 
Nikolai Semko #:
深入研究了一番(借助AI,Opus 5——搭建了测试环境,生成了50万笔交易的模拟数据,包含20个交易代码和20个交易策略,并进行了性能测试)。

从抽象层面来说:与 MonetDB/e 进行比较应该会很有意思。它和 SQLite 一样是嵌入式的无服务器数据库,但出于多种原因,在处理复杂查询时应该会快得多。当然,前提是数据模型设计合理 :-)

 
Maxim Kuznetsov #:

从理论上讲:如果能与MonetDB/e进行比较就很有意思了。它和SQLite一样是嵌入式的无服务器数据库,但出于多种原因,在处理复杂查询时应该快得多。当然,前提是数据结构设计合理 :-)

也许吧
我也想过这个问题
对于数组,NoSQL 更胜一筹
得试一试。现在借助人工智能可以快速验证这一点